zhejiushizhuce 2 tahun lalu
induk
melakukan
df85bebafa
41 mengubah file dengan 1211 tambahan dan 94 penghapusan
  1. 2 1
      src/App.js
  2. 1 0
      src/Global.js
  3. 1 0
      src/api/config.js
  4. 5 0
      src/assets/singlesvg/email-open.svg
  5. 5 0
      src/assets/singlesvg/succss.svg
  6. 4 0
      src/assets/singlesvg/telegram.svg
  7. 6 0
      src/assets/singlesvg/whatsapp.svg
  8. 10 0
      src/assets/wdpop/copy-url-bg.svg
  9. TEMPAT SAMPAH
      src/assets/wdpop/popup_icon001.png
  10. 1 0
      src/components/GameItem/index.jsx
  11. 155 0
      src/components/UInput/MultiNumPassInput.jsx
  12. 3 1
      src/constants/routes.js
  13. 32 1
      src/contexts/themeContext.js
  14. 26 0
      src/db/routes.js
  15. 33 4
      src/features/api.js
  16. 18 1
      src/features/mainSlice.js
  17. 65 58
      src/features/paySlice.js
  18. 30 0
      src/hooks/useAuthLockRoute.js
  19. 2 2
      src/layout/BottomNav/index.jsx
  20. 4 0
      src/layout/Layout.jsx
  21. 17 3
      src/layout/Routes/index.jsx
  22. 4 1
      src/layout/Sidebar/index.jsx
  23. 40 0
      src/locales/languages/en_US.json
  24. 10 0
      src/pages/CustomerService.jsx
  25. 10 0
      src/pages/WithdrawPassEdit.jsx
  26. 5 1
      src/pages/index.jsx
  27. 1 1
      src/styles/_elements.scss
  28. 31 1
      src/styles/_utils.scss
  29. 15 3
      src/widgets/LoginForm/index.jsx
  30. 158 0
      src/widgets/WCustomerService/index.jsx
  31. 103 0
      src/widgets/WCustomerService/styles.module.scss
  32. 5 1
      src/widgets/WDeposit/BR/BRDeposit.jsx
  33. 2 1
      src/widgets/WPaymentOrder/BR/BRPayOrder.jsx
  34. 17 14
      src/widgets/WWithdraw/BR/BRAccountEdit.jsx
  35. 23 0
      src/widgets/WWithdraw/BR/BRWithdraw.jsx
  36. 54 0
      src/widgets/WWithdraw/PassBox/WDPassBox.jsx
  37. 12 0
      src/widgets/WWithdraw/PassBox/styles.module.scss
  38. 157 0
      src/widgets/WWithdraw/PassEdit/WDPassEdit.jsx
  39. 64 0
      src/widgets/WWithdraw/PassEdit/styles.module.scss
  40. 47 0
      src/widgets/WWithdraw/PassPrompt/WDPassPrompt.jsx
  41. 33 0
      src/widgets/WWithdraw/PassPrompt/styles.module.scss

+ 2 - 1
src/App.js

@@ -48,6 +48,7 @@ import LoadingScreen from "@components/LoadingScreen";
 import {reqPayConfig} from "@features/paySlice";
 import {connectHall, disconnectHall} from "@features/actions/hallClient";
 import * as toast from "react-toastify";
