|
@@ -19,15 +19,16 @@ import PhoneInput from "@components/UInput/PhoneInput";
|
|
|
import {animated,useSpring} from "@react-spring/web";
|
|
import {animated,useSpring} from "@react-spring/web";
|
|
|
import {toast} from 'react-toastify';
|
|
import {toast} from 'react-toastify';
|
|
|
import {useDispatch, useSelector} from "react-redux";
|
|
import {useDispatch, useSelector} from "react-redux";
|
|
|
-import {getLoginStatus, getRegStatus} from "@features/mainSlice";
|
|
|
|
|
|
|
+import {getLoginStatus, getRegStatus, getSendCodeStatus, getSendCodeTS, getSMSLoginStatus} from "@features/mainSlice";
|
|
|
import {useLocation} from "react-router";
|
|
import {useLocation} from "react-router";
|
|
|
import {useEffect} from 'react';
|
|
import {useEffect} from 'react';
|
|
|
import SmallLoading from "@components/SmallLoading";
|
|
import SmallLoading from "@components/SmallLoading";
|
|
|
import {REQ_STATUS} from "@api/config";
|
|
import {REQ_STATUS} from "@api/config";
|
|
|
-import {reqLogin, reqRegister} from "@features/api";
|
|
|
|
|
|
|
+import {reqLogin, reqRegister, reqSendCode, reqSMSLogin} from "@features/api";
|
|
|
import {ROUTE_PATH} from "@constants/routes";
|
|
import {ROUTE_PATH} from "@constants/routes";
|
|
|
import {APP_THEME} from "@constants/app";
|
|
import {APP_THEME} from "@constants/app";
|
|
|
import {validateCountryPhone} from "@utils/helpers";
|
|
import {validateCountryPhone} from "@utils/helpers";
|
|
|
|
|
+import {CircularProgress} from "@mui/material";
|
|
|
|
|
|
|
|
const i18n=global.i18n;
|
|
const i18n=global.i18n;
|
|
|
const TYPE_LOGIN="login";
|
|
const TYPE_LOGIN="login";
|
|
@@ -35,6 +36,9 @@ const TYPE_REGISTER="register";
|
|
|
|
|
|
|
|
const LOGIN_TYPE_PASS=0;
|
|
const LOGIN_TYPE_PASS=0;
|
|
|
const LOGIN_TYPE_OTP=1;
|
|
const LOGIN_TYPE_OTP=1;
|
|
|
|
|
+const objInfo={
|
|
|
|
|
+ cdTimer:null
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
const LoginForm = ({close}) => {
|
|
const LoginForm = ({close}) => {
|
|
|
const {theme,isMobile} = useThemeProvider();
|
|
const {theme,isMobile} = useThemeProvider();
|
|
@@ -55,13 +59,51 @@ const LoginForm = ({close}) => {
|
|
|
email:"",
|
|
email:"",
|
|
|
repassword:"",
|
|
repassword:"",
|
|
|
lang:"",
|
|
lang:"",
|
|
|
- code:""
|
|
|
|
|
|
|
+ code:"",
|
|
|
|
|
+ phone:""
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
const {pathname,hash} = useLocation();
|
|
const {pathname,hash} = useLocation();
|
|
|
|
|
+ const otpTimeStamp=useSelector(getSendCodeTS);
|
|
|
|
|
+ const [otpCD,setOtpCD]=useState(-1);
|
|
|
|
|
+ const otpStatus=useSelector(getSendCodeStatus);
|
|
|
|
|
+ const smsLoginStatus=useSelector(getSMSLoginStatus);
|
|
|
|
|
+ const onSendCode=(e)=>{
|
|
|
|
|
+ if (otpCD>0)return;
|
|
|
|
|
+ if (otpStatus===REQ_STATUS.LOADING)return;
|
|
|
|
|
+ let phone=control._formValues.phone;
|
|
|
|
|
+ if (phone==null||phone==="")return;
|
|
|
|
|
+ let validate=validatePhone(phone);
|
|
|
|
|
+ if (!validate){
|
|
|
|
|
+ control.setError("phone",true)
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ let params={phone:phone};
|
|
|
|
|
+ dispatch(reqSendCode(params));
|
|
|
|
|
+ }
|
|
|
|
|
+ const getLeftCD=()=>{
|
|
|
|
|
+ let now=Date.now();
|
|
|
|
|
+ let delta=now-otpTimeStamp;
|
|
|
|
|
+ delta=Math.floor(delta/1000);
|
|
|
|
|
+ delta=60-delta;
|
|
|
|
|
+ if (delta<0)return -1;
|
|
|
|
|
+ else return delta;
|
|
|
|
|
+ }
|
|
|
|
|
+ const clearTimer=()=>{
|
|
|
|
|
+ if (objInfo.cdTimer!=null){
|
|
|
|
|
+ clearInterval(objInfo.cdTimer);
|
|
|
|
|
+ objInfo.cdTimer=null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ const onSubmitOTPLogin=(data)=>{
|
|
|
|
|
+ if (smsLoginStatus===REQ_STATUS.LOADING)return;
|
|
|
|
|
+ data.callback=onCallback;
|
|
|
|
|
+ dispatch(reqSMSLogin(data));
|
|
|
|
|
+ }
|
|
|
useEffect(()=>{
|
|
useEffect(()=>{
|
|
|
return ()=>{
|
|
return ()=>{
|
|
|
global.authLockPath=null;
|
|
global.authLockPath=null;
|
|
|
|
|
+ clearTimer();
|
|
|
}
|
|
}
|
|
|
},[])
|
|
},[])
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
@@ -72,6 +114,20 @@ const LoginForm = ({close}) => {
|
|
|
setShowType(TYPE_REGISTER);
|
|
setShowType(TYPE_REGISTER);
|
|
|
}
|
|
}
|
|
|
}, [pathname,hash]);
|
|
}, [pathname,hash]);
|
|
|
|
|
+ useEffect(()=>{
|
|
|
|
|
+ let left=getLeftCD();
|
|
|
|
|
+ setOtpCD(left);
|
|
|
|
|
+ clearTimer();
|
|
|
|
|
+ if (left>0){
|
|
|
|
|
+ objInfo.cdTimer=setInterval(()=>{
|
|
|
|
|
+ left=getLeftCD();
|
|
|
|
|
+ setOtpCD(left);
|
|
|
|
|
+ if (left<0){
|
|
|
|
|
+ clearTimer();
|
|
|
|
|
+ }
|
|
|
|
|
+ },1000)
|
|
|
|
|
+ }
|
|
|
|
|
+ },[otpTimeStamp])
|
|
|
const navigatRoute=(route)=>{
|
|
const navigatRoute=(route)=>{
|
|
|
navigate(route,{replace:true});
|
|
navigate(route,{replace:true});
|
|
|
}
|
|
}
|
|
@@ -89,11 +145,13 @@ const LoginForm = ({close}) => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
const onSubmitLogin=(data)=>{
|
|
const onSubmitLogin=(data)=>{
|
|
|
|
|
+ if (loginStatus===REQ_STATUS.LOADING)return;
|
|
|
data.country=country;
|
|
data.country=country;
|
|
|
data.callback=onCallback;
|
|
data.callback=onCallback;
|
|
|
dispatch(reqLogin(data));
|
|
dispatch(reqLogin(data));
|
|
|
}
|
|
}
|
|
|
const onSubmitReg=(data)=>{
|
|
const onSubmitReg=(data)=>{
|
|
|
|
|
+ if (regStatus===REQ_STATUS.LOADING)return;
|
|
|
data.country=country;
|
|
data.country=country;
|
|
|
data.callback=onCallback;
|
|
data.callback=onCallback;
|
|
|
dispatch(reqRegister(data));
|
|
dispatch(reqRegister(data));
|
|
@@ -180,10 +238,10 @@ const LoginForm = ({close}) => {
|
|
|
const renderOTPLogin=()=>{
|
|
const renderOTPLogin=()=>{
|
|
|
return (
|
|
return (
|
|
|
<form autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
|
|
<form autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
|
|
|
- onSubmitLogin(data);
|
|
|
|
|
|
|
+ onSubmitOTPLogin(data);
|
|
|
})}>
|
|
})}>
|
|
|
<Controller control={control}
|
|
<Controller control={control}
|
|
|
- name="account"
|
|
|
|
|
|
|
+ name="phone"
|
|
|
rules={{required: true}}
|
|
rules={{required: true}}
|
|
|
render={({field: {ref, onChange, value}, fieldState: {error}}) => {
|
|
render={({field: {ref, onChange, value}, fieldState: {error}}) => {
|
|
|
let message = error ? i18n.t("form_errors.phone_" + country) : "";
|
|
let message = error ? i18n.t("form_errors.phone_" + country) : "";
|
|
@@ -214,7 +272,20 @@ const LoginForm = ({close}) => {
|
|
|
onChange={e => onChange(e.target.value)}
|
|
onChange={e => onChange(e.target.value)}
|
|
|
placeholder={i18n.t('login.otp_ph')}
|
|
placeholder={i18n.t('login.otp_ph')}
|
|
|
/>
|
|
/>
|
|
|
- <button type={"button"} className={styles.otp_btn}>OTP</button>
|
|
|
|
|
|
|
+ <button type={"button"}
|
|
|
|
|
+ className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
|
|
|
|
|
+ onClick={onSendCode}>
|
|
|
|
|
+ {
|
|
|
|
|
+ otpStatus === REQ_STATUS.LOADING ? (
|
|
|
|
|
+ <CircularProgress color="success" size={22} thickness={5}/>) : (
|
|
|
|
|
+ <>
|
|
|
|
|
+ {
|
|
|
|
|
+ otpCD <= 0 ? "OTP" : otpCD + "S"
|
|
|
|
|
+ }
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ </button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
)
|
|
)
|
|
@@ -222,7 +293,7 @@ const LoginForm = ({close}) => {
|
|
|
/>
|
|
/>
|
|
|
<button className={"button-green"}>
|
|
<button className={"button-green"}>
|
|
|
{
|
|
{
|
|
|
- loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
|
|
|
|
|
|
|
+ smsLoginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
|
|
|
}
|
|
}
|
|
|
</button>
|
|
</button>
|
|
|
{renderGuestLogin()}
|
|
{renderGuestLogin()}
|