index.jsx 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. // components
  2. import PasswordInput from '@components/UInput/PasswordInput';
  3. import BasicCheckbox from '@ui/BasicCheckbox';
  4. import ResetPasswordPopup from '@components/ResetPasswordPopup';
  5. // hooks
  6. import {useForm, Controller} from 'react-hook-form';
  7. import {useNavigate} from 'react-router-dom';
  8. import React, {useState} from 'react';
  9. import styles from './styles.module.scss';
  10. import logo_dark from '@assets/logo/logo.png';
  11. import logo_light from '@assets/logo/logo_w.png';
  12. // utils
  13. import classNames from 'classnames';
  14. import {useThemeProvider} from "@contexts/themeContext";
  15. import Spring from "@components/Spring";
  16. import PhoneInput from "@components/UInput/PhoneInput";
  17. import {animated,useSpring} from "@react-spring/web";
  18. import {toast} from 'react-toastify';
  19. import {useDispatch, useSelector} from "react-redux";
  20. import {
  21. getAccountLogin,
  22. getChangePassStatus,
  23. getLoginStatus,
  24. getRegStatus,
  25. getSendCodeStatus,
  26. getSendCodeTS,
  27. getSMSLoginStatus
  28. } from "@features/mainSlice";
  29. import {useLocation} from "react-router";
  30. import {useEffect} from 'react';
  31. import SmallLoading from "@components/SmallLoading";
  32. import {REQ_STATUS} from "@api/config";
  33. import {reqForgetPass, reqLogin, reqRegister, reqSendCode, reqSMSLogin} from "@features/api";
  34. import {ROUTE_PATH} from "@constants/routes";
  35. import {APP_LOGIN_TYPE, APP_THEME} from "@constants/app";
  36. import {validateCountryPhone} from "@utils/helpers";
  37. import {CircularProgress} from "@mui/material";
  38. import area from "@db/area";
  39. import SvgIcon from "@components/SvgIcon";
  40. const i18n=global.i18n;
  41. const TYPE_LOGIN="login";
  42. const TYPE_REGISTER="register";
  43. const TYPE_FORGET_PASS="forgetPassword";
  44. const LOGIN_TYPE_PASS=0;
  45. const LOGIN_TYPE_OTP=1;
  46. const LOGIN_TYPE_ACOUNT=2;
  47. const REG_TYPE_PHONE=0;
  48. const REG_TYPE_ACCOUNT=1;
  49. const objInfo={
  50. cdTimer:null,
  51. inSubmit:false
  52. }
  53. const LoginForm = ({close}) => {
  54. const {theme,isMobile} = useThemeProvider();
  55. const [showType,setShowType]=useState(TYPE_LOGIN);
  56. const [open, setOpen] = useState(false);
  57. const [country, setCountry] = useState("55");
  58. const logourl=(theme===APP_THEME.DARK?logo_dark:logo_light);
  59. const loginStatus=useSelector(getLoginStatus);
  60. const regStatus=useSelector(getRegStatus);
  61. const forgetStatus=useSelector(getChangePassStatus);
  62. const dispatch = useDispatch();
  63. const navigate=useNavigate();
  64. const [loginType,setLoginType]=useState(LOGIN_TYPE_PASS);
  65. const {register, handleSubmit, formState: {errors}, control} = useForm({
  66. defaultValues: {
  67. // country:'55',
  68. account: '',
  69. password: '',
  70. email:"",
  71. repassword:"",
  72. lang:"",
  73. code:"",
  74. phone:"",
  75. newpassword:"",
  76. renewpassword:"",
  77. acc_account:"",
  78. acc_password:"",
  79. acc_repassword:""
  80. }
  81. });
  82. const {pathname,hash} = useLocation();
  83. const otpTimeStamp=useSelector(getSendCodeTS);
  84. const [otpCD,setOtpCD]=useState(-1);
  85. const otpStatus=useSelector(getSendCodeStatus);
  86. const smsLoginStatus=useSelector(getSMSLoginStatus);
  87. const isAccountLogin=useSelector(getAccountLogin);
  88. const [regType,setRegType]=useState(REG_TYPE_PHONE);
  89. const onSendCode=(e)=>{
  90. if (otpCD>0)return;
  91. if (otpStatus===REQ_STATUS.LOADING)return;
  92. let phone=control._formValues.phone;
  93. if (phone==null||phone==="")return;
  94. let validate=validatePhone(phone);
  95. if (!validate){
  96. control.setError("phone",true)
  97. return;
  98. }
  99. let params={phone:phone};
  100. dispatch(reqSendCode(params));
  101. }
  102. const getLeftCD=()=>{
  103. let now=Date.now();
  104. let delta=now-otpTimeStamp;
  105. delta=Math.floor(delta/1000);
  106. delta=60-delta;
  107. if (delta<0)return -1;
  108. else return delta;
  109. }
  110. const clearTimer=()=>{
  111. if (objInfo.cdTimer!=null){
  112. clearInterval(objInfo.cdTimer);
  113. objInfo.cdTimer=null;
  114. }
  115. }
  116. const onSubmitOTPLogin=(data)=>{
  117. if (smsLoginStatus===REQ_STATUS.LOADING)return;
  118. data.callback=onCallback;
  119. dispatch(reqSMSLogin(data));
  120. }
  121. useEffect(()=>{
  122. return ()=>{
  123. global.authLockPath=null;
  124. clearTimer();
  125. objInfo.inSubmit=false;
  126. }
  127. },[])
  128. useEffect(() => {
  129. if (hash===ROUTE_PATH.SIGN_IN){
  130. setShowType(TYPE_LOGIN);
  131. }
  132. else if (hash===ROUTE_PATH.SIGN_UP){
  133. setShowType(TYPE_REGISTER);
  134. }
  135. }, [pathname,hash]);
  136. useEffect(()=>{
  137. let left=getLeftCD();
  138. setOtpCD(left);
  139. clearTimer();
  140. if (left>0){
  141. objInfo.cdTimer=setInterval(()=>{
  142. left=getLeftCD();
  143. setOtpCD(left);
  144. if (left<0){
  145. clearTimer();
  146. }
  147. },1000)
  148. }
  149. },[otpTimeStamp])
  150. const navigatRoute=(route)=>{
  151. navigate(route,{replace:true});
  152. }
  153. const onCallback=(code)=>{
  154. // global.authLockPath=null;
  155. objInfo.inSubmit=false;
  156. if (code==200){
  157. if (global.authLockPath!=null){
  158. let path=global.authLockPath;
  159. global.authLockPath=null;
  160. navigate(path,{replace:true});
  161. }
  162. else{
  163. if (close)close();
  164. }
  165. }
  166. }
  167. const onSubmitLogin=(data)=>{
  168. if (loginStatus===REQ_STATUS.LOADING)return;
  169. if (objInfo.inSubmit)return;
  170. data.country=country;
  171. data.callback=onCallback;
  172. dispatch(reqLogin(data));
  173. objInfo.inSubmit=true;
  174. }
  175. const onSubmitReg=(data)=>{
  176. if (regStatus===REQ_STATUS.LOADING)return;
  177. if (objInfo.inSubmit)return;
  178. data.country=country;
  179. data.callback=onCallback;
  180. dispatch(reqRegister(data));
  181. objInfo.inSubmit=true;
  182. }
  183. const onSubmitForget=(data)=>{
  184. if (forgetStatus===REQ_STATUS.LOADING)return;
  185. if (objInfo.inSubmit)return;
  186. data.country=country;
  187. data.callback=onCallback;
  188. dispatch(reqForgetPass(data));
  189. objInfo.inSubmit=true;
  190. }
  191. const onSubmitAccountLogin=(data)=>{
  192. if (loginStatus===REQ_STATUS.LOADING)return;
  193. if (objInfo.inSubmit)return;
  194. // acc_account:"",
  195. // acc_password:"",
  196. // acc_repassword:""
  197. //data.type=APP_LOGIN_TYPE.ID;
  198. let ndata={
  199. account:data.acc_account,
  200. password:data.acc_password,
  201. type:APP_LOGIN_TYPE.ID
  202. }
  203. ndata.callback=onCallback;
  204. dispatch(reqLogin(ndata));
  205. objInfo.inSubmit=true;
  206. }
  207. const onSubmitAccountReg=(data)=>{
  208. if (regStatus===REQ_STATUS.LOADING)return;
  209. if (objInfo.inSubmit)return;
  210. let ndata={
  211. account:data.acc_account,
  212. password:data.acc_password,
  213. repassword:data.acc_repassword,
  214. type:APP_LOGIN_TYPE.ID
  215. }
  216. ndata.callback=onCallback;
  217. dispatch(reqRegister(ndata));
  218. objInfo.inSubmit=true;
  219. }
  220. const validatePhone=(value)=>{
  221. return validateCountryPhone(country,value);
  222. }
  223. const getAreaItem=()=>{
  224. let areaID=global.getLocalAreaID();
  225. let item=null;
  226. for (let i = 0; i < area.length; i++) {
  227. let aitem=area[i];
  228. if (aitem.id===areaID){
  229. item=aitem;
  230. break;
  231. }
  232. }
  233. return item;
  234. }
  235. const renderLoading=()=>{
  236. return (<SmallLoading fill={"#fff"}/>)
  237. }
  238. const renderLogo=()=>{
  239. return (
  240. <div className={styles.l_logo}>
  241. <img className={styles.logo_img} src={logourl}/>
  242. </div>
  243. )
  244. }
  245. const renderAreaSelect=()=>{
  246. let item=getAreaItem();
  247. if (item==null)return (<></>);
  248. return (
  249. <button type={"button"} className={styles.area_btn} onClick={()=>{
  250. global.showAreaSelect();
  251. }}>
  252. <span>{i18n.t(item.name)}</span>
  253. <SvgIcon className={styles.icon} herf={"icon_Arrow"}></SvgIcon>
  254. </button>
  255. )
  256. }
  257. const renderLoginToReg=()=>{
  258. return (
  259. <div className={"d-flex flex-row align-items-center justify-content-between"}>
  260. <div className={styles.l_reg_new}>
  261. <div>{i18n.t("login.reg_new_des")}</div>
  262. <div className={styles.reg_btn} onClick={() => {
  263. // setShowType(TYPE_REGISTER);
  264. if (isMobile()) navigatRoute(ROUTE_PATH.SIGN_UP)
  265. else setShowType(TYPE_REGISTER);
  266. }}>
  267. {i18n.t("sign_up")}
  268. </div>
  269. </div>
  270. {renderAreaSelect()}
  271. </div>
  272. )
  273. }
  274. const renderGuestLogin = () => {
  275. // return (
  276. // <button type={"button"} className={styles.guest_btn}>
  277. // {i18n.t("login.guest_login")}
  278. // </button>
  279. // )
  280. }
  281. //login__________
  282. const renderPassLogin = () => {
  283. return (
  284. <form key={"pass"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  285. onSubmitLogin(data);
  286. })}>
  287. <Controller control={control}
  288. name="account"
  289. rules={{required: true}}
  290. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  291. let message = error ? i18n.t("form_errors.phone_" + country) : "";
  292. return (<PhoneInput
  293. key={"account"}
  294. className={classNames({'input-control--error': error})}
  295. value={value}
  296. message={message}
  297. onChange={e => onChange(e.target.value)}
  298. onChangeCountry={(country) => {
  299. setCountry(country);
  300. }}
  301. placeholder={i18n.t('login.phone_ph')}
  302. innerRef={ref}/>)
  303. }}
  304. />
  305. <Controller control={control}
  306. name="password"
  307. rules={{required: true, minLength: 6}}
  308. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  309. <PasswordInput
  310. className={classNames({'input-control--error': error})}
  311. value={value}
  312. message={error ? i18n.t("form_errors.pass") : ''}
  313. onChange={e => onChange(e.target.value)}
  314. placeholder={i18n.t('login.login_pwd')}
  315. innerRef={ref}/>
  316. )}
  317. />
  318. <div className={styles.l_forgot}>
  319. <button type={"button"} className={styles.forgot_btn} onClick={()=>{
  320. setShowType(TYPE_FORGET_PASS);
  321. }}>
  322. {i18n.t("login.forgot")}
  323. </button>
  324. </div>
  325. <button className={"button-green"}>
  326. {
  327. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  328. }
  329. </button>
  330. {renderGuestLogin()}
  331. {renderLoginToReg()}
  332. </form>
  333. )
  334. }
  335. const renderOTPLogin=()=>{
  336. return (
  337. <form key={"otp"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  338. onSubmitOTPLogin(data);
  339. })}>
  340. <Controller control={control}
  341. name="phone"
  342. rules={{required: true}}
  343. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  344. let message = error ? i18n.t("form_errors.phone_" + country) : "";
  345. return (<PhoneInput
  346. key={"phone"}
  347. className={classNames({'input-control--error': error})}
  348. value={value}
  349. message={message}
  350. onChange={e => onChange(e.target.value)}
  351. onChangeCountry={(country) => {
  352. setCountry(country);
  353. }}
  354. placeholder={i18n.t('login.phone_ph')}
  355. innerRef={ref}/>)
  356. }}
  357. />
  358. <Controller control={control}
  359. name="code"
  360. rules={{required: true}}
  361. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  362. return (
  363. <div className={`d-flex flex-column g-6`}>
  364. <div
  365. className={`input-control ${classNames({'input-control--error': error})}`}>
  366. <input
  367. type={'text'}
  368. autoComplete="off"
  369. ref={ref}
  370. onChange={e => onChange(e.target.value)}
  371. placeholder={i18n.t('login.otp_ph')}
  372. />
  373. <button type={"button"}
  374. className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
  375. onClick={onSendCode}>
  376. {
  377. otpStatus === REQ_STATUS.LOADING ? (
  378. <CircularProgress color="success" size={22} thickness={5}/>) : (
  379. <>
  380. {
  381. otpCD <= 0 ? i18n.t('login.btn_otp') : otpCD + "S"
  382. }
  383. </>
  384. )
  385. }
  386. </button>
  387. </div>
  388. </div>
  389. )
  390. }}
  391. />
  392. <button className={"button-green"}>
  393. {
  394. smsLoginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  395. }
  396. </button>
  397. {renderGuestLogin()}
  398. {renderLoginToReg()}
  399. </form>
  400. )
  401. }
  402. const renderAccountLogin=()=>{
  403. return (
  404. <form key={"account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  405. onSubmitAccountLogin(data);
  406. })}>
  407. <Controller control={control}
  408. name="acc_account"
  409. rules={{required: true, minLength: 6}}
  410. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  411. return (
  412. <div className={`d-flex flex-column g-6`}>
  413. <div
  414. className={`input-control ${classNames({'input-control--error': error})}`}>
  415. <input
  416. type={'text'}
  417. autoComplete="off"
  418. ref={ref}
  419. onChange={e => onChange(e.target.value)}
  420. placeholder={i18n.t('login.account_ph')}
  421. />
  422. </div>
  423. {
  424. error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
  425. }
  426. </div>
  427. )
  428. }}
  429. />
  430. <Controller control={control}
  431. name="acc_password"
  432. rules={{required: true, minLength: 6}}
  433. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  434. <PasswordInput
  435. className={classNames({'input-control--error': error})}
  436. value={value}
  437. message={error ? i18n.t("form_errors.pass") : ''}
  438. onChange={e => onChange(e.target.value)}
  439. placeholder={i18n.t('login.login_pwd')}
  440. innerRef={ref}/>
  441. )}
  442. />
  443. <button className={"button-green"}>
  444. {
  445. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  446. }
  447. </button>
  448. {renderGuestLogin()}
  449. {renderLoginToReg()}
  450. </form>
  451. )
  452. }
  453. const renderLoginType = () => {
  454. if (loginType === LOGIN_TYPE_PASS) {
  455. return renderPassLogin();
  456. } else if (loginType === LOGIN_TYPE_OTP){
  457. return renderOTPLogin();
  458. } else if (loginType === LOGIN_TYPE_ACOUNT){
  459. return renderAccountLogin();
  460. }
  461. return (<></>);
  462. }
  463. const renderLoginForm = () => {
  464. return (
  465. <Spring type="slideUp">
  466. <div className={styles.l_title}>{i18n.t("login.login_title")}</div>
  467. <div className={styles.l_type_tabs}>
  468. <button className={`${styles.l_type_btn} ${loginType === LOGIN_TYPE_PASS ? styles.active : ''}`}
  469. onClick={() => {
  470. setLoginType(LOGIN_TYPE_PASS)
  471. }}>
  472. <span>{i18n.t("login.login_type.password")}</span>
  473. </button>
  474. <button className={`${styles.l_type_btn} ${loginType === LOGIN_TYPE_OTP ? styles.active : ''}`}
  475. onClick={() => {
  476. setLoginType(LOGIN_TYPE_OTP)
  477. }}>
  478. <span>{i18n.t("login.login_type.otp")}</span>
  479. </button>
  480. {
  481. isAccountLogin?(
  482. <button className={`${styles.l_type_btn} ${loginType === LOGIN_TYPE_ACOUNT ? styles.active : ''}`}
  483. onClick={() => {
  484. setLoginType(LOGIN_TYPE_ACOUNT)
  485. }}>
  486. <span>{i18n.t("login.login_type.account")}</span>
  487. </button>
  488. ):(<></>)
  489. }
  490. </div>
  491. {
  492. // loginType===LOGIN_TYPE_PASS?renderPassLogin():renderOTPLogin()
  493. renderLoginType()
  494. }
  495. </Spring>
  496. )
  497. }
  498. //login__________
  499. //register_______________
  500. const renderRegToLogin=()=>{
  501. return (
  502. <div className={"d-flex flex-row align-items-center justify-content-between"}>
  503. <div className={styles.l_reg_new}>
  504. <div>{i18n.t("login.login_des")}</div>
  505. <div className={styles.reg_btn} onClick={() => {
  506. // setShowType(TYPE_LOGIN);
  507. if (isMobile()) navigatRoute(ROUTE_PATH.SIGN_IN)
  508. else setShowType(TYPE_LOGIN);
  509. }}>
  510. {i18n.t("login.sign_in_btn")}
  511. </div>
  512. </div>
  513. {renderAreaSelect()}
  514. </div>
  515. )
  516. }
  517. const renderRegPhone = () => {
  518. return (
  519. <form key={"reg_phone"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  520. onSubmitReg(data);
  521. })}>
  522. <Controller control={control}
  523. name="account"
  524. rules={{required: true, validate: validatePhone}}
  525. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  526. let message = error ? i18n.t("form_errors.phone_" + country) : "";
  527. return (<PhoneInput
  528. className={classNames({'input-control--error': error})}
  529. value={value}
  530. message={message}
  531. onChange={e => onChange(e.target.value)}
  532. onChangeCountry={(country) => {
  533. setCountry(country);
  534. }}
  535. placeholder={i18n.t('login.phone_ph')}
  536. innerRef={ref}/>)
  537. }}
  538. />
  539. <Controller control={control}
  540. name="password"
  541. rules={{required: true, minLength: 6}}
  542. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  543. <PasswordInput
  544. className={classNames({'input-control--error': error})}
  545. value={value}
  546. message={error ? i18n.t("form_errors.pass") : ''}
  547. onChange={e => onChange(e.target.value)}
  548. placeholder={i18n.t('login.login_pwd')}
  549. innerRef={ref}/>
  550. )}
  551. />
  552. <Controller control={control}
  553. name="repassword"
  554. rules={{required: true, minLength: 6}}
  555. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  556. <PasswordInput
  557. className={classNames({'input-control--error': error})}
  558. value={value}
  559. message={error ? i18n.t("form_errors.pass") : ''}
  560. onChange={e => onChange(e.target.value)}
  561. placeholder={i18n.t('login.re_pwd')}
  562. innerRef={ref}/>
  563. )}
  564. />
  565. <button className={"button-green"}>
  566. {
  567. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  568. }
  569. </button>
  570. {renderRegToLogin()}
  571. </form>
  572. )
  573. }
  574. const renderRegAccount=()=>{
  575. return (
  576. <form key={"reg_account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  577. // onSubmitReg(data);
  578. onSubmitAccountReg(data);
  579. })}>
  580. <Controller control={control}
  581. name="acc_account"
  582. rules={{required: true, minLength: 6}}
  583. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  584. return (
  585. <div className={`d-flex flex-column g-6`}>
  586. <div
  587. className={`input-control ${classNames({'input-control--error': error})}`}>
  588. <input
  589. type={'text'}
  590. autoComplete="off"
  591. ref={ref}
  592. onChange={e => onChange(e.target.value)}
  593. placeholder={i18n.t('login.account_ph')}
  594. />
  595. </div>
  596. {
  597. error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
  598. }
  599. </div>
  600. )
  601. }}
  602. />
  603. <Controller control={control}
  604. name="acc_password"
  605. rules={{required: true, minLength: 6}}
  606. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  607. <PasswordInput
  608. className={classNames({'input-control--error': error})}
  609. value={value}
  610. message={error ? i18n.t("form_errors.pass") : ''}
  611. onChange={e => onChange(e.target.value)}
  612. placeholder={i18n.t('login.login_pwd')}
  613. innerRef={ref}/>
  614. )}
  615. />
  616. <Controller control={control}
  617. name="acc_repassword"
  618. rules={{required: true, minLength: 6}}
  619. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  620. <PasswordInput
  621. className={classNames({'input-control--error': error})}
  622. value={value}
  623. message={error ? i18n.t("form_errors.pass") : ''}
  624. onChange={e => onChange(e.target.value)}
  625. placeholder={i18n.t('login.re_pwd')}
  626. innerRef={ref}/>
  627. )}
  628. />
  629. <button className={"button-green"}>
  630. {
  631. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  632. }
  633. </button>
  634. {renderRegToLogin()}
  635. </form>
  636. )
  637. }
  638. const renderRegType=()=>{
  639. if (regType===REG_TYPE_PHONE){
  640. return renderRegPhone();
  641. }
  642. else if (regType===REG_TYPE_ACCOUNT){
  643. return renderRegAccount();
  644. }
  645. return (<></>);
  646. }
  647. const renderRegisterForm = () => {
  648. return (
  649. <Spring type="slideUp">
  650. <div className={styles.l_title}>{i18n.t("login.reg_title")}</div>
  651. {
  652. isAccountLogin?(
  653. <div className={styles.l_type_tabs}>
  654. <button className={`${styles.l_type_btn} ${regType === REG_TYPE_PHONE ? styles.active : ''}`}
  655. onClick={() => {
  656. setRegType(REG_TYPE_PHONE);
  657. }}>
  658. <span>{i18n.t("login.reg_type.phone")}</span>
  659. </button>
  660. <button
  661. className={`${styles.l_type_btn} ${regType === REG_TYPE_ACCOUNT ? styles.active : ''}`}
  662. onClick={() => {
  663. setRegType(REG_TYPE_ACCOUNT)
  664. }}>
  665. <span>{i18n.t("login.login_type.account")}</span>
  666. </button>
  667. </div>
  668. ):(<></>)
  669. }
  670. {renderRegType()}
  671. </Spring>
  672. )
  673. }
  674. //register_______________
  675. const renderForgetForm = () => {
  676. return (
  677. <Spring type="slideUp">
  678. <div className={styles.l_title}>{i18n.t("login.forget_title")}</div>
  679. <form key={"forget"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  680. onSubmitForget(data);
  681. })}>
  682. <Controller control={control}
  683. name="phone"
  684. rules={{required: true}}
  685. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  686. let message = error ? i18n.t("form_errors.phone_" + country) : "";
  687. return (<PhoneInput
  688. key={"phone"}
  689. className={classNames({'input-control--error': error})}
  690. value={value}
  691. message={message}
  692. onChange={e => onChange(e.target.value)}
  693. onChangeCountry={(country) => {
  694. setCountry(country);
  695. }}
  696. placeholder={i18n.t('login.phone_ph')}
  697. innerRef={ref}/>)
  698. }}
  699. />
  700. <Controller control={control}
  701. name="newpassword"
  702. rules={{required: true, minLength: 6}}
  703. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  704. <PasswordInput
  705. className={classNames({'input-control--error': error})}
  706. value={value}
  707. message={error ? i18n.t("form_errors.pass") : ''}
  708. onChange={e => onChange(e.target.value)}
  709. placeholder={i18n.t('user.password.newpassword')}
  710. innerRef={ref}/>
  711. )}
  712. />
  713. <Controller control={control}
  714. name="renewpassword"
  715. rules={{required: true, minLength: 6}}
  716. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  717. <PasswordInput
  718. className={classNames({'input-control--error': error})}
  719. value={value}
  720. message={error ? i18n.t("form_errors.pass") : ''}
  721. onChange={e => onChange(e.target.value)}
  722. placeholder={i18n.t('user.password.renewpassword')}
  723. innerRef={ref}/>
  724. )}
  725. />
  726. <Controller control={control}
  727. name="code"
  728. rules={{required: true}}
  729. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  730. return (
  731. <div className={`d-flex flex-column g-6`}>
  732. <div
  733. className={`input-control ${classNames({'input-control--error': error})}`}>
  734. <input
  735. type={'text'}
  736. autoComplete="off"
  737. ref={ref}
  738. onChange={e => onChange(e.target.value)}
  739. placeholder={i18n.t('login.otp_ph')}
  740. />
  741. <button type={"button"}
  742. className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
  743. onClick={onSendCode}>
  744. {
  745. otpStatus === REQ_STATUS.LOADING ? (
  746. <CircularProgress color="success" size={22}
  747. thickness={5}/>) : (
  748. <>
  749. {
  750. otpCD <= 0 ? i18n.t('login.btn_otp') : otpCD + "S"
  751. }
  752. </>
  753. )
  754. }
  755. </button>
  756. </div>
  757. </div>
  758. )
  759. }}
  760. />
  761. <button className={"button-green"}>
  762. {
  763. forgetStatus === REQ_STATUS.LOADING ? (
  764. <SmallLoading fill={"#fff"}/>) : i18n.t("login.forget_title")
  765. }
  766. </button>
  767. <div className={styles.l_reg_new}>
  768. <div>{i18n.t("login.back_to_login")}</div>
  769. <div className={styles.reg_btn} onClick={() => {
  770. setShowType(TYPE_LOGIN);
  771. }}>
  772. {i18n.t("login.sign_in_btn")}
  773. </div>
  774. </div>
  775. </form>
  776. </Spring>
  777. )
  778. }
  779. const renderForm = () => {
  780. let form = (<></>);
  781. if (showType === TYPE_LOGIN) {
  782. form = renderLoginForm();
  783. } else if (showType === TYPE_REGISTER) {
  784. form = renderRegisterForm();
  785. } else if (showType === TYPE_FORGET_PASS) {
  786. form = renderForgetForm();
  787. }
  788. return (
  789. <div className={styles.l_form_container}>
  790. {form}
  791. </div>
  792. )
  793. }
  794. return (
  795. <div className={styles.container}>
  796. {renderLogo()}
  797. {renderForm()}
  798. </div>
  799. )
  800. }
  801. export default LoginForm;