index.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import styles from './styles.module.scss';
  2. import Spring from "@components/Spring";
  3. import {APP_AVATAR, REQ_STATUS} from "@api/config";
  4. import LazyImage from "@components/LazyImage";
  5. import {useDispatch, useSelector} from "react-redux";
  6. import {getChangeEmailStatus, getChangeInfoStatus, getChangePhoneStatus, getUserInfo} from "@features/mainSlice";
  7. import React, {useState} from "react";
  8. import {Controller, useForm} from "react-hook-form";
  9. import classNames from "classnames";
  10. import PhoneInput from "@components/UInput/PhoneInput";
  11. import {ReactComponent as Male} from '@assets/singlesvg/gener/male.svg';
  12. import {ReactComponent as FeMale} from '@assets/singlesvg/gener/female.svg';
  13. import SmallLoading from "@components/SmallLoading";
  14. import {reqChangeEmail, reqChangeInfo, reqChangePhone} from "@features/api";
  15. import {APP_GENDER} from "@constants/app";
  16. import {validateCountryPhone} from "@utils/helpers";
  17. import LazyImgix from "@components/Imgix/LazyImgix";
  18. const i18n=global.i18n;
  19. const getAvatarUrl=(id)=>{
  20. return `${APP_AVATAR}avatar_${id}.png?auto=format,compress&cs=srgb`;
  21. }
  22. const SelectAvatar=({innerRef, ...props})=>{
  23. const [value, setValue] = useState(props.value);
  24. const aNum=16;
  25. const avatars = Array.from({ length:aNum }, (value, index) => index + 1);
  26. return (
  27. <div className={styles.select_avatar_con}
  28. ref={innerRef}
  29. {...props}
  30. >
  31. {
  32. avatars.map((item,index)=>{
  33. return (
  34. <button type={"button"} key={index} className={`${styles.avatar_btn}`} onClick={()=>{
  35. setValue(item);
  36. if (props.onChange)props.onChange(item);
  37. }}>
  38. {/*<LazyImage wrapperClassName={`${styles.avatar} ${item==value?styles.active:''}`} src={getAvatarUrl(item)} alt={"avatar_" + index}/>*/}
  39. <LazyImgix className={`${styles.avatar} ${item==value?styles.active:''}`} src={getAvatarUrl(item)} alt={"avatar_" + index} width={60} />
  40. </button>
  41. )
  42. })
  43. }
  44. </div>
  45. )
  46. }
  47. const WEditProfile=({close})=>{
  48. const user=useSelector(getUserInfo);
  49. const status=useSelector(getChangeInfoStatus);
  50. const status_ph=useSelector(getChangePhoneStatus);
  51. const status_em=useSelector(getChangeEmailStatus);
  52. const dispatch = useDispatch();
  53. const [avatarID,setAvatarID]=useState(user.FaceID);
  54. const [country, setCountry] = useState(user.RegisterLocation);
  55. const validatePhone=(value)=>{
  56. return validateCountryPhone(country,value);
  57. }
  58. const getPhone=()=>{
  59. let loc=user.RegisterLocation;
  60. let phone=user.Phone;
  61. if (phone.startsWith(loc)){
  62. phone=phone.replace(loc,"");
  63. }
  64. return phone;
  65. }
  66. const getIsLock=()=>{
  67. let isLock=status===REQ_STATUS.LOADING||status_ph===REQ_STATUS.LOADING||status_em===REQ_STATUS.LOADING;
  68. return isLock;
  69. }
  70. const {register, handleSubmit, formState: {errors}, control} = useForm({
  71. defaultValues: {
  72. FaceID:user.FaceID,
  73. NickName:user.NickName,
  74. Gender:user.Gender,
  75. Phone:getPhone(),
  76. Email:user.Email
  77. }
  78. });
  79. const renderAvatar=()=>{
  80. return (
  81. <div className={styles.avatar_con}>
  82. {/*<LazyImage wrapperClassName={styles.avatar} src={getAvatarUrl(avatarID)} alt={"avator"}/>*/}
  83. <LazyImgix className={styles.avatar} src={getAvatarUrl(avatarID)} alt={"avatar"} width={100}></LazyImgix>
  84. </div>
  85. )
  86. }
  87. const renderSelectAvatar=()=>{
  88. return (
  89. <div className={styles.form_item}>
  90. <div className={styles.title}>{i18n.t("user.title_avatar")}</div>
  91. <Controller control={control}
  92. name="FaceID"
  93. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  94. <SelectAvatar
  95. value={value}
  96. onChange={(faceID)=>{
  97. onChange(faceID);
  98. setAvatarID(faceID);
  99. }}
  100. innerRef={ref}/>
  101. )}
  102. />
  103. </div>
  104. )
  105. }
  106. const renderUsername=()=>{
  107. return (
  108. <div className={styles.form_item}>
  109. <div className={styles.title}>{i18n.t("user.title_username")}</div>
  110. <Controller control={control}
  111. name="NickName"
  112. rules={{required: true}}
  113. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  114. <div className={classNames("input-control",{'input-control--error': error})}>
  115. <input
  116. value={value}
  117. type="tel"
  118. ref={ref}
  119. onChange={(e)=>{
  120. onChange(e.target.value);
  121. }}
  122. placeholder={i18n.t('user.username_ph')}
  123. />
  124. </div>
  125. )}
  126. />
  127. </div>
  128. )
  129. }
  130. const renderPhone=()=>{
  131. return (
  132. <div className={styles.form_item}>
  133. <div className={styles.title}>{i18n.t("user.title_phone")}</div>
  134. <Controller control={control}
  135. name="Phone"
  136. rules={{required: true,validate:validatePhone}}
  137. render={({field: {ref, onChange, value}, fieldState: {error}}) => {
  138. let message=error?i18n.t("form_errors.phone_"+country):"";
  139. return (
  140. <PhoneInput
  141. className={classNames({'input-control--error': error})}
  142. value={value}
  143. message={message}
  144. onChange={e => onChange(e.target.value)}
  145. onChangeCountry={(country)=>{
  146. setCountry(country);
  147. }}
  148. placeholder={i18n.t('user.phone_ph')}
  149. innerRef={ref}/>
  150. )
  151. }}
  152. />
  153. </div>
  154. )
  155. }
  156. const renderEmail=()=>{
  157. return (
  158. <div className={styles.form_item}>
  159. <div className={styles.title}>{i18n.t("user.title_email")}</div>
  160. <Controller control={control}
  161. name="Email"
  162. // rules={{required: true}}
  163. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  164. <div className={classNames("input-control",{'input-control--error': error})}>
  165. <input
  166. value={value}
  167. type="tel"
  168. ref={ref}
  169. onChange={(e)=>{
  170. onChange(e.target.value);
  171. }}
  172. placeholder={i18n.t('user.email_ph')}
  173. />
  174. </div>
  175. )}
  176. />
  177. </div>
  178. )
  179. }
  180. const renderGender=()=>{
  181. return (
  182. <div className={styles.form_item}>
  183. <div className={styles.title}>{i18n.t("user.title_gender")}</div>
  184. <Controller control={control}
  185. name="Gender"
  186. // rules={{required: true}}
  187. render={({field: {ref, onChange, value}, fieldState: {error}}) => (
  188. <div className={styles.gender_con}>
  189. <button type={"button"} className={`${styles.radio_btn} ${value===APP_GENDER.FEMALE?styles.active:''}`} onClick={()=>{
  190. onChange(APP_GENDER.FEMALE);
  191. }}>
  192. <div className={styles.circle}>
  193. <div className={styles.dot}/>
  194. </div>
  195. <div>{i18n.t("user.female")}</div>
  196. <FeMale className={styles.icon_f}/>
  197. </button>
  198. <button type={"button"} className={`${styles.radio_btn} ${value===APP_GENDER.MALE?styles.active:''}`} onClick={()=>{
  199. onChange(APP_GENDER.MALE)
  200. }}>
  201. <div className={styles.circle}>
  202. <div className={styles.dot}/>
  203. </div>
  204. <div>{i18n.t("user.male")}</div>
  205. <Male className={styles.icon_m}/>
  206. </button>
  207. <button type={"button"} className={`${styles.radio_btn} ${value===APP_GENDER.OTHER?styles.active:''}`} onClick={()=>{
  208. onChange(APP_GENDER.OTHER)
  209. }}>
  210. <div className={styles.circle}>
  211. <div className={styles.dot}/>
  212. </div>
  213. <div>{i18n.t("user.other")}</div>
  214. </button>
  215. </div>
  216. )}
  217. />
  218. </div>
  219. )
  220. }
  221. const renderSubmit=()=>{
  222. let isLoading=getIsLock();
  223. return (
  224. <div className={styles.submit_btn_con}>
  225. <button className={"button-green"}>
  226. {
  227. isLoading?(<SmallLoading fill={"#fff"}/>):i18n.t("user.submit_btn")
  228. }
  229. </button>
  230. </div>
  231. )
  232. }
  233. const onCallback=(code)=>{
  234. if (code==200){
  235. if (close)close();
  236. }
  237. }
  238. const handleChangeInfo=(data)=>{
  239. data.Phone=country+data.Phone;
  240. data.RegisterLocation=country;
  241. let change={};
  242. let change_ph={};
  243. let change_em={};
  244. let isSubmit=false;
  245. let isSubmit_ph=false;
  246. let isSubmit_em=false;
  247. for (const key in data) {
  248. let value=data[key];
  249. if (value!==user[key]){
  250. if (key==="Phone"){
  251. isSubmit_ph=true;
  252. change_ph[key]=value;
  253. }
  254. else if (key=="Email"){
  255. isSubmit_em=true;
  256. change_em[key]=value;
  257. }
  258. else
  259. {
  260. isSubmit=true;
  261. change[key]=value;
  262. }
  263. }
  264. }
  265. // if (!isSubmit)return;
  266. if (getIsLock())return;
  267. change.callback=onCallback;
  268. change_ph.callback=onCallback;
  269. change_em.callback=onCallback;
  270. if (isSubmit)dispatch(reqChangeInfo(change));
  271. if (isSubmit_ph)dispatch(reqChangePhone(change_ph));
  272. if (isSubmit_em)dispatch(reqChangeEmail(change_em));
  273. }
  274. const renderForm=()=>{
  275. return (
  276. <form autoComplete="off" className={styles.user_form} onSubmit={handleSubmit((data) => {
  277. handleChangeInfo(data);
  278. })}>
  279. {renderUsername()}
  280. {renderPhone()}
  281. {renderEmail()}
  282. {renderGender()}
  283. {renderSelectAvatar()}
  284. {renderSubmit()}
  285. </form>
  286. )
  287. }
  288. return (
  289. <div className={styles.container}>
  290. <Spring type="slideUp" className={styles.content}>
  291. {renderAvatar()}
  292. {renderForm()}
  293. </Spring>
  294. </div>
  295. )
  296. }
  297. export default WEditProfile;