index.jsx 12 KB

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