edit-personal-info.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import React, { useEffect, useState } from 'react';
  2. import { ScrollView, View, Text } from 'react-native';
  3. import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
  4. import { Formik } from 'formik';
  5. import * as yup from 'yup';
  6. import { useNavigation } from '@react-navigation/native';
  7. import { useQueryClient } from '@tanstack/react-query';
  8. import { Image } from 'expo-image';
  9. import { API_HOST } from '../../../../constants';
  10. import { AvatarPicker, BigText, Header, Input, PageWrapper, Button } from '../../../../components';
  11. import { InputDatePicker } from '../../../../components/Calendar/InputDatePicker';
  12. import { ModalFlatList } from '../../../../components/FlatList/modal-flatlist';
  13. import { usePostGetProfileQuery } from '../../../../modules/auth/user/queries/use-post-get-profile';
  14. import { useGetRegionsWithFlagQuery } from '../../../../modules/auth/regions/queries/use-post-get-regions';
  15. import { usePostSetProfileMutation } from '../../../../modules/auth/user/queries/use-post-set-profile';
  16. import { userQueryKeys } from '../../../../modules/auth/user/user-query-keys';
  17. import type { PostSetProfileData } from '../../../../modules/auth/user/user-api';
  18. import { storageGet } from '../../../../storage';
  19. import { Colors } from '../../../../theme';
  20. import FacebookIcon from '../../../../../assets/icons/facebook.svg';
  21. import InstagramIcon from '../../../../../assets/icons/instagram.svg';
  22. import XIcon from '../../../../../assets/icons/x(twitter).svg';
  23. import YoutubeIcon from '../../../../../assets/icons/youtube.svg';
  24. import GlobeIcon from '../../../../../assets/icons/bottom-navigation/globe.svg';
  25. import LinkIcon from '../../../../../assets/icons/link.svg';
  26. const ProfileSchema = yup.object({
  27. username: yup.string().optional(),
  28. email: yup.string().email().optional(),
  29. first_name: yup.string().optional(),
  30. last_name: yup.string().optional(),
  31. date_of_birth: yup.string().optional(),
  32. homebase: yup.number().optional(),
  33. homebase2: yup.number().nullable().optional(),
  34. bio: yup.string().optional(),
  35. f: yup.string().optional(),
  36. t: yup.string().optional(),
  37. i: yup.string().optional(),
  38. y: yup.string().optional(),
  39. www: yup.string().optional(),
  40. other: yup.string().optional()
  41. });
  42. export const EditPersonalInfo = () => {
  43. const [token, setToken] = useState<string>('');
  44. const { mutate: updateProfile, data: updateResponse, reset } = usePostSetProfileMutation();
  45. useEffect(() => {
  46. async function getToken() {
  47. setToken((await storageGet('token')) as unknown as string);
  48. }
  49. reset();
  50. getToken();
  51. }, []);
  52. const navigation = useNavigation();
  53. const queryClient = useQueryClient();
  54. const { data, error } = usePostGetProfileQuery(token!, true);
  55. const regions = useGetRegionsWithFlagQuery(true);
  56. if (!data) return <Text>Loading</Text>;
  57. const originRegion = regions.data?.data.find((region) => region.id === data.homebase);
  58. const secondOrigin = regions.data?.data.find((region) => region.id === data.homebase2);
  59. return (
  60. <PageWrapper>
  61. <ScrollView showsVerticalScrollIndicator={false}>
  62. <Header label={'Edit Personal Info'} />
  63. <KeyboardAwareScrollView>
  64. <Formik
  65. validationSchema={ProfileSchema}
  66. initialValues={{
  67. username: data.username,
  68. email: data.email,
  69. first_name: data.first_name,
  70. last_name: data.last_name,
  71. date_of_birth: data.date_of_birth,
  72. homebase: data.homebase,
  73. homebase2: data.homebase2,
  74. bio: data.bio.toString(),
  75. f: data.links.f!.link,
  76. i: data.links.i!.link,
  77. t: data.links.t!.link,
  78. y: data.links.y!.link,
  79. www: data.links.www!.link,
  80. other: data.links.other!.link,
  81. photo: {
  82. type: '',
  83. uri: '',
  84. name: ''
  85. }
  86. }}
  87. onSubmit={async (values) => {
  88. const profileData: PostSetProfileData = {
  89. token: token,
  90. user: {
  91. username: values.username,
  92. email: values.email,
  93. first_name: values.first_name,
  94. last_name: values.last_name,
  95. date_of_birth: values.date_of_birth,
  96. homebase: values.homebase,
  97. bio: values.bio,
  98. f: values.f,
  99. i: values.i,
  100. t: values.t,
  101. y: values.y,
  102. www: values.www,
  103. other: values.other
  104. }
  105. };
  106. if (values.homebase2) {
  107. profileData.user!.homebase2 = values.homebase2;
  108. }
  109. if (values.photo.uri) {
  110. profileData.photo = {
  111. type: values.photo.type,
  112. uri: values.photo.uri,
  113. name: values.photo.uri.split('/').pop()!
  114. };
  115. }
  116. updateProfile(profileData, {
  117. onSuccess: () => {
  118. queryClient.invalidateQueries({
  119. queryKey: userQueryKeys.getProfileData(),
  120. refetchType: 'all'
  121. });
  122. Image.clearDiskCache();
  123. Image.clearMemoryCache();
  124. navigation.goBack();
  125. }
  126. });
  127. }}
  128. >
  129. {(props) => (
  130. <View style={{ gap: 10 }}>
  131. <View style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  132. <AvatarPicker
  133. defaultAvatar={API_HOST + '/img/avatars/' + data.avatar}
  134. selectedAvatar={(asset) => props.setFieldValue('photo', asset)}
  135. />
  136. </View>
  137. <BigText>Account</BigText>
  138. <Input
  139. editable={false}
  140. header={"Username (can't edit)"}
  141. placeholder={'Text'}
  142. inputMode={'text'}
  143. onChange={props.handleChange('username')}
  144. value={props.values.username}
  145. onBlur={props.handleBlur('username')}
  146. formikError={props.touched.username && props.errors.username}
  147. />
  148. <Input
  149. editable={false}
  150. header={"Email address (can't edit)"}
  151. placeholder={'Email'}
  152. inputMode={'email'}
  153. onChange={props.handleChange('email')}
  154. value={props.values.email}
  155. onBlur={props.handleBlur('email')}
  156. formikError={props.touched.email && props.errors.email}
  157. />
  158. <BigText>General Info</BigText>
  159. <Input
  160. header={'First name'}
  161. placeholder={'Text'}
  162. inputMode={'text'}
  163. onChange={props.handleChange('first_name')}
  164. value={props.values.first_name}
  165. onBlur={props.handleBlur('first_name')}
  166. formikError={props.touched.first_name && props.errors.first_name}
  167. />
  168. <Input
  169. header={'Last name'}
  170. placeholder={'Text'}
  171. inputMode={'text'}
  172. onChange={props.handleChange('last_name')}
  173. value={props.values.last_name}
  174. onBlur={props.handleBlur('last_name')}
  175. formikError={props.touched.last_name && props.errors.last_name}
  176. />
  177. <InputDatePicker
  178. headerTitle={'Date of birth'}
  179. defaultDate={new Date(data.date_of_birth)}
  180. selectedDate={(date) => props.setFieldValue('date_of_birth', date)}
  181. formikError={props.touched.date_of_birth && props.errors.date_of_birth}
  182. />
  183. <ModalFlatList
  184. headerTitle={'Region of origin'}
  185. defaultObject={{ name: originRegion?.name }}
  186. selectedObject={(data) => props.setFieldValue('homebase', data.id)}
  187. />
  188. <ModalFlatList
  189. headerTitle={'Second region'}
  190. defaultObject={{ name: secondOrigin?.name }}
  191. selectedObject={(data) => props.setFieldValue('homebase2', data.id)}
  192. />
  193. <Input
  194. multiline={true}
  195. header={'Bio'}
  196. placeholder={'Text'}
  197. inputMode={'text'}
  198. onChange={props.handleChange('bio')}
  199. value={props.values.bio}
  200. onBlur={props.handleBlur('bio')}
  201. formikError={props.touched.bio && props.errors.bio}
  202. />
  203. <BigText>Links</BigText>
  204. <Input
  205. icon={<FacebookIcon />}
  206. placeholder={'https://www.facebook.com'}
  207. inputMode={'text'}
  208. onChange={props.handleChange('f')}
  209. value={props.values.f as unknown as string}
  210. onBlur={props.handleBlur('f')}
  211. formikError={props.touched.f && props.errors.f}
  212. />
  213. <Input
  214. icon={<InstagramIcon />}
  215. placeholder={'https://www.instagram.com'}
  216. inputMode={'text'}
  217. onChange={props.handleChange('i')}
  218. value={props.values.i as unknown as string}
  219. onBlur={props.handleBlur('i')}
  220. formikError={props.touched.i && props.errors.i}
  221. />
  222. <Input
  223. icon={<XIcon />}
  224. placeholder={'https://www.twitter.com'}
  225. inputMode={'text'}
  226. onChange={props.handleChange('t')}
  227. value={props.values.t as unknown as string}
  228. onBlur={props.handleBlur('t')}
  229. formikError={props.touched.t && props.errors.t}
  230. />
  231. <Input
  232. icon={<YoutubeIcon />}
  233. placeholder={'https://www.youtube.com'}
  234. inputMode={'text'}
  235. onChange={props.handleChange('y')}
  236. value={props.values.y as unknown as string}
  237. onBlur={props.handleBlur('y')}
  238. formikError={props.touched.y && props.errors.y}
  239. />
  240. <Input
  241. icon={<GlobeIcon fill={Colors.LIGHT_GRAY} />}
  242. placeholder={'My Website'}
  243. inputMode={'text'}
  244. onChange={props.handleChange('www')}
  245. value={props.values.www as unknown as string}
  246. onBlur={props.handleBlur('www')}
  247. formikError={props.touched.www && props.errors.www}
  248. />
  249. <Input
  250. icon={<LinkIcon />}
  251. placeholder={'Other link'}
  252. inputMode={'text'}
  253. onChange={props.handleChange('other')}
  254. value={props.values.other as unknown as string}
  255. onBlur={props.handleBlur('other')}
  256. formikError={props.touched.other && props.errors.other}
  257. />
  258. <View style={{ marginTop: 15, marginBottom: 15 }}>
  259. <Button onPress={props.handleSubmit}>Save</Button>
  260. </View>
  261. </View>
  262. )}
  263. </Formik>
  264. </KeyboardAwareScrollView>
  265. </ScrollView>
  266. </PageWrapper>
  267. );
  268. };