zhejiushizhuce 2 роки тому
батько
коміт
e8ebdbea95

+ 6 - 0
src/Global.js

@@ -100,4 +100,10 @@ global.showFirstPay=()=>{
 global.hideFirstPay=()=>{
     if (global.firstPay)global.firstPay.hide();
 }
+global.showAreaSelect=()=>{
+    if (global.areaSelect)global.areaSelect.show();
+}
+global.hideAreaSelect=()=>{
+    if (global.areaSelect)global.areaSelect.hide();
+}
 //wd pass

BIN
src/assets/area/BRL.rect.png


BIN
src/assets/area/EUR.rect.png


BIN
src/assets/area/MXN.rect.png


BIN
src/assets/area/RUB.rect.png


+ 4 - 0
src/assets/singlesvg/area_map.svg

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11 16C11 16.5523 11.4477 17 12 17C12.5523 17 13 16.5523 13 16H11ZM8.21567 14.3922C8.75496 14.2731 9.09558 13.7394 8.97647 13.2001C8.85735 12.6608 8.32362 12.3202 7.78433 12.4393L8.21567 14.3922ZM16.2157 12.4393C15.6764 12.3202 15.1426 12.6608 15.0235 13.2001C14.9044 13.7394 15.245 14.2731 15.7843 14.3922L16.2157 12.4393ZM15 7C15 8.65685 13.6569 10 12 10V12C14.7614 12 17 9.76142 17 7H15ZM12 10C10.3431 10 9 8.65685 9 7H7C7 9.76142 9.23858 12 12 12V10ZM9 7C9 5.34315 10.3431 4 12 4V2C9.23858 2 7 4.23858 7 7H9ZM12 4C13.6569 4 15 5.34315 15 7H17C17 4.23858 14.7614 2 12 2V4ZM11 11V16H13V11H11ZM20 17C20 17.2269 19.9007 17.5183 19.5683 17.8676C19.2311 18.222 18.6958 18.5866 17.9578 18.9146C16.4844 19.5694 14.3789 20 12 20V22C14.5917 22 16.9861 21.5351 18.7701 20.7422C19.6608 20.3463 20.4435 19.8491 21.0171 19.2463C21.5956 18.6385 22 17.8777 22 17H20ZM12 20C9.62114 20 7.51558 19.5694 6.04218 18.9146C5.30422 18.5866 4.76892 18.222 4.43166 17.8676C4.0993 17.5183 4 17.2269 4 17H2C2 17.8777 2.40438 18.6385 2.98287 19.2463C3.55645 19.8491 4.33918 20.3463 5.2299 20.7422C7.01386 21.5351 9.40829 22 12 22V20ZM4 17C4 16.6824 4.20805 16.2134 4.96356 15.6826C5.70129 15.1644 6.81544 14.7015 8.21567 14.3922L7.78433 12.4393C6.22113 12.7846 4.83528 13.3285 3.81386 14.0461C2.81023 14.7512 2 15.747 2 17H4ZM15.7843 14.3922C17.1846 14.7015 18.2987 15.1644 19.0364 15.6826C19.792 16.2134 20 16.6824 20 17H22C22 15.747 21.1898 14.7512 20.1861 14.0461C19.1647 13.3285 17.7789 12.7846 16.2157 12.4393L15.7843 14.3922Z" fill="#000000"/>
+</svg>

+ 27 - 0
src/db/area.js

@@ -0,0 +1,27 @@
+import img1 from '@assets/area/BRL.rect.png';
+import img2 from '@assets/area/MXN.rect.png';
+import img3 from '@assets/area/RUB.rect.png';
+import img4 from '@assets/area/EUR.rect.png';
+const area=[
+    {
+        id:1,
+        name:"areaSelect.brazil",
+        icon:img1
+    },
+    {
+        id:2,
+        name:"areaSelect.mexico",
+        icon:img2
+    },
+    {
+        id:3,
+        name:"areaSelect.russia",
+        icon:img3
+    },
+    {
+        id:4,
+        name:"areaSelect.europe",
+        icon:img4
+    }
+]
+export default area;

+ 13 - 2
src/features/mainSlice.js

@@ -252,6 +252,8 @@ const reducerRoutes=(state,action)=>{
         let popBindPhone=0;
         let firstBonus=0;
         let openRelief=0;
+        let accountLogin=1;
+        let area=1;
         //sport 配置
         let bbConf=null;
         if (conf){
@@ -281,10 +283,11 @@ const reducerRoutes=(state,action)=>{
                 bbConf=conf.bb;
                 if(userInfo!=null)userInfo.bb=bbConf;
             }
+            if (!!conf.accountLogin)accountLogin=conf.accountLogin;
         }
         //favorites
         // let favorites=getFavorites(json.favorites);
-        Object.assign(state, {routes:state.routes,asyncRoutes:data,styles,blocks,...generData,isLogin:isLogin,userInfo,hallServerUrl,promoteInstall,guest,upgradeBonus,popWheel,popBindPhone,firstBonus,openRelief,bbConf});
+        Object.assign(state, {routes:state.routes,asyncRoutes:data,styles,blocks,...generData,isLogin:isLogin,userInfo,hallServerUrl,promoteInstall,guest,upgradeBonus,popWheel,popBindPhone,firstBonus,openRelief,bbConf,accountLogin,area});
         // Object.assign(state, {routes:state.routes,asyncRoutes:data,styles:styles,blocks:blocks,...generData,isLogin:isLogin,userInfo:userInfo,hallServerUrl:hallServerUrl,promoteInstall:promoteInstall,guest:guest,upgradeBonus:upgradeBonus});
     }
 }