+import {useBlocker} from "react-router";
 const App = () => {
     const dispatch = useDispatch();
     const fetchStatus=useSelector(getFetchStatus);
@@ -100,7 +101,7 @@ const App = () => {
         return (
             <>
                 {
-                    fetchStatus==REQ_STATUS.IDLE?<Layout />:(<LoadingScreen />)
+                    fetchStatus===REQ_STATUS.IDLE?<Layout />:(<LoadingScreen />)
                 }
             </>
         )

+ 1 - 0
src/Global.js

@@ -14,3 +14,4 @@ global.msgBoxShow=(params)=>{
 global.msgBoxHide=()=>{
     if (global.msgBox)global.msgBox.hide();
 }
+global.authLockPath=null;

+ 1 - 0
src/api/config.js

@@ -41,6 +41,7 @@ export const APP_PAYMENT_ORDER=BASE_PREFIX+"payment_entry/pay";
 export const APP_WITHDRAW_TAX="api/api/withDrawTax";
 export const APP_WITHDRAW_BASE_INFO=BASE_PREFIX+"withdraw/baseInfo";
 export const APP_WITHDRAW_INFO=BASE_PREFIX+"withDraw/getWithDrawInfo";
+export const APP_CHANGE_PAY_PASS=BASE_PREFIX+"changePayPass";
 //withdraw
 //userinfo
 export const APP_GAME_INFO=BASE_PREFIX+"info";

+ 5 - 0
src/assets/singlesvg/email-open.svg

@@ -0,0 +1,5 @@
+<?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 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.76295 2.05976C8.91094 1.98008 9.08906 1.98008 9.23705 2.05976L14.9482 5.135C15.596 5.48382 16 6.16018 16 6.89594V12.5C16 13.8807 14.8807 15 13.5 15H4.5C3.11929 15 2 13.8807 2 12.5V6.89594C2 6.16018 2.40398 5.48382 3.0518 5.135L8.76295 2.05976ZM9 3.06788L3.5259 6.01547C3.40256 6.08188 3.2969 6.17204 3.21334 6.27854L9.00002 8.94932L14.7867 6.27856C14.7031 6.17205 14.5974 6.08189 14.4741 6.01547L9 3.06788ZM15 7.28147L9.20955 9.95399C9.0766 10.0153 8.92344 10.0153 8.79049 9.95399L3 7.28145V12.5C3 13.3284 3.67157 14 4.5 14H13.5C14.3284 14 15 13.3284 15 12.5V7.28147Z"/>
+<path d="M6.5 17C5.68209 17 4.95592 16.6072 4.49982 16H13.5C15.433 16 17 14.433 17 12.5V6.5C17.6072 6.9561 18 7.68209 18 8.5V12.5C18 14.9853 15.9853 17 13.5 17H6.5Z" />
+</svg>

+ 5 - 0
src/assets/singlesvg/succss.svg

@@ -0,0 +1,5 @@
+<svg width="55" height="55" viewBox="0 0 55 55" fill="none" xmlns="http://www.w3.org/2000/svg" class="s-ion-icon">
+<rect width="55" height="55" rx="27.5" fill="#27D48B"></rect>
+<rect x="41.2139" y="18.03" width="3" height="30" rx="1.5" transform="rotate(45 41.2139 18.03)" fill="white"></rect>
+<rect width="3" height="14.5074" rx="1.5" transform="matrix(-0.707107 0.707107 0.707107 0.707107 14 29)" fill="white"></rect>
+</svg>

+ 4 - 0
src/assets/singlesvg/telegram.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 fill-rule="evenodd" clip-rule="evenodd" d="M23.1117 4.49449C23.4296 2.94472 21.9074 1.65683 20.4317 2.227L2.3425 9.21601C0.694517 9.85273 0.621087 12.1572 2.22518 12.8975L6.1645 14.7157L8.03849 21.2746C8.13583 21.6153 8.40618 21.8791 8.74917 21.968C9.09216 22.0568 9.45658 21.9576 9.70712 21.707L12.5938 18.8203L16.6375 21.8531C17.8113 22.7334 19.5019 22.0922 19.7967 20.6549L23.1117 4.49449ZM3.0633 11.0816L21.1525 4.0926L17.8375 20.2531L13.1 16.6999C12.7019 16.4013 12.1448 16.4409 11.7929 16.7928L10.5565 18.0292L10.928 15.9861L18.2071 8.70703C18.5614 8.35278 18.5988 7.79106 18.2947 7.39293C17.9906 6.99479 17.4389 6.88312 17.0039 7.13168L6.95124 12.876L3.0633 11.0816ZM8.17695 14.4791L8.78333 16.6015L9.01614 15.321C9.05253 15.1209 9.14908 14.9366 9.29291 14.7928L11.5128 12.573L8.17695 14.4791Z" />
+</svg>

+ 6 - 0
src/assets/singlesvg/whatsapp.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
+<title>whatsapp</title>
+<path d="M26.576 5.363c-2.69-2.69-6.406-4.354-10.511-4.354-8.209 0-14.865 6.655-14.865 14.865 0 2.732 0.737 5.291 2.022 7.491l-0.038-0.070-2.109 7.702 7.879-2.067c2.051 1.139 4.498 1.809 7.102 1.809h0.006c8.209-0.003 14.862-6.659 14.862-14.868 0-4.103-1.662-7.817-4.349-10.507l0 0zM16.062 28.228h-0.005c-0 0-0.001 0-0.001 0-2.319 0-4.489-0.64-6.342-1.753l0.056 0.031-0.451-0.267-4.675 1.227 1.247-4.559-0.294-0.467c-1.185-1.862-1.889-4.131-1.889-6.565 0-6.822 5.531-12.353 12.353-12.353s12.353 5.531 12.353 12.353c0 6.822-5.53 12.353-12.353 12.353h-0zM22.838 18.977c-0.371-0.186-2.197-1.083-2.537-1.208-0.341-0.124-0.589-0.185-0.837 0.187-0.246 0.371-0.958 1.207-1.175 1.455-0.216 0.249-0.434 0.279-0.805 0.094-1.15-0.466-2.138-1.087-2.997-1.852l0.010 0.009c-0.799-0.74-1.484-1.587-2.037-2.521l-0.028-0.052c-0.216-0.371-0.023-0.572 0.162-0.757 0.167-0.166 0.372-0.434 0.557-0.65 0.146-0.179 0.271-0.384 0.366-0.604l0.006-0.017c0.043-0.087 0.068-0.188 0.068-0.296 0-0.131-0.037-0.253-0.101-0.357l0.002 0.003c-0.094-0.186-0.836-2.014-1.145-2.758-0.302-0.724-0.609-0.625-0.836-0.637-0.216-0.010-0.464-0.012-0.712-0.012-0.395 0.010-0.746 0.188-0.988 0.463l-0.001 0.002c-0.802 0.761-1.3 1.834-1.3 3.023 0 0.026 0 0.053 0.001 0.079l-0-0.004c0.131 1.467 0.681 2.784 1.527 3.857l-0.012-0.015c1.604 2.379 3.742 4.282 6.251 5.564l0.094 0.043c0.548 0.248 1.25 0.513 1.968 0.74l0.149 0.041c0.442 0.14 0.951 0.221 1.479 0.221 0.303 0 0.601-0.027 0.889-0.078l-0.031 0.004c1.069-0.223 1.956-0.868 2.497-1.749l0.009-0.017c0.165-0.366 0.261-0.793 0.261-1.242 0-0.185-0.016-0.366-0.047-0.542l0.003 0.019c-0.092-0.155-0.34-0.247-0.712-0.434z"></path>
+</svg>

+ 10 - 0
src/assets/wdpop/copy-url-bg.svg

@@ -0,0 +1,10 @@
+<svg viewBox="0 0 340 100" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 20C0 8.9543 8.95431 0 20 0H320C331.046 0 340 8.95431 340 20V100H0V20Z" fill="url(#paint0_linear_5375_3601)"/>
+<defs>
+<linearGradient id="paint0_linear_5375_3601" x1="-4.46447e-06" y1="7.40742" x2="325.092" y2="131.149" gradientUnits="userSpaceOnUse">
+<stop stop-color="#74DBFE"/>
+<stop offset="0.475" stop-color="#8BB7FF"/>
+<stop offset="1" stop-color="#CB89FE"/>
+</linearGradient>
+</defs>
+</svg>

TEMPAT SAMPAH
src/assets/wdpop/popup_icon001.png


+ 1 - 0
src/components/GameItem/index.jsx

@@ -27,6 +27,7 @@ const GameItem=({data})=>{
         let url=data.link;
         localStorageSet(LOCAL_GAME_URL+id,url);
         let path=ROUTE_PATH.GAME+"/"+id;
+        global.authLockPath=path;
         navigate(path);
     }
     //to={ROUTE_PATH.GAME+"/"+data.id+"?url="+data.link}

+ 155 - 0
src/components/UInput/MultiNumPassInput.jsx

@@ -0,0 +1,155 @@
+import {useEffect, useRef, useState} from "react";
+import styled from 'styled-components/macro';
+import {toast} from 'react-toastify';
+const StyledInput= styled.input`
+  position: absolute;
+  font-size:1.2rem !important;
+  font-weight:700 !important;
+  text-align: center;
+  padding: .5rem !important;
+`;
+const StyledInputControl=styled.button`
+    padding: 0rem !important;
+    justify-content: center !important;
+    height:3.5rem !important;
+`
+const StyledPass=styled.div`
+    width: 0.65rem;
+    height: 0.65rem;
+    background: var(--header);
+    border-radius: 50%;
+`
+const MultiNumPassInput=({innerRef, ...props})=>{
+    const [values,setValues]=useState([]);
+    const [focusIndex,setFocusIndex]=useState(-1);
+    const {length,value,focus,onChange,onFinish,className}=props;
+    const col=length<1?1:length;
+    const inputRef = useRef(null);
+    const btnRefs = useRef([]);
+
+    useEffect(()=>{
+        initValues();
+        return ()=>{
+
+        }
+    },[]);
+    useEffect(()=>{
+        if (inputRef.current)inputRef.current.focus();
+    },[focusIndex]);
+    useEffect(()=>{
+        if (focus){
+            if (values.length>0){
+                checkFocus(values);
+            }
+        }
+    },[focus])
+
+    const initValues=()=>{
+        let values=[];
+        let initValues=[];
+        if (value!=null){
+            initValues=value.split('');
+        }
+        for (let i = 0; i <length ; i++) {
+            values[i]=initValues[i]?initValues[i]:"";
+        }
+        setValues(values);
+        if (focus)checkFocus(values);
+    }
+    // const checkFocus=(index)=>{
+    //     // console.log(inputRefs);
+    //     for (let i = 0; i <values.length; i++) {
+    //         let value=values[i];
+    //         if (i===index)continue;
+    //         if (value===""){
+    //             let input=inputRefs[i];
+    //             if (input)input.focus();
+    //             break;
+    //         }
+    //     }
+    // }
+    const checkFocus=(valueArr)=>{
+        let fIndex=-1;
+        for (let i = 0; i <valueArr.length; i++) {
+            let value=valueArr[i];
+            if (value===""){
+                fIndex=i;
+                break;
+            }
+        }
+        setFocusIndex(fIndex);
+        // toast.success(fIndex);
+        if (fIndex===-1){
+            if (onFinish)onFinish(valueArr);
+        }
+    }
+    const handleChange=(index,value)=>{
+        let valueArr=values.slice(0);
+        valueArr[index]=value;
+        if (value!==""){
+            checkFocus(valueArr);
+        }
+        else
+        {
+            if (index==0){
+                valueArr=Array.from({ length: length }, (_, index) => "");
+            }
+        }
+        setValues(valueArr);
+        if (onChange)onChange(index,value);
+    }
+
+    const renderContent=()=>{
+        return (
+            <>
+                {
+                    values.map((value,index)=>{
+                        return (
+                            <StyledInputControl
+                                ref={(ref) => (btnRefs.current[index] = ref)}
+                                onClick={()=>{
+                                    setFocusIndex(index);
+                                }}
+                                type={"button"} key={index} className={`input-control ${value===""?className:''}`}>
+                                {
+                                    !(focusIndex===index)?(<></>):(
+                                        <StyledInput
+                                            ref={inputRef}
+                                            // autoFocus={true}
+                                            onChange={(e)=>{
+                                                let text=e.target.value;
+                                                handleChange(index,text)
+                                            }}
+                                            onFocus={()=>{
+                                                handleChange(index,"");
+                                            }}
+                                            onKeyDown={(e)=>{
+                                                if (e.keyCode === 8 || e.key === "Backspace") {
+                                                    if (focusIndex>0){
+                                                        setFocusIndex(focusIndex-1);
+                                                    }
+                                                }
+                                            }}
+                                            value={""}
+                                            type={"number"}
+                                            pattern="[0-9]*"
+                                        />
+                                    )
+                                }
+                                {
+                                    value==null||value===""?(<></>):(<StyledPass/>)
+                                }
+                            </StyledInputControl>
+                        )
+                    })
+                }
+            </>
+        )
+    }
+    return (
+        <div className={`w-100 d-grid g-16 row-1 ${'col-'+col}`} ref={innerRef}>
+            {renderContent()}
+        </div>
+    )
+}
+export default MultiNumPassInput;

+ 3 - 1
src/constants/routes.js

@@ -20,7 +20,9 @@ const ROUTE_PATH={
     PAY:"#/pay",
     SAQUE:"#/saque",
     PAY_ORDER:"#/payorder",
-    ACCOUNT_INFO:"#/accountInfo"
+    ACCOUNT_INFO:"#/accountInfo",
+    CHANGE_PAY_PASS:"#/changePayPass",
+    CUSTOMER:"#/customer"
 }
 
 export {

+ 32 - 1
src/contexts/themeContext.js

@@ -2,6 +2,9 @@ import {createContext, useContext, useEffect, useState} from 'react';
 import {isRtlLang} from 'rtl-detect';
 import {useWindowSize} from "react-use";
 import {APP_THEME} from "@constants/app";
+import {ROUTE_PATH} from "@constants/routes";
+import {useSelector} from "react-redux";
+import {getUserInfo, isLogined} from "@features/mainSlice";
 
 const ThemeContext = createContext(undefined);
 
@@ -39,7 +42,11 @@ export const ThemeProvider = ({children}) => {
     //lang select
     const [isShowLang,setIsShowLang]=useState(false);
 
+    //show pass prompt
+    const [isShowPassPrompt,setIsShowPassPrompt]=useState(false);
 
+    const isLogin=useSelector(isLogined);
+    const user=useSelector(getUserInfo);
     const stopTransition = () => {
         page.classList.add('no-transition');
         setTimeout(() => page.classList.remove('no-transition'), 100);
@@ -76,6 +83,26 @@ export const ThemeProvider = ({children}) => {
         setIsShowSearch(show);
         setSearchData(data);
     }
+    //检查提现
+    const checkWithdraw=()=>{
+        if (isLogin){
+            if (user){
+                let InsurePass=Number(user.InsurePass);
+                if (InsurePass!==1){
+                    setIsShowPassPrompt(true);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    //检查路由是否允许跳转
+    const checkRoute=(path)=>{
+        if (path===ROUTE_PATH.SAQUE){
+            return checkWithdraw();
+        }
+        return true;
+    }
 
     useEffect(() => {
 
@@ -115,7 +142,11 @@ export const ThemeProvider = ({children}) => {
                 setShowHeader,
                 //lang
                 isShowLang,
-                setIsShowLang
+                setIsShowLang,
+                isShowPassPrompt,
+                setIsShowPassPrompt,
+                //检查路由是否允许跳转
+                checkRoute
             }}>
             {children}
         </ThemeContext.Provider>

+ 26 - 0
src/db/routes.js

@@ -217,4 +217,30 @@ export const routes=[
         lpath:"#/signin",//登录path
         subs:[]
     },
+    {
+        path: "#/changePayPass",
+        type: 1,
+        side: 0,
+        block:1,//块排序
+        title: "Withdraw Password",
+        icon:"",
+        fill:";;",//icon 颜色 默认 选中 本身颜色
+        component:"wdPassEdit",
+        login:1,//0,1 检不检查登录
+        lpath:"#/signin",//登录path
+        subs:[]
+    },
+    {
+        path: "#/customer",
+        type: 1,
+        side: 0,
+        block:1,//块排序
+        title: "Customer service",
+        icon:"",
+        fill:";;",//icon 颜色 默认 选中 本身颜色
+        component:"customer",
+        login:1,//0,1 检不检查登录
+        lpath:"#/signin",//登录path
+        subs:[]
+    },
 ]

+ 33 - 4
src/features/api.js

@@ -2,18 +2,30 @@ import {createAsyncThunk} from "@reduxjs/toolkit";
 import {
     APP_ACCOUNTS_PAY_INFO,
     APP_CHANGE_EMAIL,
-    APP_CHANGE_INFO, APP_CHANGE_PASS, APP_CHANGE_PHONE, APP_CUSTOMER_SERVICE, APP_FIRSTPAY_CONFIG, APP_GAME_INFO,
+    APP_CHANGE_INFO,
+    APP_CHANGE_PASS,
+    APP_CHANGE_PAY_PASS,
+    APP_CHANGE_PHONE,
+    APP_CUSTOMER_SERVICE,
+    APP_FIRSTPAY_CONFIG,
+    APP_GAME_INFO,
     APP_GAME_LIST,
     APP_LOGIN,
     APP_LOGOUT,
-    APP_PAGE_MODULES, APP_PAYMENT_ORDER, APP_RECHARGE_CONFIG,
+    APP_PAGE_MODULES,
+    APP_PAYMENT_ORDER,
+    APP_RECHARGE_CONFIG,
     APP_REGISTER,
-    APP_ROUTES, APP_WITHDRAW_BASE_INFO, APP_WITHDRAW_INFO, APP_WITHDRAW_TAX,
+    APP_ROUTES,
+    APP_WITHDRAW_BASE_INFO,
+    APP_WITHDRAW_INFO,
+    APP_WITHDRAW_TAX,
     REQ_STATUS
 } from "@api/config";
 import Http from "@api/request";
 import {updateGameList} from "@features/pageSlice";
 import {APP_CHANNEL} from "@constants/app";
+import {updateInsurePass, updateUserInfo} from "@features/mainSlice";
 
 export const buildReqReducer=(builder,thunk,callback,statusCB=null)=>{
     if (builder==null||thunk==null)return;
@@ -220,6 +232,7 @@ export const reqPaymentOrder=createAsyncThunk(
     APP_PAYMENT_ORDER,
     async (arg,thunkAPI)=>{
         let {user,price,goodsName,payType,GiftsID}=arg;
+        console.log(arg)
         let params={
             url:APP_PAYMENT_ORDER,
             params:{
@@ -268,13 +281,29 @@ export const reqWithdrawBaseInfo=createAsyncThunk(
 export const reqWithdrawInfo=createAsyncThunk(
     APP_WITHDRAW_INFO,
     async (arg, thunkAPI) => {
+        let {UserID}=arg;
         let params={
-            url:APP_WITHDRAW_INFO
+            url:APP_WITHDRAW_INFO,
+            params:{
+                UserID:UserID
+            }
         }
         const response=await Http.get(params);
         return response;
     }
 )
+export const reqChangePayPass=createAsyncThunk(
+    APP_CHANGE_PAY_PASS,
+    async (arg, thunkAPI) => {
+        let params={
+            url:APP_CHANGE_PAY_PASS,
+            data:arg
+        }
+        const response=await Http.post(params);
+        thunkAPI.dispatch(updateUserInfo(response));
+        return response;
+    }
+)
 //withdraw
 //用户信息
 export const reqGameInfo=createAsyncThunk(

+ 18 - 1
src/features/mainSlice.js

@@ -321,6 +321,9 @@ export const Main=createSlice({
             state.isLogin=0;
             // localStorageSet(LOCAL_USER_INFO,"");
             // localStorageSet(LOCAL_IS_LOGIN,0);
+        },
+        updateUserInfo:(state, action)=>{
+            parseLogin(state,action,{},false);
         }
     },
     extraReducers: (builder) => {
@@ -338,7 +341,7 @@ export const Main=createSlice({
         buildReqReducer(builder,reqCustomService,reducerCustom,null);
     },
 })
-export const {logout} = Main.actions;
+export const {logout,updateUserInfo} = Main.actions;
 //数据获取
 export const getFetchStatus=(state)=>{
     return state.main.status;
@@ -469,6 +472,20 @@ export const getUserID=(state)=>{
 export const getCustomInfo=(state)=>{
     return state.main.customerInfo;
 }
+export const getCustomTypeInfo=(type)=>(state)=>{
+    let item=null;
+    let customerInfo=state.main.customerInfo;
+    if (customerInfo){
+        for (let i = 0; i < customerInfo.length; i++) {
+            let info=customerInfo[i];
+            if (info.StatusName===type){
+                item=info;
+                break;
+            }
+        }
+    }
+    return item
+}
 //数据获取
 export default Main.reducer;
 

+ 65 - 58
src/features/paySlice.js

@@ -1,12 +1,14 @@
 import {createSlice} from "@reduxjs/toolkit";
 import {REQ_STATUS} from "@api/config";
 import {
-    buildReqReducer,
+    buildReqReducer, reqChangePayPass,
     reqFirstPayConfig,
     reqGetAccountsPayInfo,
     reqPaymentOrder,
     reqRechargeConfig, reqWithdrawBaseInfo, reqWithdrawInfo, reqWithdrawTax
 } from "@features/api";
+import {getHttpMsg} from "@utils/helpers";
+import {toast} from "react-toastify";
 const reducerRechargeConfig=(state,action,arg)=>{
     let payload=action.payload;
     if (payload!=null&&payload.code===200){
@@ -19,32 +21,31 @@ const rechargeConfigStatus=(state,status,arg)=>{
 }
 const reducerFirstPayConfig=(state,action,arg)=>{
     let payload=action.payload;
-    payload={
-        "data": {
-            "first_pay": {
-                "id": "1017",
-                "money": "10",
-                "gear": "[{\"id\":\"28\",\"name\":\"PIX\\u76f4\\u8fde\",\"status\":1,\"type\":3}]",
-                "status": "1",
-                "created_at": "2022-06-09 13:57:58.000",
-                "favorable_price": 20,
-                "image": "11",
-                "give": "10",
-                "first_pay": "1",
-                "name": "\u9996\u5145\u6863\u4f4d\u914d\u7f6e",
-                "gift_id": "201",
-                "channels": "-1"
-            },
-            "recomendar_recharge": "7"
-        },
-        "result": "",
-        "msg": "success",
-        "code": 200
-    };
+    // payload={
+    //     "data": {
+    //         "first_pay": {
+    //             "id": "1017",
+    //             "money": "10",
+    //             "gear": "[{\"id\":\"28\",\"name\":\"PIX\\u76f4\\u8fde\",\"status\":1,\"type\":3}]",
+    //             "status": "1",
+    //             "created_at": "2022-06-09 13:57:58.000",
+    //             "favorable_price": 20,
+    //             "image": "11",
+    //             "give": "10",
+    //             "first_pay": "1",
+    //             "name": "\u9996\u5145\u6863\u4f4d\u914d\u7f6e",
+    //             "gift_id": "201",
+    //             "channels": "-1"
+    //         },
+    //         "recomendar_recharge": "7"
+    //     },
+    //     "result": "",
+    //     "msg": "success",
+    //     "code": 200
+    // };
     if (payload!=null&&payload.code===200){
         let data=payload.data;
         state.firstconfig=data;
-        console.log(state.firstconfig)
     }
 }
 const firstPayConfigStatus=(state,status,arg)=>{
@@ -62,16 +63,16 @@ const getAccountsPayInfoStatus=(state,status,arg)=>{
 }
 const reducerPaymentOrder=(state,action,arg)=>{
     let payload=action.payload;
-    payload={
-        "data": {
-            "content": "00020101021226830014br.gov.bcb.pix2561pix.delbank.com.br\/v1\/qrcode\/vcharge22e43499260b46a9a5f303ca55204000053039865802BR5907DELBANK6007ARACAJU62070503***6304F3DF",
-            "money": 10,
-            "prdOrdNo": "BR5050013857473344515256"
-        },
-        "result": "",
-        "msg": "success",
-        "code": 200
-    };
+    // payload={
+    //     "data": {
+    //         "content": "00020101021226830014br.gov.bcb.pix2561pix.delbank.com.br\/v1\/qrcode\/vcharge22e43499260b46a9a5f303ca55204000053039865802BR5907DELBANK6007ARACAJU62070503***6304F3DF",
+    //         "money": 10,
+    //         "prdOrdNo": "BR5050013857473344515256"
+    //     },
+    //     "result": "",
+    //     "msg": "success",
+    //     "code": 200
+    // };
     if (payload!=null&&payload.code===200){
         let data=payload.data;
         data.createAt=Date.now();
@@ -79,7 +80,6 @@ const reducerPaymentOrder=(state,action,arg)=>{
         state.currPayOrder=data;
         if (arg.callback!=null)arg.callback();
     }
-    console.log(payload)
 }
 const paymentOrderStatus=(state,status,arg)=>{
     state.status.PaymentOrder=status;
@@ -111,6 +111,23 @@ const reducerWithdrawInfo=(state,action,arg)=>{
         }
     }
 }
+const reducerChangePayPass=(state,action,arg)=>{
+    let payload=action.payload;
+    let msg=getHttpMsg(payload);
+    if (payload&&payload.code===200){
+        let data=payload.data;
+        if (data){
+            // state.withdrawInfo=data;
+        }
+        toast.success(msg);
+    }
+    else{
+        toast.error(msg);
+    }
+}
+const changePayPassStatus=(state,status,arg)=>{
+    state.status.ChangePayPass=status;
+}
 export const Pay=createSlice({
     name: 'pay',
     initialState: {
@@ -118,7 +135,8 @@ export const Pay=createSlice({
             RechargeConfig:REQ_STATUS.NONE,
             FirstPayConfig:REQ_STATUS.NONE,
             GetAccountsPayInfo:REQ_STATUS.NONE,
-            PaymentOrder:REQ_STATUS.NONE
+            PaymentOrder:REQ_STATUS.NONE,
+            ChangePayPass:REQ_STATUS.NONE
         },
         config:[],
         payconfig:null,
@@ -127,26 +145,7 @@ export const Pay=createSlice({
         currPayOrder:null,
         WithDrawTax:4,
         withdrawBaseInfo:null,
-        withdrawInfo:null,
-        // withdrawBaseInfo:{
-        //     // "Achieves": null,
-        //     // "SumCanExchange": "3482",
-        //     // "AccountsBank": "",
-        //     // "BranchBank": "",
-        //     // "BankNO": "",
-        //     // "MinExchange": "6000",
-        //     // "MaxExchange": "3000000",
-        //     // "OrderLimit": "3",
-        //     // "OrderCount": "0",
-        //     // "BankUserName": "",
-        //     // "PhoneNumber": "",
-        //     // "IFSCNumber": "",
-        //     // "EmailAddress": "",
-        //     // "PANNumber": "",
-        //     // "AdhaarNumber": "",
-        //     // "PixNum": "",
-        //     // "PixType": "0"
-        // }
+        withdrawInfo:null
     },
     reducers: {
 
@@ -159,6 +158,7 @@ export const Pay=createSlice({
         buildReqReducer(builder,reqWithdrawTax,reducerWithdrawTax,null);
         buildReqReducer(builder,reqWithdrawBaseInfo,reducerWithdrawBaseInfo,null);
         buildReqReducer(builder,reqWithdrawInfo,reducerWithdrawInfo,null);
+        buildReqReducer(builder,reqChangePayPass,reducerChangePayPass,changePayPassStatus);
     },
 })
 export const {} = Pay.actions;
@@ -173,13 +173,15 @@ export const getFirstPay=(state)=>{
         let first_pay=firstconfig.first_pay;
         let recomendar_recharge=firstconfig.recomendar_recharge;
         if (first_pay!=null){
+            let gear=JSON.parse(first_pay.gear);
+            if (gear)gear=gear[0];
             order={
                 goodsName:"firstpay",
                 goodsPrice:first_pay.money,
                 GiftsID: 201,
                 cpf_first:0,
                 give:first_pay.give,
-                gear:JSON.parse(first_pay.gear)
+                gear:gear
             }
         }
         else
@@ -187,13 +189,15 @@ export const getFirstPay=(state)=>{
             for (let i = 0; i <config.length ; i++) {
                 const elem = config[i];
                 if (elem.id===recomendar_recharge){
+                    let gear=JSON.parse(elem.gear);
+                    if (gear)gear=gear[0];
                     order={
                         goodsName: "chip",
                         goodsPrice: elem.money,
                         GiftsID:elem.gift_id,
                         cpf_first:0,
                         give:elem.give,
-                        gear:JSON.parse(elem.gear)
+                        gear:gear
                     }
                     break;
                 }
@@ -214,6 +218,9 @@ export const getWithdrawBaseInfo=(state)=>{
 export const getWithdrawInfo=(state)=>{
     return state.pay.withdrawInfo;
 }
+export const getChangePayPassStatus=(state)=>{
+    return state.pay.status.ChangePayPass;
+}
 export default Pay.reducer;
 
 export const reqPayConfig=(dispatch,userInfo)=>{

+ 30 - 0
src/hooks/useAuthLockRoute.js

@@ -0,0 +1,30 @@
+import {useEffect, useState} from "react";
+import {ROUTE_PATH} from "@constants/routes";
+import {useLocation} from "react-router-dom";
+
+const useAuthLockRoute=()=>{
+    const location = useLocation();
+    const [lockPath, setLockPath] = useState("");
+    //如果不是登录和注册则清除
+    const unLockRoute=(path,force=false)=>{
+        if (!force&&(path==ROUTE_PATH.SIGN_IN||path==ROUTE_PATH.SIGN_UP)){
+            return;
+        }
+        setLockPath("");
+    }
+    const lockRoute=(path)=>{
+        setLockPath(path);
+    }
+    useEffect(() => {
+        return () => {
+
+        }
+    }, [location]);
+    return {
+        lockPath,
+        // setLockPath,
+        lockRoute,
+        unLockRoute
+    }
+}
+export default useAuthLockRoute;

+ 2 - 2
src/layout/BottomNav/index.jsx

@@ -94,14 +94,14 @@ const BottomNav = () => {
                 <TabMessage className={styles.icon}/>
                 <span>{i18n.t("tab.message")}</span>
             </button>
-            <button className={styles.button}>
+            <NavLink className={styles.button} to={ROUTE_PATH.CUSTOMER}>
                 <div className={styles["dont-badge"]}></div>
                 {/*<svg className={"icon"}>*/}
                 {/*    <use xlinkHref={`${symbol}#icon_Chat`} />*/}
                 {/*</svg>*/}
                 <TabSett className={styles.icon}></TabSett>
                 <span>{i18n.t("tab.service")}</span>
-            </button>
+            </NavLink>
         </div>
     )
 }

+ 4 - 0
src/layout/Layout.jsx

@@ -20,6 +20,8 @@ import CSSTransition from "react-transition-group/CSSTransition";
 import Transition from "react-transition-group/Transition";
 import WLangSelect from "@widgets/WLangSelect";
 import MsgBox from "@components/MsgBox";
+import WDPassPrompt from "@widgets/WWithdraw/PassPrompt/WDPassPrompt";
+import useAuthLockRoute from "@hooks/useAuthLockRoute";
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
 
 const Layout=()=>{
@@ -31,6 +33,7 @@ const Layout=()=>{
     const inRoutes=useSelector(routesIn);
     const popRoutes=useSelector(routesPop);
     const isLogin=useSelector(isLogined);
+    // const {setLockPath}=useAuthLockRoute();
     useEffect(() => {
         // scroll to top on route change
         appRef.current && appRef.current.scrollTo(0, 0);
@@ -96,6 +99,7 @@ const Layout=()=>{
             <>
                 <WLangSelect/>
                 <MsgBox ref={msgBoxRef}/>
+                <WDPassPrompt/>
             </>
         )
     }

+ 17 - 3
src/layout/Routes/index.jsx

@@ -9,6 +9,8 @@ import RouteContainer from "@layout/Routes/RouteContainer";
 import {Navigate, useLocation} from "react-router";
 import usePreviousRoute from "@hooks/usePreviousRoute";
 import {ROUTE_PATH} from "@constants/routes";
+import {useThemeProvider} from "@contexts/themeContext";
+import useAuthLockRoute from "@hooks/useAuthLockRoute";
 const RouteWrapper = lazy(() => import('@layout/Routes/RouteWrapper'));
 
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
@@ -17,9 +19,10 @@ const CreateRoute=(props)=>{
     const {route,path,isLogin}=props;
     const component=(route.component!=null&&route.component!=="")?route.component:"ModulePage";
     const Component = AllComponents[component];
+    const topath=path?path:route.path;
     const checkLogin=()=>{
         if (!isLogin&&route.login===1){
-            return (<Navigate to={route.lpath} replace={true}></Navigate>)
+            return (<Navigate to={route.lpath} replace={true}/>)
         }
         return (
             <RouteWrapper {...{ ...props, Comp: Component, route: route }}  />
@@ -30,7 +33,7 @@ const CreateRoute=(props)=>{
             <Route
                 key={route.path}
                 exact
-                path={path?path:route.path}
+                path={topath}
                 element={checkLogin()}
             >
 
@@ -54,6 +57,7 @@ const CBrowserRouter=(props)=>{
 }
 const CHashRouter=(props)=>{
     const {routes,hlocation,isLogin}=props;
+    const {checkRoute}=useThemeProvider();
     const navigate = useNavigate()
     //多hash 切到最后一个
     let {pathname,hash,search}=hlocation;
@@ -61,6 +65,7 @@ const CHashRouter=(props)=>{
     pathname=paths.shift();
     let hashs=hash.split("#");
     let currpath=pathname+hash;
+    let currhash="";
     const timeout=200;
     //多hash 切到最后一个
     const getRoutes=(path)=>{
@@ -87,9 +92,18 @@ const CHashRouter=(props)=>{
                     if (route==null)return (<></>);
                     if (!isLogin&&route.login==1){
                         //检测未登录
-                        navigate(route.lpath,{replace:true});
+                        global.authLockPath=currpath;
+                        navigate(pathname+currhash+route.lpath,{replace:true});
                         return (<></>);
+                        // return (<Navigate to={pathname + currhash + route.lpath} replace={true}/>)
                     }
+                    //再次检查路由
+                    if (!checkRoute(route.path)){
+                        navigate(pathname+currhash,{replace:true});
+                        return (<></>);
+                        // return (<Navigate to={pathname+currhash} replace={true}/>)
+                    }
+                    currhash+=hash;
                     return (
                         <CSSTransition timeout={timeout}>
                             <RouteContainer route={route} timeout={timeout} onClose={handleClose} header={Header[route.component]}>

+ 4 - 1
src/layout/Sidebar/index.jsx

@@ -61,6 +61,7 @@ import {
     nBlocks
 } from "@features/mainSlice";
 import {
+    ROUTE_PATH,
     ROUTE_TYPE_OUTLINK,
     ROUTE_TYPE_POP,
     ROUTE_TYPE_POP_OR_FULL,
@@ -407,7 +408,9 @@ const Sidebar = () => {
             <StyledBlock open={open}>
                 {/*{renderLogout()}*/}
                 <MTooltip disableHoverListener={open} title={i18n.t("links.live_support")} arrow placement="right">
-                    <StyledButton open={open} className="h4" fill={"#3bc117"}>
+                    <StyledButton open={open} className="h4" fill={"#3bc117"} onClick={()=>{
+                        navigate(ROUTE_PATH.CUSTOMER);
+                    }}>
                         <SvgIcon className={"icon"} herf={"icon_Support"}/>
                         {open?i18n.t("links.live_support"):""}
                     </StyledButton>

+ 40 - 0
src/locales/languages/en_US.json

@@ -243,6 +243,46 @@
         "is_error": "incorrect format"
 
       }
+    },
+    "pass": {
+      "prompt": "For the security of your funds, please set up a fund password first",
+      "btn_confirm": "Confirm",
+      "edit_title": "Configure Withdraw Password",
+      "new_pass": "New Withdraw Password",
+      "re_pass": "Confirm New Password",
+      "btn_submit": "Withdraw Now",
+      "tips": {
+        "success": "Successfully configured",
+        "des": "New password established correctly, remember your password",
+        "btn_back": "Return to home page",
+        "btn_withdraw": "Withdraw Now",
+        "err_not_same": "The password input is inconsistent, please re-enter it."
+      },
+      "pass_box_title": "Enter the withdrawal password"
     }
+  },
+  "customer": {
+    "TitleLabel": "Customer service",
+    "leavemsg_notice": "Describe your questions and comments. (up to 300 characters)",
+    "TipLabel": "If you encounter any problems in the game, please contact the customer service below.",
+    "Input_tip_Label": "Alternatively, you can leave us a message.",
+
+    "Btn_send": "Submit",
+    "Item_customer_Label": "Contact Directly",
+
+    "input_holder": "Please describe your questions and comments. (up to 300 characters)",
+
+    "TopTip_succeed": "Message successful!",
+    "TopTip_fail": "Message failed!",
+    "TopTip_chatIsNull": "The content can not be blank!",
+    "TopTip_timerFail": "Too many messages, please try again later!",
+
+    "WhatsApp_tip": "if you have any questions,you can click WhatsAPP to consult",
+    "WhatsApp_btn_WhastApp": "To WhatsApp",
+    "copy": "Copy",
+    "btn_telegram": "To Telegram",
+    "whats_label": "Or copy the number to your WhatsApp",
+    "email_label": "You can also contact us by email",
+    "write_now": "Write Now"
   }
 }

+ 10 - 0
src/pages/CustomerService.jsx

@@ -0,0 +1,10 @@
+import WCustomerService from "@widgets/WCustomerService";
+
+const CustomerService=({...props})=>{
+    return (
+        <>
+            <WCustomerService {...props}/>
+        </>
+    )
+}
+export default CustomerService;

+ 10 - 0
src/pages/WithdrawPassEdit.jsx

@@ -0,0 +1,10 @@
+import WDPassEdit from "@widgets/WWithdraw/PassEdit/WDPassEdit";
+
+const WithdrawPassEdit=({...props})=>{
+    return (
+        <>
+            <WDPassEdit {...props}/>
+        </>
+    )
+}
+export default WithdrawPassEdit;

+ 5 - 1
src/pages/index.jsx

@@ -12,6 +12,8 @@ const Deposit=lazy(()=>import("@pages/Deposit"));
 const PaymentOrder=lazy(()=>import("@pages/PaymentOrder"));
 const Withdraw=lazy(()=>import("@pages/Withdraw"));
 const WithdrawAccountEdit=lazy(()=>import("@pages/WithdrawAccountEdit"));
+const WithdrawPassEdit=lazy(()=>import("@pages/WithdrawPassEdit"));
+const CustomerService=lazy(()=>import("@pages/CustomerService"));
 export default {
     ModulePage:ModulePage,
     Home:Home,
@@ -23,7 +25,9 @@ export default {
     deposit:Deposit,
     paymentOrder:PaymentOrder,
     withdraw:Withdraw,
-    accountInfo:WithdrawAccountEdit
+    accountInfo:WithdrawAccountEdit,
+    wdPassEdit:WithdrawPassEdit,
+    customer:CustomerService
 }
 export const Header={
     deposit: DepositHeader,

+ 1 - 1
src/styles/_elements.scss

@@ -671,7 +671,7 @@ a {
     display: flex;
     align-items: center;
     padding: 0 .75rem;
-    height: 2.875rem;
+    min-height: 2.875rem;
     border: 1px solid transparent;
     background-color: var(--nav-item-bg);
     border-radius: var(--border-radius);

+ 31 - 1
src/styles/_utils.scss

@@ -18,12 +18,42 @@
 
 .col-1 {
     grid-template-columns: minmax(0, 1fr);
-    grid-template-rows: repeat(2, minmax(0, 1fr));
+    //grid-template-rows: repeat(2, minmax(0, 1fr));
 }
 
 .col-2 {
     grid-template-columns: repeat(2, minmax(0, 1fr));
 }
+.col-3{
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+.col-4{
+    grid-template-columns: repeat(4, minmax(0, 1fr));
+}
+.col-5{
+    grid-template-columns: repeat(5, minmax(0, 1fr));
+}
+.col-6{
+    grid-template-columns: repeat(6, minmax(0, 1fr));
+}
+.col-7{
+    grid-template-columns: repeat(7, minmax(0, 1fr));
+}
+.col-8{
+    grid-template-columns: repeat(8, minmax(0, 1fr));
+}
+.row-1{
+    grid-template-rows: repeat(1, minmax(0, 1fr));
+}
+.row-2{
+    grid-template-rows: repeat(2, minmax(0, 1fr));
+}
+.row-3{
+    grid-template-rows: repeat(3, minmax(0, 1fr));
+}
+.row-4{
+    grid-template-rows: repeat(4, minmax(0, 1fr));
+}
 
 .d-flex {
   display: flex;

+ 15 - 3
src/widgets/LoginForm/index.jsx

@@ -54,6 +54,11 @@ const LoginForm = ({close}) => {
         }
     });
     const {pathname,hash} = useLocation();
+    useEffect(()=>{
+       return ()=>{
+           global.authLockPath=null;
+       }
+    },[])
     useEffect(() => {
         if (hash===ROUTE_PATH.SIGN_IN){
             setShowType(TYPE_LOGIN);
@@ -63,12 +68,19 @@ const LoginForm = ({close}) => {
         }
     }, [pathname,hash]);
     const navigatRoute=(route)=>{
-        if (pathname.indexOf(route)==-1)navigate(route);
-        else close();
+        navigate(route,{replace:true});
     }
     const onCallback=(code)=>{
+        // global.authLockPath=null;
         if (code==200){
-            if (close)close();
+            if (global.authLockPath!=null){
+                let path=global.authLockPath;
+                global.authLockPath=null;
+                navigate(path,{replace:true});
+            }
+            else{
+                if (close)close();
+            }
         }
     }
     const onSubmitLogin=(data)=>{

+ 158 - 0
src/widgets/WCustomerService/index.jsx

@@ -0,0 +1,158 @@
+import styles from "./styles.module.scss";
+import Spring from "@components/Spring";
+import {ReactComponent as WSIcon} from '@assets/singlesvg/whatsapp.svg';
+import {ReactComponent as TGIcon} from '@assets/singlesvg/telegram.svg';
+import {ReactComponent as EamilIcon} from '@assets/singlesvg/email-open.svg';
+import SvgIcon from "@components/SvgIcon";
+import {useSelector} from "react-redux";
+import {getCustomTypeInfo, getUserInfo} from "@features/mainSlice";
+import {toast} from "react-toastify";
+import {CopyToClipboard} from "react-copy-to-clipboard";
+import {APP_CHANNEL} from "@constants/app";
+const i18n=global.i18n;
+const WCustomerService=({close})=>{
+    const whatsInfo=useSelector(getCustomTypeInfo("WhatsApp"));
+    const emailInfo=useSelector(getCustomTypeInfo("Email"));
+    const tgInfo=useSelector(getCustomTypeInfo("Telegram"));
+    const user=useSelector(getUserInfo);
+    const gameID=user?user.GameID:"";
+    const onClickWS=()=>{
+        if (whatsInfo){
+            let url=whatsInfo.StatusString+"&gameid="+gameID;
+            window.open(url,"_blank");
+        }
+    }
+    const onClickTG=()=>{
+        if (tgInfo) {
+            window.open(tgInfo.StatusString,"_blank");
+        }
+    }
+    const onClickEmail=(email)=>{
+        // cc.sys.openURL("mailto:"+BaseDefine.CS_EMAIL+"?subject=Mexico "+cc.vv.config.AppId+" gameid:"+cc.vv.globalUserInfo.getGameID()+"&body=problem:");
+        let url="mailto:"+email+"?subject=Mexico "+APP_CHANNEL.Channel+" gameid:"+gameID+"&body=problem:";
+        window.open(url,"_blank");
+    }
+    const renderTips=()=>{
+        return (
+            <div className={styles.tips}>
+                {i18n.t("customer.TipLabel")}
+            </div>
+        )
+    }
+    const renderCustomBtns=()=>{
+        return (
+            <div className={styles.block}>
+                <div className={styles.title}>
+                    {i18n.t("customer.Item_customer_Label")}
+                </div>
+                <div className={styles.line}></div>
+                <div className={styles.item}>
+                    <button className={`${styles.btn_base} ${styles.ws_btn}`} onClick={onClickWS}>
+                        <WSIcon className={styles.icon}></WSIcon>
+                        {i18n.t("customer.WhatsApp_btn_WhastApp")}
+                    </button>
+                    <button className={`${styles.btn_base} ${styles.tg_btn}`} onClick={onClickTG}>
+                        <TGIcon className={styles.icon}></TGIcon>
+                        {i18n.t("customer.btn_telegram")}
+                    </button>
+                </div>
+            </div>
+        )
+    }
+    const renderWhatsApp=()=>{
+        let id="";
+        if (whatsInfo){
+            let StatusValue=whatsInfo.StatusValue;
+            if (StatusValue)id=StatusValue.replace("ID:","");
+        }
+        return(
+            <div className={styles.block}>
+                <div className={styles.title}>
+                    {i18n.t("customer.whats_label")}
+                </div>
+                <div className={styles.line}></div>
+                <div className={styles.item}>
+                    <div className={"d-flex g-6"}>
+                        <div className={styles.title}>ID:</div>
+                        <div className={styles.text}>{id}</div>
+                    </div>
+                    <CopyToClipboard text={id} onCopy={()=>{
+                        toast.success(i18n.t("copy_success"));
+                    }}>
+                        <button className={`${styles.btn_base} ${styles.copy_btn}`}>
+                            <SvgIcon className={styles.icon} herf={"icon_Copy"}/>
+                            {i18n.t("customer.copy")}
+                        </button>
+                    </CopyToClipboard>
+                </div>
+            </div>
+        )
+    }
+    const renderEmail=()=>{
+        let email="";
+        if (emailInfo){
+            let StatusString=emailInfo.StatusString;
+            if (StatusString){
+                email=StatusString;
+            }
+        }
+        return(
+            <div className={styles.block}>
+                <div className={styles.title}>
+                    {i18n.t("customer.email_label")}
+                </div>
+                <div className={styles.line}></div>
+                <div className={styles.item}>
+                    <div className={"d-flex g-6"}>
+                        <div className={styles.title}>Email:</div>
+                        <div className={styles.text}>{email}</div>
+                    </div>
+                    <CopyToClipboard text={email} onCopy={()=>{
+                        toast.success(i18n.t("copy_success"));
+                    }}>
+                        <button className={`${styles.btn_base} ${styles.copy_btn}`}>
+                            <SvgIcon className={styles.icon} herf={"icon_Copy"}/>
+                            {i18n.t("customer.copy")}
+                        </button>
+                    </CopyToClipboard>
+                </div>
+                <div className={styles.item}>
+                    <button className={`${styles.btn_base} ${styles.write_btn}`} onClick={()=>{
+                        onClickEmail(email);
+                    }}>
+                        <EamilIcon className={styles.icon}/>
+                        {i18n.t("customer.write_now")}
+                    </button>
+                </div>
+            </div>
+        )
+    }
+    const renderReport=()=>{
+        return(
+            <div className={styles.block}>
+                <div className={styles.title}>
+                    {i18n.t("customer.Input_tip_Label")}
+                </div>
+                <div className={styles.line}></div>
+                <div className={styles.report_con}>
+                    <textarea rows={7} maxLength={300} placeholder={i18n.t("customer.input_holder")}/>
+                </div>
+                <button className={"button-green"}>
+                    {i18n.t("customer.Btn_send")}
+                </button>
+            </div>
+        )
+    }
+    return (
+        <div className={styles.container}>
+            <Spring type={"slideUp"} className={styles.content}>
+                {renderTips()}
+                {renderCustomBtns()}
+                {renderWhatsApp()}
+                {renderEmail()}
+                {renderReport()}
+            </Spring>
+        </div>
+    )
+}
+export default WCustomerService;

+ 103 - 0
src/widgets/WCustomerService/styles.module.scss

@@ -0,0 +1,103 @@
+.container{
+  width: 100%;
+  min-height: 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem 1rem;
+  background-color: var(--widget-bg);
+}
+.content{
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  & .block{
+    display: flex;
+    flex-direction: column;
+    gap: 0.75rem;
+    color: var(--text);
+    border-radius: var(--border-radius);
+    background-color: var(--card-bg);
+    padding: 1rem;
+    & .title{
+      font-size: 0.95rem;
+      color: var(--header);
+    }
+    & .text{
+      font-size: 0.95rem;
+      color: var(--coin-yellow);
+    }
+    & .item{
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      font-weight: 600;
+    }
+  }
+}
+.tips{
+  color: var(--coin-yellow);
+  opacity: 0.9;
+}
+.btn_base{
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  gap: 0.5rem;
+  //border-radius: 5rem;
+  border-radius: 0.3rem;
+  color: #fff;
+  font-weight: 700;
+  padding: 0.55rem 1.5rem;
+  & .icon{
+    width: 1.4rem;
+    height: 1.4rem;
+    fill: #fff;
+    line{
+      fill: #fff;
+    }
+  }
+}
+.ws_btn{
+  background-image: linear-gradient(135deg,  rgba(42, 184, 83, 0.7) 0%, rgb(47, 208, 94) 100%);
+  padding: 0.55rem 1.6rem;
+}
+.tg_btn{
+  background-image: linear-gradient(135deg,  rgb(66, 135, 194) 0%, rgb(85, 162, 229) 100%);
+  padding: 0.55rem 1.6rem;
+}
+.copy_btn{
+  padding: 0.5rem 1.2rem;
+  background-image: linear-gradient(135deg,  rgb(66, 135, 194) 0%, rgb(85, 162, 229) 100%);
+}
+.write_btn{
+  padding: 0.55rem 1.6rem;
+  background-color: #a9a335;
+  & .icon{
+    width: 1.5rem;
+    height: 1.5rem;
+  }
+}
+.line{
+  border-top: 1px solid var(--card-line);
+}
+.report_con{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  min-height: 10rem;
+  border-radius: var(--border-radius);
+  background-color: rgba(0, 0, 0, 0.1);
+  padding: 1rem;
+  flex-wrap: wrap;
+  textarea{
+    width: 100%;
+    color: var(--header);
+    &::placeholder {
+      font-weight: 500;
+      color: var(--header);
+      opacity: 0.6;
+    }
+  }
+}

+ 5 - 1
src/widgets/WDeposit/BR/BRDeposit.jsx

@@ -164,7 +164,11 @@ const BRDeposit=()=>{
             <button className={"button-green"} onClick={()=>{
                 let payItem=getSelectedConfig();
                 if (payItem==null)return;
-                let gear=payItem.gear!=null?JSON.parse(payItem.gear):{};
+                let gear={};
+                if (payItem.gear!=null){
+                    gear=JSON.parse(payItem.gear);
+                    gear=gear[0];
+                }
                 onGetPaymentOder({
                     price:payItem.money,
                     goodsName:"chip",

+ 2 - 1
src/widgets/WPaymentOrder/BR/BRPayOrder.jsx

@@ -12,7 +12,7 @@ import {CopyToClipboard} from "react-copy-to-clipboard";
 import {toast} from "react-toastify";
 import QRCode from 'qrcode.react';
 const i18n=global.i18n;
-const BRPayOrder=()=>{
+const BRPayOrder=({close})=>{
     const navigate=useNavigate();
     const user=useSelector(getUserInfo);
     const orderInfo=useSelector(getCurrPayOrder);
@@ -33,6 +33,7 @@ const BRPayOrder=()=>{
         if (left<=0){
             clearInterval(timer);
             timer=null;
+            if (close)close();
         }
         return timer;
     }

+ 17 - 14
src/widgets/WWithdraw/BR/BRAccountEdit.jsx

@@ -10,28 +10,31 @@ import {Controller, useForm} from "react-hook-form";
 import PasswordInput from "@components/UInput/PasswordInput";
 import classNames from "classnames";
 import {APP_GENDER} from "@constants/app";
+import {getUserInfo} from "@features/mainSlice";
 const i18n=global.i18n;
 const BRAccountEdit=()=>{
-    let info=useSelector(getWithdrawBaseInfo);
-    if (info==null)info={};
+    const user=useSelector(getUserInfo);
+    let info=useSelector(getWithdrawInfo);
+    // if (info==null)info={};
+    let dinfo=info==null?{}:info;
     const dispatch=useDispatch();
     const {register, handleSubmit, formState: {errors}, control} = useForm({
         defaultValues: {
-            account: info.AccountsBank||"",
-            userName: info.BankUserName||"",
-            bank: info.BankNO||"",
-            branceBank: info.BranchBank||"",
-            phone: info.PhoneNumber||"",
-            PAN: info.PANNumber||"",
-            IFSC:info.IFSCNumber||"",
-            email: info.EmailAddress||"",
-            PixNum: info.PixNum||"",
-            adhaar: info.AdhaarNumber||"",
-            PixType: info.PixType||"",
+            account: dinfo.AccountsBank||"",
+            userName: dinfo.BankUserName||"",
+            bank: dinfo.BankNO||"",
+            branceBank: dinfo.BranchBank||"",
+            phone: dinfo.PhoneNumber||"",
+            PAN: dinfo.PANNumber||"",
+            IFSC:dinfo.IFSCNumber||"",
+            email: dinfo.EmailAddress||"",
+            PixNum: dinfo.PixNum||"",
+            adhaar: dinfo.AdhaarNumber||"",
+            PixType: dinfo.PixType||"",
         }
     });
     useEffect(()=>{
-        // dispatch(reqWithdrawInfo());
+        dispatch(reqWithdrawInfo({UserID:user.UserID}));
     },[])
     const handleChange=(data)=>{
 

+ 23 - 0
src/widgets/WWithdraw/BR/BRWithdraw.jsx

@@ -9,6 +9,7 @@ import symbol from "@assets/symbol-defs.svg";
 import {ReactComponent as Edit} from '@assets/singlesvg/edit.svg';
 import {useNavigate} from "react-router-dom";
 import {ROUTE_PATH} from "@constants/routes";
+import WDPassBox from "@widgets/WWithdraw/PassBox/WDPassBox";
 const i18n=global.i18n;
 const BRWithdraw=()=>{
     const user=useSelector(getUserInfo);
@@ -17,6 +18,8 @@ const BRWithdraw=()=>{
     const addBtnParam = [200, 500, 1000, 2000, 5000, -1];
     const [addIndex,setAddIndex]=useState(-1);
     const [wdValue,setWdValue]=useState("");
+    const [wdPass,setWdPass]=useState("");
+    const [openPassBox,setOpenPassBox]=useState(false);
     const getShowCash=(value)=>{
         value=Number(value);
         return value/global.CASH_BASE;
@@ -166,6 +169,25 @@ const BRWithdraw=()=>{
             </div>
         )
     }
+    const renderPassBox=()=>{
+        return (
+            <WDPassBox
+                open={openPassBox}
+                title={i18n.t("withdraw.pass.pass_box_title")}
+                confirmLabel={i18n.t("withdraw.pass.btn_confirm")}
+                onClose={()=>{
+                    setOpenPassBox(false);
+                }}
+                onConfirm={(data)=>{
+                    if (data!=null){
+                        setWdPass(data);
+                    }
+                }}
+            >
+
+            </WDPassBox>
+        )
+    }
     return (
         <>
             {
@@ -175,6 +197,7 @@ const BRWithdraw=()=>{
                         {renderWithdrawValue()}
                         {renderAccount()}
                         {renderSubmit()}
+                        {renderPassBox()}
                     </Spring>
                 )
             }

+ 54 - 0
src/widgets/WWithdraw/PassBox/WDPassBox.jsx

@@ -0,0 +1,54 @@
+import Fade from "@mui/material/Fade";
+import {ClickAwayListener} from "@mui/base/ClickAwayListener";
+import Grow from "@mui/material/Grow";
+import styles from "./styles.module.scss";
+import Modal from "@mui/material/Modal";
+import MultiNumPassInput from "@components/UInput/MultiNumPassInput";
+import classNames from "classnames";
+import React, {useState} from "react";
+
+const WDPassBox=({...props})=>{
+    const {open,onClose,title,confirmLabel,onConfirm}=props;
+    const [pass,setPass]=useState("");
+    const passLen=6;
+    const onSubmit=(pass)=>{
+        if (pass.length<passLen)return;
+        if (onConfirm!=null)onConfirm(pass);
+        if (onClose)onClose();
+    }
+    return (
+        <Modal open={open} onClose={onClose} closeAfterTransition>
+            <Fade in={open} timeout={500}>
+                <div className="popup-container">
+                    <ClickAwayListener onClickAway={onClose}>
+                        <Grow in={open} timeout={500}>
+                            <div className={`popup card card-padded ${styles.container}`}>
+                                <div className={styles.content}>
+                                    <div className={styles.title}>{title}</div>
+                                    <MultiNumPassInput
+                                        focus={true}
+                                        length={passLen}
+                                        value={""}
+                                        onChange={(num,index)=>{
+                                        }}
+                                        onFinish={(numArr)=>{
+                                            let value=numArr.join("");
+                                            setPass(value);
+                                            onSubmit(value);
+                                        }}
+                                    />
+                                    <button className={"button-green"} onClick={()=>{
+                                        onSubmit(pass);
+                                    }}>
+                                        {confirmLabel}
+                                    </button>
+                                </div>
+                            </div>
+                        </Grow>
+                    </ClickAwayListener>
+                </div>
+            </Fade>
+        </Modal>
+    )
+}
+export default WDPassBox;

+ 12 - 0
src/widgets/WWithdraw/PassBox/styles.module.scss

@@ -0,0 +1,12 @@
+.container{
+  & .content{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    color: var(--header);
+    gap: 1.5rem;
+    & .title{
+      font-size: 1.1rem;
+    }
+  }
+}

+ 157 - 0
src/widgets/WWithdraw/PassEdit/WDPassEdit.jsx

@@ -0,0 +1,157 @@
+import styles from "./styles.module.scss";
+import Spring from "@components/Spring";
+import React, {useState} from "react";
+import {Controller, useForm} from "react-hook-form";
+import classNames from "classnames";
+import MultiNumPassInput from "@components/UInput/MultiNumPassInput";
+import {ReactComponent as SuccessIcon} from "@assets/singlesvg/succss.svg";
+import {useNavigate} from "react-router-dom";
+import {ROUTE_PATH} from "@constants/routes";
+import {useDispatch, useSelector} from "react-redux";
+import {getUserInfo} from "@features/mainSlice";
+import {toast} from "react-toastify";
+import {reqChangePayPass} from "@features/api";
+import {getChangePayPassStatus} from "@features/paySlice";
+import {REQ_STATUS} from "@api/config";
+import SmallLoading from "@components/SmallLoading";
+const i18n=global.i18n;
+const WDPassEdit=({close})=>{
+    const navigate=useNavigate();
+    const dispatch=useDispatch();
+    const user=useSelector(getUserInfo);
+    const status=useSelector(getChangePayPassStatus);
+    const passLen=6;
+    const {register, handleSubmit, formState: {errors}, control} = useForm({
+        defaultValues: {
+            password: "",
+            repassword:""
+        }
+    });
+    const [focusIndex,setFocusIndex]=useState(0);
+    const onSubmitPass=(data)=>{
+        if (status===REQ_STATUS.LOADING)return;
+        if (data.password!==data.repassword){
+            toast.error(i18n.t("withdraw.pass.tips.err_not_same"));
+            return;
+        }
+        dispatch(reqChangePayPass(data));
+    }
+    const renderTitle=()=>{
+        return (
+            <div className={styles.title}>
+                {i18n.t("withdraw.pass.edit_title")}
+            </div>
+        )
+    }
+    const renderPass=()=>{
+        return (
+            <Controller control={control}
+                        name="password"
+                        rules={{required: true}}
+                        render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                            <div className={styles.password}>
+                                <div>{i18n.t("withdraw.pass.new_pass")}</div>
+                                <MultiNumPassInput
+                                    focus={focusIndex===0}
+                                    length={passLen}
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    onChange={(num,index)=>{
+                                    }}
+                                    onFinish={(numArr)=>{
+                                        let value=numArr.join("");
+                                        onChange(value);
+                                        setFocusIndex(focusIndex+1);
+                                    }}
+                                    innerRef={ref}
+                                />
+                            </div>
+                        )}
+            />
+        )
+    }
+    const renderRePass=()=>{
+        return (
+            <Controller control={control}
+                        name="repassword"
+                        rules={{required: true}}
+                        render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                            <div className={styles.password}>
+                                <div>{i18n.t("withdraw.pass.re_pass")}</div>
+                                <MultiNumPassInput
+                                    focus={focusIndex===1}
+                                    length={passLen}
+                                    className={classNames({'input-control--error': error})}
+                                    value={value}
+                                    onChange={(num,index)=>{
+                                    }}
+                                    onFinish={(numArr)=>{
+                                        let value=numArr.join("");
+                                        onChange(value);
+                                        setFocusIndex(focusIndex+1);
+                                    }}
+                                    innerRef={ref}
+                                />
+                            </div>
+                        )}
+            />
+        )
+    }
+    const renderSubmit=()=>{
+        return (
+            <div className={styles.btn_con}>
+                <button className={"button-green"}>
+                    {status===REQ_STATUS.LOADING?(<SmallLoading fill={"#fff"}/>):(i18n.t("withdraw.pass.btn_submit"))}
+                </button>
+            </div>
+        )
+    }
+    const renderForm=()=>{
+        return (
+            <form className={styles.form} autoComplete="off" onSubmit={handleSubmit((data) => {
+                onSubmitPass(data);
+            })}>
+                {renderTitle()}
+                {renderPass()}
+                {renderRePass()}
+                {renderSubmit()}
+            </form>
+        )
+    }
+    const renderSuccess=()=>{
+        return (
+            <div className={styles.success}>
+                <SuccessIcon className={styles.logo}/>
+                <div className={styles.title}>{i18n.t("withdraw.pass.tips.success")}</div>
+                <div>{i18n.t("withdraw.pass.tips.des")}</div>
+                <div className={styles.btns_con}>
+                    <button className={"button-gray"} onClick={()=>{
+                        if (close)close()
+                    }}>
+                        {i18n.t("withdraw.pass.tips.btn_back")}
+                    </button>
+                    <button className={"button-green"} onClick={()=>{
+                        navigate(ROUTE_PATH.SAQUE,{replace:true})
+                    }}>
+                        {i18n.t("withdraw.pass.tips.btn_withdraw")}
+                    </button>
+                </div>
+            </div>
+        )
+    }
+    const renderContent=()=>{
+        let InsurePass=Number(user.InsurePass);
+        if (InsurePass===1)return renderSuccess();
+        else return renderForm();
+    }
+    return (
+        <>
+            <div className={styles.container}>
+                <Spring type="slideUp" className={styles.content}>
+                    {renderContent()}
+                </Spring>
+            </div>
+        </>
+    )
+}
+export default WDPassEdit;

+ 64 - 0
src/widgets/WWithdraw/PassEdit/styles.module.scss

@@ -0,0 +1,64 @@
+.container{
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem;
+  width: 100%;
+  min-height: 100%;
+  //gap: 1rem;
+  background-color: var(--widget-bg);
+}
+.content{
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  width: 100%;
+  gap: 1rem;
+}
+.form{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  gap: 1rem;
+  & .title{
+    font-size: 1rem;
+    color: var(--header);
+  }
+  & .password{
+    display: flex;
+    flex-direction: column;
+    //font-size: 0.8rem;
+    gap: 0.5rem;
+    color: var(--header);
+  }
+  & .btn_con{
+    margin-top: 1rem;
+  }
+}
+.success{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-top: 3.8rem;
+  width: 100%;
+  gap: 1rem;
+  font-size: 0.9rem;
+  color: var(--header);
+  text-align: center;
+  & .title{
+    font-size: 1.1rem;
+  }
+  & .logo{
+    //width: 3rem;
+    //height: 3rem;
+  }
+  & .btns_con{
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+    gap: 1.5rem;
+    margin-top: 2rem;
+    width: 100%;
+  }
+}
+

+ 47 - 0
src/widgets/WWithdraw/PassPrompt/WDPassPrompt.jsx

@@ -0,0 +1,47 @@
+import Fade from "@mui/material/Fade";
+import {ClickAwayListener} from "@mui/base/ClickAwayListener";
+import Grow from "@mui/material/Grow";
+import Modal from "@mui/material/Modal";
+import {useThemeProvider} from "@contexts/themeContext";
+import styles from "./styles.module.scss";
+import {ReactComponent as Imgbg} from '@assets/wdpop/copy-url-bg.svg';
+import bannerImg from '@assets/wdpop/popup_icon001.png';
+import {useNavigate} from "react-router";
+import {ROUTE_PATH} from "@constants/routes";
+const i18n=global.i18n;
+const WDPassPrompt=()=>{
+    const {isMobile,isShowPassPrompt,setIsShowPassPrompt} = useThemeProvider();
+    const navigate=useNavigate();
+    const onClose=()=>{
+        setIsShowPassPrompt(false);
+    }
+    const onConfirm=()=>{
+        setIsShowPassPrompt(false);
+        navigate(ROUTE_PATH.CHANGE_PAY_PASS);
+    }
+    return (
+        <Modal open={isShowPassPrompt} onClose={onClose} closeAfterTransition>
+            <Fade in={isShowPassPrompt} timeout={500}>
+                <div className="popup-container">
+                    <ClickAwayListener onClickAway={onClose}>
+                        <Grow in={isShowPassPrompt} timeout={500}>
+                            <div className={`${styles.container}`}>
+                                <div className={styles.banner}>
+                                    <Imgbg/>
+                                    <img src={bannerImg}/>
+                                </div>
+                                <div className={styles.content}>
+                                    {i18n.t("withdraw.pass.prompt")}
+                                </div>
+                                <button className={styles.btn} onClick={onConfirm}>
+                                    {i18n.t("withdraw.pass.btn_confirm")}
+                                </button>
+                            </div>
+                        </Grow>
+                    </ClickAwayListener>
+                </div>
+            </Fade>
+        </Modal>
+    )
+}
+export default WDPassPrompt;

+ 33 - 0
src/widgets/WWithdraw/PassPrompt/styles.module.scss

@@ -0,0 +1,33 @@
+.container{
+  display: flex;
+  flex-direction: column;
+  background-color: #fff;
+  border-radius: 1.25rem;
+  position: relative;
+  align-items: center;
+  width: 95%;
+  & .banner{
+    position: relative;
+    width: 100%;
+    img{
+      width: 100%;
+      height: auto;
+      position: absolute;
+      bottom: 0.5rem;
+    }
+  }
+  & .content{
+    padding: 1.5rem;
+    font-size: 0.95rem;
+    color: rgba(0, 0, 0, 0.7);
+    text-align: center;
+  }
+  & .btn{
+    margin-bottom: 1.5rem;
+    padding: 0.6rem 2.2rem;
+    min-height: 2.1875rem;
+    background-color: #FBA531;
+    border-radius: var(--border-radius);
+    color: var(--header);
+  }
+}