index.jsx 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  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, getLoginOpen,
  23. getLoginStatus, getRegisterOpen,
  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, validateEmail} 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_PHONE=0;
  45. const LOGIN_TYPE_SMS=1;
  46. const LOGIN_TYPE_ID=2;
  47. const LOGIN_TYPE_MAIL=3;
  48. const LOGIN_TYPE_GUEST=4;
  49. const REG_TYPE_PHONE=0;
  50. const REG_TYPE_SMS=1;
  51. const REG_TYPE_ID=2;
  52. const REG_TYPE_MAIL=3;
  53. const REG_TYPE_GUEST=4;
  54. const objInfo={
  55. cdTimer:null,
  56. inSubmit:false
  57. }
  58. const LoginForm = ({close}) => {
  59. const {theme,isMobile} = useThemeProvider();
  60. const [showType,setShowType]=useState(TYPE_LOGIN);
  61. const [open, setOpen] = useState(false);
  62. const [country, setCountry] = useState("55");
  63. const logourl=(theme===APP_THEME.DARK?logo_dark:logo_light);
  64. const loginStatus=useSelector(getLoginStatus);
  65. const regStatus=useSelector(getRegStatus);
  66. const forgetStatus=useSelector(getChangePassStatus);
  67. const dispatch = useDispatch();
  68. const navigate=useNavigate();
  69. const [loginType,setLoginType]=useState(LOGIN_TYPE_PHONE);
  70. const {register, handleSubmit, formState: {errors}, control} = useForm({
  71. defaultValues: {
  72. // country:'55',
  73. account: '',
  74. password: '',
  75. email:"",
  76. repassword:"",
  77. lang:"",
  78. code:"",
  79. phone:"",
  80. newpassword:"",
  81. renewpassword:""
  82. }
  83. });
  84. const {pathname,hash} = useLocation();
  85. const otpTimeStamp=useSelector(getSendCodeTS);
  86. const [otpCD,setOtpCD]=useState(-1);
  87. const otpStatus=useSelector(getSendCodeStatus);
  88. const smsLoginStatus=useSelector(getSMSLoginStatus);
  89. const isAccountLogin=useSelector(getAccountLogin);
  90. const [regType,setRegType]=useState(REG_TYPE_PHONE);
  91. const loginOpen=useSelector(getLoginOpen);
  92. const registerOpen=useSelector(getRegisterOpen);
  93. //登录类型列表
  94. const [logTypeList,setLogTypeList]=useState([]);
  95. //注册类型列表
  96. const [regTypeList,setRegTypeList]=useState([]);
  97. const onSendCode=(e)=>{
  98. if (otpCD>0)return;
  99. if (otpStatus===REQ_STATUS.LOADING)return;
  100. let phone=control._formValues.phone;
  101. if (phone==null||phone==="")return;
  102. let validate=validatePhone(phone);
  103. if (!validate){
  104. control.setError("phone",true)
  105. return;
  106. }
  107. let params={phone:phone};
  108. dispatch(reqSendCode(params));
  109. }
  110. const getLeftCD=()=>{
  111. let now=Date.now();
  112. let delta=now-otpTimeStamp;
  113. delta=Math.floor(delta/1000);
  114. delta=60-delta;
  115. if (delta<0)return -1;
  116. else return delta;
  117. }
  118. const clearTimer=()=>{
  119. if (objInfo.cdTimer!=null){
  120. clearInterval(objInfo.cdTimer);
  121. objInfo.cdTimer=null;
  122. }
  123. }
  124. const onSubmitOTPLogin=(data)=>{
  125. if (smsLoginStatus===REQ_STATUS.LOADING)return;
  126. data.callback=onCallback;
  127. dispatch(reqSMSLogin(data));
  128. }
  129. const parseLogTypeList=(openType,stype)=>{
  130. let subs=openType.split(",");
  131. let list=[];
  132. for(let i=0;i<subs.length;i++){
  133. let type=subs[i];
  134. let obj={};
  135. if (type===APP_LOGIN_TYPE.ID)stype===TYPE_LOGIN?obj.type=LOGIN_TYPE_ID:obj.type=REG_TYPE_ID;
  136. else if (type===APP_LOGIN_TYPE.SMS)stype===TYPE_LOGIN?obj.type=LOGIN_TYPE_SMS:obj.type=REG_TYPE_SMS;
  137. else if (type===APP_LOGIN_TYPE.PHONE)stype===TYPE_LOGIN?obj.type=LOGIN_TYPE_PHONE:obj.type=REG_TYPE_PHONE;
  138. else if (type===APP_LOGIN_TYPE.MAIL)stype===TYPE_LOGIN?obj.type=LOGIN_TYPE_MAIL:obj.type=REG_TYPE_MAIL;
  139. else if (type===APP_LOGIN_TYPE.GUEST) stype===TYPE_LOGIN?obj.type=LOGIN_TYPE_GUEST:obj.type=REG_TYPE_GUEST;
  140. obj.label="login.login_type."+type;
  141. list.push(obj);
  142. }
  143. list.sort((a,b)=>{
  144. return a.type-b.type;
  145. })
  146. return list;
  147. }
  148. const getPhoneError=()=>{
  149. if (country==="55")return i18n.t("form_errors.phone_" + country);
  150. else return i18n.t("form_errors.phone");
  151. }
  152. //effect_______
  153. useEffect(()=>{
  154. return ()=>{
  155. global.authLockPath=null;
  156. clearTimer();
  157. objInfo.inSubmit=false;
  158. }
  159. },[])
  160. useEffect(() => {
  161. objInfo.inSubmit=false;
  162. if (hash===ROUTE_PATH.SIGN_IN){
  163. setShowType(TYPE_LOGIN);
  164. }
  165. else if (hash===ROUTE_PATH.SIGN_UP){
  166. setShowType(TYPE_REGISTER);
  167. }
  168. }, [pathname,hash]);
  169. useEffect(()=>{
  170. let left=getLeftCD();
  171. setOtpCD(left);
  172. clearTimer();
  173. if (left>0){
  174. objInfo.cdTimer=setInterval(()=>{
  175. left=getLeftCD();
  176. setOtpCD(left);
  177. if (left<0){
  178. clearTimer();
  179. }
  180. },1000)
  181. }
  182. },[otpTimeStamp])
  183. useEffect(()=>{
  184. let list=parseLogTypeList(loginOpen,TYPE_LOGIN);
  185. if (list&&list.length>0){
  186. setLogTypeList(list);
  187. setLoginType(list[0].type);
  188. }
  189. },[loginOpen])
  190. useEffect(()=>{
  191. let list=parseLogTypeList(registerOpen,TYPE_REGISTER);
  192. if (list&&list.length>0){
  193. setRegTypeList(list);
  194. setRegType(list[0].type);
  195. }
  196. },[registerOpen])
  197. //effect_______
  198. const navigatRoute=(route)=>{
  199. navigate(route,{replace:true});
  200. }
  201. const onCallback=(code)=>{
  202. // global.authLockPath=null;
  203. objInfo.inSubmit=false;
  204. if (code==200){
  205. if (global.authLockPath!=null){
  206. let path=global.authLockPath;
  207. global.authLockPath=null;
  208. navigate(path,{replace:true});
  209. }
  210. else{
  211. if (close)close();
  212. }
  213. }
  214. }
  215. const onSubmitLogin=(data)=>{
  216. if (loginStatus===REQ_STATUS.LOADING)return;
  217. if (objInfo.inSubmit)return;
  218. data.country=country;
  219. data.callback=onCallback;
  220. dispatch(reqLogin(data));
  221. objInfo.inSubmit=true;
  222. }
  223. const onSubmitReg=(data)=>{
  224. if (regStatus===REQ_STATUS.LOADING)return;
  225. if (objInfo.inSubmit)return;
  226. data.country=country;
  227. data.callback=onCallback;
  228. dispatch(reqRegister(data));
  229. objInfo.inSubmit=true;
  230. }
  231. const onSubmitForget=(data)=>{
  232. if (forgetStatus===REQ_STATUS.LOADING)return;
  233. if (objInfo.inSubmit)return;
  234. data.country=country;
  235. data.callback=onCallback;
  236. dispatch(reqForgetPass(data));
  237. objInfo.inSubmit=true;
  238. }
  239. const validatePhone=(value)=>{
  240. return validateCountryPhone(country,value);
  241. }
  242. const validateMail=(value)=>{
  243. return validateEmail(value);
  244. }
  245. const getAreaItem=()=>{
  246. let areaID=global.getLocalAreaID();
  247. let item=null;
  248. for (let i = 0; i < area.length; i++) {
  249. let aitem=area[i];
  250. if (aitem.id===areaID){
  251. item=aitem;
  252. break;
  253. }
  254. }
  255. return item;
  256. }
  257. const renderLoading=()=>{
  258. return (<SmallLoading fill={"#fff"}/>)
  259. }
  260. const renderLogo=()=>{
  261. return (
  262. <div className={styles.l_logo}>
  263. <img className={styles.logo_img} src={logourl}/>
  264. </div>
  265. )
  266. }
  267. const renderAreaSelect=()=>{
  268. let item=getAreaItem();
  269. if (item==null)return (<></>);
  270. return (
  271. <button type={"button"} className={styles.area_btn} onClick={() => {
  272. global.showAreaSelect();
  273. }}>
  274. <img className={styles.flag} src={item.icon}/>
  275. <span>{i18n.t(item.name)}</span>
  276. <SvgIcon className={styles.icon} herf={"icon_Arrow"}></SvgIcon>
  277. </button>
  278. )
  279. }
  280. const renderLoginToReg = () =>{
  281. return (
  282. <div className={"d-flex flex-row align-items-center justify-content-between"}>
  283. <div className={styles.l_reg_new}>
  284. <div>{i18n.t("login.reg_new_des")}</div>
  285. <div className={styles.reg_btn} onClick={() => {
  286. // setShowType(TYPE_REGISTER);
  287. if (isMobile()) navigatRoute(ROUTE_PATH.SIGN_UP)
  288. else setShowType(TYPE_REGISTER);
  289. }}>
  290. {i18n.t("sign_up")}
  291. </div>
  292. </div>
  293. {renderAreaSelect()}
  294. </div>
  295. )
  296. }
  297. // const renderGuestLogin = () => {
  298. // let subs=loginOpen.split(",");
  299. // let isGuest=subs.indexOf(APP_LOGIN_TYPE.GUEST)!==-1;
  300. // if (!isGuest)return (<></>);
  301. // return (
  302. // <button type={"button"} className={styles.guest_btn}>
  303. // {i18n.t("login.guest_login")}
  304. // </button>
  305. // )
  306. // }
  307. const renderTypeTabs=(type)=>{
  308. let list=type===TYPE_LOGIN?logTypeList:regTypeList;
  309. if (list.length<=1)return (<></>);
  310. let ltype=type===TYPE_LOGIN?loginType:regType;
  311. return (
  312. <div className={styles.l_type_tabs}>
  313. {
  314. list.map((item,index)=>{
  315. return (
  316. <button
  317. key={index}
  318. className={`${styles.l_type_btn} ${ltype === item.type ? styles.active : ''}`}
  319. onClick={() => {
  320. if(type===TYPE_LOGIN)setLoginType(item.type);
  321. else if (type===TYPE_REGISTER)setRegType(item.type);
  322. }}>
  323. <span>{i18n.t(item.label)}</span>
  324. </button>
  325. )
  326. })
  327. }
  328. </div>
  329. )
  330. }
  331. //login__________
  332. const renderPassLogin = () => {
  333. return (
  334. <form key={"pass"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  335. data.type=APP_LOGIN_TYPE.PHONE;
  336. onSubmitLogin(data);
  337. })}>
  338. <Controller control={control}
  339. name="phone"
  340. rules={{required: true}}
  341. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  342. let message = error ? getPhoneError() : "";
  343. return (<PhoneInput
  344. key={"account"}
  345. className={classNames({'input-control--error': error})}
  346. value={value}
  347. message={message}
  348. onChange={e => onChange(e.target.value)}
  349. onChangeCountry={(country) => {
  350. setCountry(country);
  351. }}
  352. placeholder={i18n.t('login.phone_ph')}
  353. innerRef={ref}/>)
  354. }}
  355. />
  356. <Controller control={control}
  357. name="password"
  358. rules={{required: true, minLength: 6}}
  359. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  360. <PasswordInput
  361. className={classNames({'input-control--error': error})}
  362. value={value}
  363. message={error ? i18n.t("form_errors.pass") : ''}
  364. onChange={e => onChange(e.target.value)}
  365. placeholder={i18n.t('login.login_pwd')}
  366. innerRef={ref}/>
  367. )}
  368. />
  369. <div className={styles.l_forgot}>
  370. <button type={"button"} className={styles.forgot_btn} onClick={()=>{
  371. setShowType(TYPE_FORGET_PASS);
  372. }}>
  373. {i18n.t("login.forgot")}
  374. </button>
  375. </div>
  376. <button className={"button-green"}>
  377. {
  378. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  379. }
  380. </button>
  381. {/*{renderGuestLogin()}*/}
  382. {renderLoginToReg()}
  383. </form>
  384. )
  385. }
  386. const renderOTPLogin=()=>{
  387. return (
  388. <form key={"otp"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  389. onSubmitOTPLogin(data);
  390. })}>
  391. <Controller control={control}
  392. name="phone"
  393. rules={{required: true}}
  394. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  395. let message = error ? getPhoneError() : "";
  396. return (<PhoneInput
  397. key={"phone"}
  398. className={classNames({'input-control--error': error})}
  399. value={value}
  400. message={message}
  401. onChange={e => onChange(e.target.value)}
  402. onChangeCountry={(country) => {
  403. setCountry(country);
  404. }}
  405. placeholder={i18n.t('login.phone_ph')}
  406. innerRef={ref}/>)
  407. }}
  408. />
  409. <Controller control={control}
  410. name="code"
  411. rules={{required: true}}
  412. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  413. return (
  414. <div className={`d-flex flex-column g-6`}>
  415. <div
  416. className={`input-control ${classNames({'input-control--error': error})}`}>
  417. <input
  418. type={'text'}
  419. autoComplete="off"
  420. ref={ref}
  421. onChange={e => onChange(e.target.value)}
  422. placeholder={i18n.t('login.otp_ph')}
  423. />
  424. <button type={"button"}
  425. className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
  426. onClick={onSendCode}>
  427. {
  428. otpStatus === REQ_STATUS.LOADING ? (
  429. <CircularProgress color="success" size={22} thickness={5}/>) : (
  430. <>
  431. {
  432. otpCD <= 0 ? i18n.t('login.btn_otp') : otpCD + "S"
  433. }
  434. </>
  435. )
  436. }
  437. </button>
  438. </div>
  439. </div>
  440. )
  441. }}
  442. />
  443. <button className={"button-green"}>
  444. {
  445. smsLoginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  446. }
  447. </button>
  448. {/*{renderGuestLogin()}*/}
  449. {renderLoginToReg()}
  450. </form>
  451. )
  452. }
  453. const renderAccountLogin=()=>{
  454. return (
  455. <form key={"account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  456. // onSubmitAccountLogin(data);
  457. data.type=APP_LOGIN_TYPE.ID;
  458. onSubmitLogin(data);
  459. })}>
  460. <Controller control={control}
  461. name="account"
  462. rules={{required: true, minLength: 6}}
  463. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  464. return (
  465. <div className={`d-flex flex-column g-6`}>
  466. <div
  467. className={`input-control ${classNames({'input-control--error': error})}`}>
  468. <input
  469. type={'text'}
  470. value={value}
  471. autoComplete="off"
  472. ref={ref}
  473. onChange={e => onChange(e.target.value)}
  474. placeholder={i18n.t('login.account_ph')}
  475. />
  476. </div>
  477. {
  478. error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
  479. }
  480. </div>
  481. )
  482. }}
  483. />
  484. <Controller control={control}
  485. name="password"
  486. rules={{required: true, minLength: 6}}
  487. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  488. <PasswordInput
  489. className={classNames({'input-control--error': error})}
  490. value={value}
  491. message={error ? i18n.t("form_errors.pass") : ''}
  492. onChange={e => onChange(e.target.value)}
  493. placeholder={i18n.t('login.login_pwd')}
  494. innerRef={ref}/>
  495. )}
  496. />
  497. <button className={"button-green"}>
  498. {
  499. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  500. }
  501. </button>
  502. {/*{renderGuestLogin()}*/}
  503. {renderLoginToReg()}
  504. </form>
  505. )
  506. }
  507. const renderMailLogin=()=>{
  508. return (
  509. <form key={"mail"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  510. // onSubmitAccountLogin(data);
  511. data.type=APP_LOGIN_TYPE.MAIL;
  512. onSubmitLogin(data);
  513. })}>
  514. <Controller control={control}
  515. name="email"
  516. rules={{required: true, validate: validateMail}}
  517. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  518. return (
  519. <div className={`d-flex flex-column g-6`}>
  520. <div
  521. className={`input-control ${classNames({'input-control--error': error})}`}>
  522. <input
  523. type={'text'}
  524. value={value}
  525. autoComplete="off"
  526. ref={ref}
  527. onChange={e => onChange(e.target.value)}
  528. placeholder={i18n.t('login.mail_ph')}
  529. />
  530. </div>
  531. {
  532. error?(<div className="input-prompt-error">{i18n.t('form_errors.email')}</div>):(<></>)
  533. }
  534. </div>
  535. )
  536. }}
  537. />
  538. <Controller control={control}
  539. name="password"
  540. rules={{required: true, minLength: 6}}
  541. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  542. <PasswordInput
  543. className={classNames({'input-control--error': error})}
  544. value={value}
  545. message={error ? i18n.t("form_errors.pass") : ''}
  546. onChange={e => onChange(e.target.value)}
  547. placeholder={i18n.t('login.login_pwd')}
  548. innerRef={ref}/>
  549. )}
  550. />
  551. <button className={"button-green"}>
  552. {
  553. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_in_btn")
  554. }
  555. </button>
  556. {/*{renderGuestLogin()}*/}
  557. {renderLoginToReg()}
  558. </form>
  559. )
  560. }
  561. const renderGuestLogin=()=>{
  562. return (
  563. <form key={"guest"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  564. // onSubmitAccountLogin(data);
  565. data.type=APP_LOGIN_TYPE.GUEST;
  566. onSubmitLogin(data);
  567. })}>
  568. <button className={"button-green"}>
  569. {
  570. loginStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.guest_login")
  571. }
  572. </button>
  573. {renderLoginToReg()}
  574. </form>
  575. )
  576. }
  577. const renderLoginType = () => {
  578. control._names.mount.clear();
  579. if (loginType === LOGIN_TYPE_PHONE) {
  580. return renderPassLogin();
  581. } else if (loginType === LOGIN_TYPE_SMS){
  582. return renderOTPLogin();
  583. } else if (loginType === LOGIN_TYPE_ID){
  584. return renderAccountLogin();
  585. } else if (loginType ===LOGIN_TYPE_MAIL){
  586. return renderMailLogin();
  587. } else if (loginType === LOGIN_TYPE_GUEST){
  588. return renderGuestLogin();
  589. }
  590. return (<></>);
  591. }
  592. const renderLoginForm = () => {
  593. return (
  594. <Spring type="slideUp">
  595. <div className={styles.l_title}>{i18n.t("login.login_title")}</div>
  596. {renderTypeTabs(TYPE_LOGIN)}
  597. {
  598. // loginType===LOGIN_TYPE_PASS?renderPassLogin():renderOTPLogin()
  599. renderLoginType()
  600. }
  601. </Spring>
  602. )
  603. }
  604. //login__________
  605. //register_______________
  606. const renderRegToLogin=()=>{
  607. return (
  608. <div className={"d-flex flex-row align-items-center justify-content-between"}>
  609. <div className={styles.l_reg_new}>
  610. <div>{i18n.t("login.login_des")}</div>
  611. <div className={styles.reg_btn} onClick={() => {
  612. // setShowType(TYPE_LOGIN);
  613. if (isMobile()) navigatRoute(ROUTE_PATH.SIGN_IN)
  614. else setShowType(TYPE_LOGIN);
  615. }}>
  616. {i18n.t("login.sign_in_btn")}
  617. </div>
  618. </div>
  619. {renderAreaSelect()}
  620. </div>
  621. )
  622. }
  623. // const renderGuestReg = () => {
  624. // let subs=registerOpen.split(",");
  625. // let isGuest=subs.indexOf(APP_LOGIN_TYPE.GUEST)!==-1;
  626. // if (!isGuest)return (<></>);
  627. // return (
  628. // <button type={"button"} className={styles.guest_btn}>
  629. // {i18n.t("login.guest_reg")}
  630. // </button>
  631. // )
  632. // }
  633. const renderRegPhone = () => {
  634. return (
  635. <form key={"reg_phone"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  636. data.type=APP_LOGIN_TYPE.PHONE;
  637. onSubmitReg(data);
  638. })}>
  639. <Controller control={control}
  640. name="phone"
  641. rules={{required: true, validate: validatePhone}}
  642. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  643. let message = error ? getPhoneError() : "";
  644. return (<PhoneInput
  645. className={classNames({'input-control--error': error})}
  646. value={value}
  647. message={message}
  648. onChange={e => onChange(e.target.value)}
  649. onChangeCountry={(country) => {
  650. setCountry(country);
  651. }}
  652. placeholder={i18n.t('login.phone_ph')}
  653. innerRef={ref}/>)
  654. }}
  655. />
  656. <Controller control={control}
  657. name="password"
  658. rules={{required: true, minLength: 6}}
  659. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  660. <PasswordInput
  661. className={classNames({'input-control--error': error})}
  662. value={value}
  663. message={error ? i18n.t("form_errors.pass") : ''}
  664. onChange={e => onChange(e.target.value)}
  665. placeholder={i18n.t('login.login_pwd')}
  666. innerRef={ref}/>
  667. )}
  668. />
  669. <Controller control={control}
  670. name="repassword"
  671. rules={{required: true, minLength: 6}}
  672. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  673. <PasswordInput
  674. className={classNames({'input-control--error': error})}
  675. value={value}
  676. message={error ? i18n.t("form_errors.pass") : ''}
  677. onChange={e => onChange(e.target.value)}
  678. placeholder={i18n.t('login.re_pwd')}
  679. innerRef={ref}/>
  680. )}
  681. />
  682. <button className={"button-green"}>
  683. {
  684. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  685. }
  686. </button>
  687. {/*{renderGuestReg()}*/}
  688. {renderRegToLogin()}
  689. </form>
  690. )
  691. }
  692. const renderRegAccount=()=>{
  693. return (
  694. <form key={"reg_account"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  695. // onSubmitReg(data);
  696. // onSubmitAccountReg(data);
  697. data.type=APP_LOGIN_TYPE.ID;
  698. onSubmitReg(data);
  699. })}>
  700. <Controller control={control}
  701. name="account"
  702. rules={{required: true, minLength: 6}}
  703. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  704. return (
  705. <div className={`d-flex flex-column g-6`}>
  706. <div
  707. className={`input-control ${classNames({'input-control--error': error})}`}>
  708. <input
  709. type={'text'}
  710. value={value}
  711. autoComplete="off"
  712. ref={ref}
  713. onChange={e => onChange(e.target.value)}
  714. placeholder={i18n.t('login.account_ph')}
  715. />
  716. </div>
  717. {
  718. error?(<div className="input-prompt-error">{i18n.t('form_errors.account')}</div>):(<></>)
  719. }
  720. </div>
  721. )
  722. }}
  723. />
  724. <Controller control={control}
  725. name="password"
  726. rules={{required: true, minLength: 6}}
  727. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  728. <PasswordInput
  729. className={classNames({'input-control--error': error})}
  730. value={value}
  731. message={error ? i18n.t("form_errors.pass") : ''}
  732. onChange={e => onChange(e.target.value)}
  733. placeholder={i18n.t('login.login_pwd')}
  734. innerRef={ref}/>
  735. )}
  736. />
  737. <Controller control={control}
  738. name="repassword"
  739. rules={{required: true, minLength: 6}}
  740. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  741. <PasswordInput
  742. className={classNames({'input-control--error': error})}
  743. value={value}
  744. message={error ? i18n.t("form_errors.pass") : ''}
  745. onChange={e => onChange(e.target.value)}
  746. placeholder={i18n.t('login.re_pwd')}
  747. innerRef={ref}/>
  748. )}
  749. />
  750. <button className={"button-green"}>
  751. {
  752. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  753. }
  754. </button>
  755. {/*{renderGuestReg()}*/}
  756. {renderRegToLogin()}
  757. </form>
  758. )
  759. }
  760. const renderRegSms=()=>{
  761. return (
  762. <form key={"reg_sms"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  763. data.type=APP_LOGIN_TYPE.SMS;
  764. onSubmitReg(data);
  765. })}>
  766. <Controller control={control}
  767. name="phone"
  768. rules={{required: true, validate: validatePhone}}
  769. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  770. let message = error ? getPhoneError() : "";
  771. return (<PhoneInput
  772. className={classNames({'input-control--error': error})}
  773. value={value}
  774. message={message}
  775. onChange={e => onChange(e.target.value)}
  776. onChangeCountry={(country) => {
  777. setCountry(country);
  778. }}
  779. placeholder={i18n.t('login.phone_ph')}
  780. innerRef={ref}/>)
  781. }}
  782. />
  783. <Controller control={control}
  784. name="password"
  785. rules={{required: true, minLength: 6}}
  786. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  787. <PasswordInput
  788. className={classNames({'input-control--error': error})}
  789. value={value}
  790. message={error ? i18n.t("form_errors.pass") : ''}
  791. onChange={e => onChange(e.target.value)}
  792. placeholder={i18n.t('login.login_pwd')}
  793. innerRef={ref}/>
  794. )}
  795. />
  796. <Controller control={control}
  797. name="repassword"
  798. rules={{required: true, minLength: 6}}
  799. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  800. <PasswordInput
  801. className={classNames({'input-control--error': error})}
  802. value={value}
  803. message={error ? i18n.t("form_errors.pass") : ''}
  804. onChange={e => onChange(e.target.value)}
  805. placeholder={i18n.t('login.re_pwd')}
  806. innerRef={ref}/>
  807. )}
  808. />
  809. <Controller control={control}
  810. name="code"
  811. rules={{required: true}}
  812. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  813. return (
  814. <div className={`d-flex flex-column g-6`}>
  815. <div
  816. className={`input-control ${classNames({'input-control--error': error})}`}>
  817. <input
  818. type={'text'}
  819. autoComplete="off"
  820. ref={ref}
  821. onChange={e => onChange(e.target.value)}
  822. placeholder={i18n.t('login.otp_ph')}
  823. />
  824. <button type={"button"}
  825. className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
  826. onClick={onSendCode}>
  827. {
  828. otpStatus === REQ_STATUS.LOADING ? (
  829. <CircularProgress color="success" size={22} thickness={5}/>) : (
  830. <>
  831. {
  832. otpCD <= 0 ? i18n.t('login.btn_otp') : otpCD + "S"
  833. }
  834. </>
  835. )
  836. }
  837. </button>
  838. </div>
  839. </div>
  840. )
  841. }}
  842. />
  843. <button className={"button-green"}>
  844. {
  845. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  846. }
  847. </button>
  848. {/*{renderGuestReg()}*/}
  849. {renderRegToLogin()}
  850. </form>
  851. )
  852. }
  853. const renderRegMail=()=>{
  854. return (
  855. <form key={"reg_mail"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  856. // onSubmitReg(data);
  857. // onSubmitAccountReg(data);
  858. data.type=APP_LOGIN_TYPE.MAIL;
  859. onSubmitReg(data);
  860. })}>
  861. <Controller control={control}
  862. name="email"
  863. rules={{required: true, validate: validateMail}}
  864. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  865. return (
  866. <div className={`d-flex flex-column g-6`}>
  867. <div
  868. className={`input-control ${classNames({'input-control--error': error})}`}>
  869. <input
  870. type={'text'}
  871. value={value}
  872. autoComplete="off"
  873. ref={ref}
  874. onChange={e => onChange(e.target.value)}
  875. placeholder={i18n.t('login.mail_ph')}
  876. />
  877. </div>
  878. {
  879. error?(<div className="input-prompt-error">{i18n.t('form_errors.email')}</div>):(<></>)
  880. }
  881. </div>
  882. )
  883. }}
  884. />
  885. <Controller control={control}
  886. name="password"
  887. rules={{required: true, minLength: 6}}
  888. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  889. <PasswordInput
  890. className={classNames({'input-control--error': error})}
  891. value={value}
  892. message={error ? i18n.t("form_errors.pass") : ''}
  893. onChange={e => onChange(e.target.value)}
  894. placeholder={i18n.t('login.login_pwd')}
  895. innerRef={ref}/>
  896. )}
  897. />
  898. <Controller control={control}
  899. name="repassword"
  900. rules={{required: true, minLength: 6}}
  901. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  902. <PasswordInput
  903. className={classNames({'input-control--error': error})}
  904. value={value}
  905. message={error ? i18n.t("form_errors.pass") : ''}
  906. onChange={e => onChange(e.target.value)}
  907. placeholder={i18n.t('login.re_pwd')}
  908. innerRef={ref}/>
  909. )}
  910. />
  911. <button className={"button-green"}>
  912. {
  913. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.sign_up_btn")
  914. }
  915. </button>
  916. {/*{renderGuestReg()}*/}
  917. {renderRegToLogin()}
  918. </form>
  919. )
  920. }
  921. const renderRegGuest=()=>{
  922. return (
  923. <form key={"reg_guest"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  924. data.type=APP_LOGIN_TYPE.GUEST;
  925. onSubmitReg(data);
  926. })}>
  927. <button className={"button-green"}>
  928. {
  929. regStatus === REQ_STATUS.LOADING ? renderLoading() : i18n.t("login.guest_reg")
  930. }
  931. </button>
  932. {renderRegToLogin()}
  933. </form>
  934. )
  935. }
  936. const renderRegType=()=>{
  937. control._names.mount.clear();
  938. if (regType===REG_TYPE_PHONE){
  939. return renderRegPhone();
  940. }
  941. else if (regType===REG_TYPE_ID){
  942. return renderRegAccount();
  943. }
  944. else if (regType===REG_TYPE_SMS){
  945. return renderRegSms();
  946. }
  947. else if(regType===REG_TYPE_MAIL){
  948. return renderRegMail();
  949. }
  950. else if (regType===REG_TYPE_GUEST){
  951. return renderRegGuest();
  952. }
  953. return (<></>);
  954. }
  955. const renderRegisterForm = () => {
  956. return (
  957. <Spring type="slideUp">
  958. <div className={styles.l_title}>{i18n.t("login.reg_title")}</div>
  959. {renderTypeTabs(TYPE_REGISTER)}
  960. {renderRegType()}
  961. </Spring>
  962. )
  963. }
  964. //register_______________
  965. const renderForgetForm = () => {
  966. return (
  967. <Spring type="slideUp">
  968. <div className={styles.l_title}>{i18n.t("login.forget_title")}</div>
  969. <form key={"forget"} autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
  970. onSubmitForget(data);
  971. })}>
  972. <Controller control={control}
  973. name="phone"
  974. rules={{required: true}}
  975. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  976. let message = error ? getPhoneError() : "";
  977. return (<PhoneInput
  978. key={"phone"}
  979. className={classNames({'input-control--error': error})}
  980. value={value}
  981. message={message}
  982. onChange={e => onChange(e.target.value)}
  983. onChangeCountry={(country) => {
  984. setCountry(country);
  985. }}
  986. placeholder={i18n.t('login.phone_ph')}
  987. innerRef={ref}/>)
  988. }}
  989. />
  990. <Controller control={control}
  991. name="newpassword"
  992. rules={{required: true, minLength: 6}}
  993. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  994. <PasswordInput
  995. className={classNames({'input-control--error': error})}
  996. value={value}
  997. message={error ? i18n.t("form_errors.pass") : ''}
  998. onChange={e => onChange(e.target.value)}
  999. placeholder={i18n.t('user.password.newpassword')}
  1000. innerRef={ref}/>
  1001. )}
  1002. />
  1003. <Controller control={control}
  1004. name="renewpassword"
  1005. rules={{required: true, minLength: 6}}
  1006. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  1007. <PasswordInput
  1008. className={classNames({'input-control--error': error})}
  1009. value={value}
  1010. message={error ? i18n.t("form_errors.pass") : ''}
  1011. onChange={e => onChange(e.target.value)}
  1012. placeholder={i18n.t('user.password.renewpassword')}
  1013. innerRef={ref}/>
  1014. )}
  1015. />
  1016. <Controller control={control}
  1017. name="code"
  1018. rules={{required: true}}
  1019. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  1020. return (
  1021. <div className={`d-flex flex-column g-6`}>
  1022. <div
  1023. className={`input-control ${classNames({'input-control--error': error})}`}>
  1024. <input
  1025. type={'text'}
  1026. autoComplete="off"
  1027. ref={ref}
  1028. onChange={e => onChange(e.target.value)}
  1029. placeholder={i18n.t('login.otp_ph')}
  1030. />
  1031. <button type={"button"}
  1032. className={`${styles.otp_btn} ${otpCD > 0 ? styles.cd_timer : ''}`}
  1033. onClick={onSendCode}>
  1034. {
  1035. otpStatus === REQ_STATUS.LOADING ? (
  1036. <CircularProgress color="success" size={22}
  1037. thickness={5}/>) : (
  1038. <>
  1039. {
  1040. otpCD <= 0 ? i18n.t('login.btn_otp') : otpCD + "S"
  1041. }
  1042. </>
  1043. )
  1044. }
  1045. </button>
  1046. </div>
  1047. </div>
  1048. )
  1049. }}
  1050. />
  1051. <button className={"button-green"}>
  1052. {
  1053. forgetStatus === REQ_STATUS.LOADING ? (
  1054. <SmallLoading fill={"#fff"}/>) : i18n.t("login.forget_title")
  1055. }
  1056. </button>
  1057. <div className={styles.l_reg_new}>
  1058. <div>{i18n.t("login.back_to_login")}</div>
  1059. <div className={styles.reg_btn} onClick={() => {
  1060. setShowType(TYPE_LOGIN);
  1061. }}>
  1062. {i18n.t("login.sign_in_btn")}
  1063. </div>
  1064. </div>
  1065. </form>
  1066. </Spring>
  1067. )
  1068. }
  1069. const renderForm = () => {
  1070. let form = (<></>);
  1071. if (showType === TYPE_LOGIN) {
  1072. form = renderLoginForm();
  1073. } else if (showType === TYPE_REGISTER) {
  1074. form = renderRegisterForm();
  1075. } else if (showType === TYPE_FORGET_PASS) {
  1076. form = renderForgetForm();
  1077. }
  1078. return (
  1079. <div className={styles.l_form_container}>
  1080. {form}
  1081. </div>
  1082. )
  1083. }
  1084. return (
  1085. <div className={styles.container}>
  1086. {renderLogo()}
  1087. {renderForm()}
  1088. </div>
  1089. )
  1090. }
  1091. export default LoginForm;