@@ -609,7 +612,9 @@ export const Main=createSlice({
         //绑定奖励
         upgradeBonus:0,
         //sport conf
-        bbConf:null
+        bbConf:null,
+        accountLogin:0,
+        area:1
     },
     reducers: {
         logout:(state, action)=>{
@@ -914,6 +919,12 @@ export const getOpenRelief=(state)=>{
 export const getBBConf=(state)=>{
     return state.main.bbConf;
 }
+export const getAccountLogin=(state)=>{
+    return state.main.accountLogin;
+}
+export const getArea=(state)=>{
+    return state.main.area;
+}
 export const getUserBBToken=(state)=>{
     let token=null;
     let userInfo=state.main.userInfo;

+ 2 - 0
src/layout/Layout.jsx

@@ -37,6 +37,7 @@ import WWelfarebar from "@widgets/WWelfarebar";
 import WProtect from "@widgets/WProtect";
 import LoadingCircular from "@components/Loading/LoadingCircular";
 import WFirstPay from "@widgets/WFirstPay";
+import WAreaSelect from "@widgets/WAreaSelect";
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
 
 const Layout=({...props})=>{
@@ -133,6 +134,7 @@ const Layout=({...props})=>{
                 <WBindPrompt/>
                 <WProtect/>
                 <WFirstPay/>
+                <WAreaSelect/>
             </>
         )
     }

+ 19 - 4
src/locales/languages/en_US.json

@@ -114,13 +114,18 @@
     "notfound": "Your account was not found, please register or try again!",
     "login_type": {
       "password": "Password",
-      "otp": "SMS"
+      "otp": "SMS",
+      "account": "Account"
     },
     "otp_ph": "Verification Code",
     "guest_login": "Guest Login",
     "btn_otp": "Send Code",
     "forget_title": "Reset Password",
-    "back_to_login": "Back to"
+    "back_to_login": "Back to",
+    "account_ph": "User Account",
+    "reg_type": {
+      "phone": "Phone"
+    }
   },
   "logout": {
     "success": "You have exited successfully."
@@ -158,7 +163,8 @@
     "install_banner": "Show Installation Notice",
     "sound": "Sound",
     "bindPhone": "Account Upgrade",
-    "bonus": "Get Bonus +{0}"
+    "bonus": "Get Bonus +{0}",
+    "area_select": "Area Select"
   },
   "copy_success": "Copy successful",
   "user": {
@@ -412,7 +418,8 @@
   },
   "form_errors": {
     "phone_55": "Enter a correct 11-digit phone number.",
-    "pass": "The password must not be less than 6 characters."
+    "pass": "The password must not be less than 6 characters.",
+    "account": "The account number must not be less than 6 characters."
   },
   "turnplate": {
     "expires_in": "Expires in",
@@ -642,6 +649,14 @@
     "content": "Para fornecer um serviço melhor, faremos a manutenção do sistema das 3:00 às 7:00 em 27 de agosto. O site não estará acessível durante esse período. Por favor, seja paciente.",
     "confirm": "Confirm"
   },
+  "areaSelect": {
+    "brazil": "Brazil",
+    "mexico": "Mexico",
+    "russia": "Russia",
+    "europe": "Europe",
+    "title": "Area Select",
+    "btn_confirm": "Confirm"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "There is no RedPack",

+ 256 - 64
src/widgets/LoginForm/index.jsx

@@ -20,6 +20,7 @@ import {animated,useSpring} from "@react-spring/web";
 import {toast} from 'react-toastify';
 import {useDispatch, useSelector} from "react-redux";
 import {
+    getAccountLogin,
     getChangePassStatus,
     getLoginStatus,
     getRegStatus,
@@ -44,6 +45,10 @@ const TYPE_FORGET_PASS="forgetPassword";
 
 const LOGIN_TYPE_PASS=0;
 const LOGIN_TYPE_OTP=1;
+const LOGIN_TYPE_ACOUNT=2;
+
+const REG_TYPE_PHONE=0;
+const REG_TYPE_ACCOUNT=1;
 const objInfo={
     cdTimer:null,
     inSubmit:false
@@ -72,7 +77,10 @@ const LoginForm = ({close}) => {
             code:"",
             phone:"",
             newpassword:"",
-            renewpassword:""
+            renewpassword:"",
+            acc_account:"",
+            acc_password:"",
+            acc_repassword:""
         }
     });
     const {pathname,hash} = useLocation();
@@ -80,6 +88,8 @@ const LoginForm = ({close}) => {
     const [otpCD,setOtpCD]=useState(-1);
     const otpStatus=useSelector(getSendCodeStatus);
     const smsLoginStatus=useSelector(getSMSLoginStatus);
+    const isAccountLogin=useSelector(getAccountLogin);
+    const [regType,setRegType]=useState(REG_TYPE_PHONE);
     const onSendCode=(e)=>{
         if (otpCD>0)return;
         if (otpStatus===REQ_STATUS.LOADING)return;
@@ -181,6 +191,9 @@ const LoginForm = ({close}) => {
         data.callback=onCallback;
         dispatch(reqForgetPass(data));
         objInfo.inSubmit=true;
+    }
+    const onSubmitAccountLogin=(data)=>{
+
     }
     const validatePhone=(value)=>{
         return validateCountryPhone(country,value);
@@ -216,6 +229,7 @@ const LoginForm = ({close}) => {
         //     </button>
         // )
     }
+    //login__________
     const renderPassLogin = () => {
         return (
             <form key={"pass"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
@@ -336,6 +350,67 @@ const LoginForm = ({close}) => {
             </form>
         )
     }
+    const renderAccountLogin=()=>{
+        return (
+            <form key={"account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
+                onSubmitAccountLogin(data);
+            })}>
+                <Controller control={control}
+                            name="acc_account"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => {
+                                return (
+                                    <div className={`d-flex flex-column g-6`}>
+                                        <div
+                                            className={`input-control ${classNames({'input-control--error': error})}`}>
+                                            <input
+                                                type={'text'}
+                                                autoComplete="off"
+                                                ref={ref}
+                                                onChange={e => onChange(e.target.value)}
+                                                placeholder={i18n.t('login.account_ph')}
+                                            />
+                                        </div>
+                                        {
+                                            error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
+                                        }
+                                    </div>
+                                )
+                            }}
+                />
+                <Controller control={control}
+                            name="acc_password"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <PasswordInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={error ? i18n.t("form_errors.pass") : ''}
+                                    onChange={e => onChange(e.target.value)}
+                                    placeholder={i18n.t('login.login_pwd')}
+                                    innerRef={ref}/>
+                            )}
+                />
+                <button className={"button-green"}>
+                    {
+                        loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
+                    }
+                </button>
+                {renderGuestLogin()}
+                {renderLoginToReg()}
+            </form>
+        )
+    }
+    const renderLoginType = () => {
+        if (loginType === LOGIN_TYPE_PASS) {
+            return renderPassLogin();
+        } else if (loginType === LOGIN_TYPE_OTP){
+            return renderOTPLogin();
+        } else if (loginType === LOGIN_TYPE_ACOUNT){
+            return renderAccountLogin();
+        }
+        return (<></>);
+    }
     const renderLoginForm = () => {
         return (
             <Spring type="slideUp">
@@ -353,83 +428,200 @@ const LoginForm = ({close}) => {
                             }}>
                         <span>{i18n.t("login.login_type.otp")}</span>
                     </button>
+                    {
+                        isAccountLogin?(
+                            <button className={`${styles.l_type_btn} ${loginType === LOGIN_TYPE_ACOUNT ? styles.active : ''}`}
+                                    onClick={() => {
+                                        setLoginType(LOGIN_TYPE_ACOUNT)
+                                    }}>
+                                <span>{i18n.t("login.login_type.account")}</span>
+                            </button>
+                        ):(<></>)
+                    }
                 </div>
                 {
-                    loginType===LOGIN_TYPE_PASS?renderPassLogin():renderOTPLogin()
+                    // loginType===LOGIN_TYPE_PASS?renderPassLogin():renderOTPLogin()
+                    renderLoginType()
                 }
             </Spring>
         )
     }
+    //login__________
+
+    //register_______________
+    const renderRegToLogin=()=>{
+        return (
+            <div className={styles.l_reg_new}>
+                <div>{i18n.t("login.login_des")}</div>
+                <div className={styles.reg_btn} onClick={() => {
+                    // setShowType(TYPE_LOGIN);
+                    if (isMobile()) navigatRoute(ROUTE_PATH.SIGN_IN)
+                    else setShowType(TYPE_LOGIN);
+                }}>
+                    {i18n.t("login.sign_in_btn")}
+                </div>
+            </div>
+        )
+    }
+    const renderRegPhone = () => {
+        return (
+            <form key={"reg_phone"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
+                onSubmitReg(data);
+            })}>
+                <Controller control={control}
+                            name="account"
+                            rules={{required: true, validate: validatePhone}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => {
+                                let message = error ? i18n.t("form_errors.phone_" + country) : "";
+                                return (<PhoneInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={message}
+                                    onChange={e => onChange(e.target.value)}
+                                    onChangeCountry={(country) => {
+                                        setCountry(country);
+                                    }}
+                                    placeholder={i18n.t('login.phone_ph')}
+                                    innerRef={ref}/>)
+                            }}
+                />
+                <Controller control={control}
+                            name="password"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <PasswordInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={error ? i18n.t("form_errors.pass") : ''}
+                                    onChange={e => onChange(e.target.value)}
+                                    placeholder={i18n.t('login.login_pwd')}
+                                    innerRef={ref}/>
+                            )}
+                />
+                <Controller control={control}
+                            name="repassword"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <PasswordInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={error ? i18n.t("form_errors.pass") : ''}
+                                    onChange={e => onChange(e.target.value)}
+                                    placeholder={i18n.t('login.re_pwd')}
+                                    innerRef={ref}/>
+                            )}
+                />
+                <button className={"button-green"}>
+                    {
+                        regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
+                    }
+                </button>
+                {renderRegToLogin()}
+            </form>
+        )
+    }
+    const renderRegAccount=()=>{
+        return (
+            <form key={"reg_account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
+                // onSubmitReg(data);
+            })}>
+                <Controller control={control}
+                            name="acc_account"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => {
+                                return (
+                                    <div className={`d-flex flex-column g-6`}>
+                                        <div
+                                            className={`input-control ${classNames({'input-control--error': error})}`}>
+                                            <input
+                                                type={'text'}
+                                                autoComplete="off"
+                                                ref={ref}
+                                                onChange={e => onChange(e.target.value)}
+                                                placeholder={i18n.t('login.account_ph')}
+                                            />
+                                        </div>
+                                        {
+                                            error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
+                                        }
+                                    </div>
+                                )
+                            }}
+                />
+                <Controller control={control}
+                            name="acc_password"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <PasswordInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={error ? i18n.t("form_errors.pass") : ''}
+                                    onChange={e => onChange(e.target.value)}
+                                    placeholder={i18n.t('login.login_pwd')}
+                                    innerRef={ref}/>
+                            )}
+                />
+                <Controller control={control}
+                            name="acc_repassword"
+                            rules={{required: true, minLength: 6}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <PasswordInput
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    message={error ? i18n.t("form_errors.pass") : ''}
+                                    onChange={e => onChange(e.target.value)}
+                                    placeholder={i18n.t('login.re_pwd')}
+                                    innerRef={ref}/>
+                            )}
+                />
+                <button className={"button-green"}>
+                    {
+                        regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
+                    }
+                </button>
+                {renderRegToLogin()}
+            </form>
+        )
+    }
+    const renderRegType=()=>{
+        if (regType===REG_TYPE_PHONE){
+            return renderRegPhone();
+        }
+        else if (regType===REG_TYPE_ACCOUNT){
+            return renderRegAccount();
+        }
+        return (<></>);
+    }
     const renderRegisterForm = () => {
         return (
             <Spring type="slideUp">
                 <div className={styles.l_title}>{i18n.t("login.reg_title")}</div>
-                <form autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
-                    onSubmitReg(data);
-                })}>
-                    <Controller control={control}
-                                name="account"
-                                rules={{required: true, validate: validatePhone}}
-                                render={({field: {ref, onChange, value}, fieldState: {error}}) => {
-                                    let message = error ? i18n.t("form_errors.phone_" + country) : "";
-                                    return (<PhoneInput
-                                        className={classNames({'input-control--error': error})}
-                                        value={value}
-                                        message={message}
-                                        onChange={e => onChange(e.target.value)}
-                                        onChangeCountry={(country) => {
-                                            setCountry(country);
-                                        }}
-                                        placeholder={i18n.t('login.phone_ph')}
-                                        innerRef={ref}/>)
-                                }}
-                    />
-                    <Controller control={control}
-                                name="password"
-                                rules={{required: true, minLength: 6}}
-                                render={({field: {ref, onChange, value}, fieldState: {error}}) => (
-                                    <PasswordInput
-                                        className={classNames({'input-control--error': error})}
-                                        value={value}
-                                        message={error ? i18n.t("form_errors.pass") : ''}
-                                        onChange={e => onChange(e.target.value)}
-                                        placeholder={i18n.t('login.login_pwd')}
-                                        innerRef={ref}/>
-                                )}
-                    />
-                    <Controller control={control}
-                                name="repassword"
-                                rules={{required: true,minLength:6}}
-                                render={({field: {ref, onChange, value}, fieldState: {error}}) => (
-                                    <PasswordInput
-                                        className={classNames({'input-control--error': error})}
-                                        value={value}
-                                        message={error?i18n.t("form_errors.pass"):''}
-                                        onChange={e => onChange(e.target.value)}
-                                        placeholder={i18n.t('login.re_pwd')}
-                                        innerRef={ref}/>
-                                )}
-                    />
-                    <button className={"button-green"}>
-                        {
-                            regStatus===REQ_STATUS.LOADING?renderLoading():i18n.t("login.sign_up_btn")
-                        }
-                    </button>
-                    <div className={styles.l_reg_new}>
-                        <div>{i18n.t("login.login_des")}</div>
-                        <div className={styles.reg_btn} onClick={()=>{
-                            // setShowType(TYPE_LOGIN);
-                            if(isMobile())navigatRoute(ROUTE_PATH.SIGN_IN)
-                            else setShowType(TYPE_LOGIN);
-                        }}>
-                            {i18n.t("login.sign_in_btn")}
+                {
+                    isAccountLogin?(
+                        <div className={styles.l_type_tabs}>
+                            <button className={`${styles.l_type_btn} ${regType === REG_TYPE_PHONE ? styles.active : ''}`}
+                                    onClick={() => {
+                                        setRegType(REG_TYPE_PHONE);
+                                    }}>
+                                <span>{i18n.t("login.reg_type.phone")}</span>
+                            </button>
+                            <button
+                                className={`${styles.l_type_btn} ${regType === REG_TYPE_ACCOUNT ? styles.active : ''}`}
+                                onClick={() => {
+                                    setRegType(REG_TYPE_ACCOUNT)
+                                }}>
+                                <span>{i18n.t("login.login_type.account")}</span>
+                            </button>
                         </div>
-                    </div>
-                </form>
+                    ):(<></>)
+                }
+                {renderRegType()}
             </Spring>
         )
     }
-    const renderForgetForm=()=>{
+    //register_______________
+
+    const renderForgetForm = () => {
         return (
             <Spring type="slideUp">
                 <div className={styles.l_title}>{i18n.t("login.forget_title")}</div>

+ 32 - 1
src/widgets/UserSettings/index.jsx

@@ -1,7 +1,7 @@
 import styles from './styles.module.scss';
 import {useDispatch, useSelector} from "react-redux";
 import {ReactComponent as EmptyAvatar} from '@assets/avatar_empty.svg';
-import {getIsGuest, getLogoutStatus, getUpgradeBonus, getUserInfo, isLogined} from "@features/mainSlice";
+import {getArea, getIsGuest, getLogoutStatus, getUpgradeBonus, getUserInfo, isLogined} from "@features/mainSlice";
 import Spring from "@components/Spring";
 import {useNavigate} from "react-router-dom";
 import {ROUTE_PATH} from "@constants/routes";
@@ -18,6 +18,7 @@ import {ReactComponent as InstallIcon} from "@assets/singlesvg/install.svg";
 import {ReactComponent as SoundOnIcon} from "@assets/singlesvg/sound-on.svg";
 import {ReactComponent as SoundOffIcon} from "@assets/singlesvg/sound-off.svg";
 import {ReactComponent as BindPhone} from "@assets/singlesvg/userupgrade.svg";
+import {ReactComponent as AreaIcon} from "@assets/singlesvg/area_map.svg";
 import {CopyToClipboard} from 'react-copy-to-clipboard';
 import {toast} from "react-toastify";
 import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
@@ -30,6 +31,7 @@ import SmallLoading from "@components/SmallLoading";
 import {APP_GENDER, APP_THEME} from "@constants/app";
 import AntSwitch from "@components/AntSwitch";
 import LazyImgix from "@components/Imgix/LazyImgix";
+import areaData from "@db/area";
 const i18n=global.i18n;
 
 const UserSettings=()=>{
@@ -41,6 +43,7 @@ const UserSettings=()=>{
     const {theme, toggleTheme,setIsShowLang,installOpen,toggleInstallOpen,soundOpen,toggleSoundOpen} = useThemeProvider();
     const guest=useSelector(getIsGuest);
     const upgradBonus=useSelector(getUpgradeBonus);
+    const area=useSelector(getArea);
     const renderEmpty=()=>{
         return (
             <div className={styles.wrap_item}>
@@ -85,6 +88,17 @@ const UserSettings=()=>{
         }
         return email;
     }
+    const getAreaName=()=>{
+        if (areaData!=null){
+            for (let i = 0; i < areaData.length; i++) {
+                let item=areaData[i];
+                if (item.id===area){
+                    return item.name;
+                }
+            }
+        }
+        return "";
+    }
     const renderPhone=()=>{
         return (
             <div className={styles.action_item}>
@@ -359,6 +373,22 @@ const UserSettings=()=>{
             </>
         )
     }
+    const renderItemArea=()=>{
+        return (
+            <button className={styles.action_item} onClick={()=>{
+                global.showAreaSelect();
+            }}>
+                <div className={styles.action_left}>
+                    <AreaIcon className={styles.icon}></AreaIcon>
+                    <div>{i18n.t("settings.area_select")}</div>
+                </div>
+                <div className={styles.action_right}>
+                    <div>{i18n.t(getAreaName())}</div>
+                    <SvgIcon className={styles.icon} herf={"icon_Arrow"}></SvgIcon>
+                </div>
+            </button>
+        )
+    }
     const renderSetting=()=>{
         return (
             <div className={`${styles.wrap_item} ${styles.action_wrap}`}>
@@ -366,6 +396,7 @@ const UserSettings=()=>{
                 {renderBindPhone()}
                 {renderItemInstallBanner()}
                 {renderItemSound()}
+                {renderItemArea()}
                 {renderItemLang()}
                 {/*{renderItemGender()}*/}
                 {renderItemTheme()}

+ 118 - 0
src/widgets/WAreaSelect/index.jsx

@@ -0,0 +1,118 @@
+import {useEffect, useState} from "react";
+import styles from "./styles.module.scss";
+import Fade from "@mui/material/Fade";
+import Grow from "@mui/material/Grow";
+import Modal from "@mui/material/Modal";
+import {useSelector} from "react-redux";
+import {getArea} from "@features/mainSlice";
+import areaData from "@db/area";
+import RadioBtn from "@components/RadioBtn";
+const i18n=global.i18n;
+
+const WAreaSelect = ({})=>{
+    const [isShow, setIsShow] = useState(false);
+    const area=useSelector(getArea);
+    const [currArea,setCurrArea]=useState(1);
+    const show=()=>{
+        setIsShow(true);
+    }
+    const hide=()=>{
+        setIsShow(false);
+    }
+    useEffect(()=>{
+        const areaSelect={
+            show,
+            hide
+        };
+        global.areaSelect=areaSelect;
+        return ()=>{
+        }
+    },[])
+    useEffect(()=>{
+        setCurrArea(area);
+    },[area])
+    const getAllData=()=>{
+        let list=[];
+        list=areaData.slice(0);
+        for (let i = 0; i < list.length; i++) {
+            let item=list[i];
+            if (item.id===area){
+                list.splice(i,1);
+                list.unshift(item);
+                break;
+            }
+        }
+        return list;
+    }
+    const onChangeArea=(value)=>{
+        setCurrArea(value);
+    }
+    const renderHeader=()=>{
+        return (
+            <>
+                <div className={styles.header}>
+                    {i18n.t("areaSelect.title")}
+                </div>
+                <div className={styles.line}/>
+            </>
+        )
+    }
+    const renderContent=()=>{
+        let list=getAllData();
+        return (
+            <div className={styles.content}>
+                {
+                    list.map((item,index)=>{
+                        return (
+                            <button onClick={()=>{
+                                onChangeArea(item.id);
+                            }} className={`${styles.item} ${currArea===item.id?styles.active:''}`} key={index}>
+                                <div className={styles.left}>
+                                    <img className={styles.icon} src={item.icon}/>
+                                    {i18n.t(item.name)}
+                                </div>
+                                <RadioBtn selected={currArea===item.id} value={item.id} onChange={(value)=>{
+                                    onChangeArea(item.id);
+                                }} />
+                            </button>
+                        )
+                    })
+                }
+            </div>
+        )
+    }
+    const renderConfirm=()=>{
+        return (
+            <button className={"button-green"} onClick={()=>{
+
+            }}>
+                {i18n.t("areaSelect.btn_confirm")}
+            </button>
+        )
+    }
+    return (
+        <Modal open={isShow} onClose={()=>{
+            hide();
+        }} closeAfterTransition>
+            <Fade in={isShow} timeout={500}>
+                <div className="popup-container">
+                    <Grow in={isShow} timeout={500}>
+                        <div className={`popup card card-padded`} style={{minHeight: 'unset'}}>
+                            <button className="popup_close" onClick={()=>{
+                                hide();
+                            }} aria-label="Close popup">
+                                <i className="icon-xmark"/>
+                            </button>
+                            <div className={styles.container}>
+                                {renderHeader()}
+                                {renderContent()}
+                                {renderConfirm()}
+                            </div>
+                        </div>
+                    </Grow>
+                </div>
+            </Fade>
+        </Modal>
+    )
+}
+export default WAreaSelect;

+ 59 - 0
src/widgets/WAreaSelect/styles.module.scss

@@ -0,0 +1,59 @@
+.container{
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  width: 100%;
+  height: 100%;
+  gap: 1rem;
+  & .header{
+    display: flex;
+    width: 100%;
+    align-items: center;
+    justify-content: center;
+    font-weight: bold;
+    font-size: 1rem;
+    color: var(--header);
+    gap: 0.5rem;
+  }
+  & .line{
+    border-top: 1px solid var(--card-line);
+  }
+}
+.content{
+  display: flex;
+  flex-direction: column;
+  gap: .75rem;
+  width: 100%;
+  max-height: 15rem;
+  overflow-y: auto;
+  overscroll-behavior: contain;
+  touch-action: pan-y;
+}
+.item{
+  display: flex;
+  flex: none;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 3.25rem;
+  padding: 0 1rem;
+  border-radius: var(--border-radius);
+  font-size: 1rem;
+  color: var(--header);
+  &.active{
+    background: var(--nav-item-hover);
+    font-weight: 600;
+  }
+  & .left{
+    display: flex;
+    align-items: center;
+    gap: 0.5rem;
+    & .icon{
+      width: 1.5rem;
+      height: auto;
+    }
+  }
+  & .right{
+
+  }
+}