1
- import { SubmitButton , YStack , isWeb , useToastController , XStack , Button , H1 } from '@my/ui'
1
+ import {
2
+ SubmitButton ,
3
+ YStack ,
4
+ isWeb ,
5
+ useToastController ,
6
+ XStack ,
7
+ Button ,
8
+ Text ,
9
+ Paragraph ,
10
+ } from '@my/ui'
2
11
import { SchemaForm } from 'app/utils/SchemaForm'
3
12
import { useSupabase } from 'app/utils/supabase/useSupabase'
4
13
import { useUser } from 'app/utils/useUser'
@@ -7,89 +16,139 @@ import type { z } from 'zod'
7
16
import { FormProvider , useForm } from 'react-hook-form'
8
17
import { VerifyCode } from 'app/features/auth/components/VerifyCode'
9
18
import { AuthUserSchema , useAuthUserMutation } from 'app/utils/useAuthUserMutation'
19
+ import { useEffect , useState } from 'react'
20
+ import { useProfileMutation } from 'app/utils/useUserPersonalDataMutation'
21
+
22
+ enum FormState {
23
+ PersonalInfoForm = 'PersonalInfoForm' ,
24
+ VerificationCode = 'VerificationCode' ,
25
+ }
10
26
11
27
export const PersonalInfoScreen = ( ) => {
12
- const { user } = useUser ( )
28
+ const { user, profile } = useUser ( )
29
+
13
30
const supabase = useSupabase ( )
14
31
const toast = useToastController ( )
15
32
const router = useRouter ( )
16
33
const form = useForm < z . infer < typeof AuthUserSchema > > ( ) // Using react-hook-form
17
- const mutation = useAuthUserMutation ( )
34
+ const { mutateAsync : mutateAuthAsync } = useAuthUserMutation ( )
35
+ const { mutateAsync : mutateProfileAsync } = useProfileMutation ( )
36
+ const [ formState , setFormState ] = useState < FormState > ( FormState . PersonalInfoForm )
37
+ const [ errorMessage , setErrorMessage ] = useState < string | null > ( null )
38
+
39
+ function handleSuccessAuthUpdate ( ) {
40
+ setFormState ( FormState . VerificationCode )
41
+ }
42
+
43
+ async function handleSubmit ( ) {
44
+ setErrorMessage ( null )
45
+ const values = form . getValues ( )
46
+
47
+ try {
48
+ if ( profile && profile . x_username !== values . xUsername ) {
49
+ await mutateProfileAsync ( values )
50
+ }
51
+
52
+ if ( user && user . phone !== values . phone ) {
53
+ await mutateAuthAsync ( values )
54
+ handleSuccessAuthUpdate ( )
55
+ }
56
+ } catch ( error ) {
57
+ console . error ( error )
18
58
19
- if ( mutation . isError ) {
20
- form . setError ( 'phone' , { type : 'custom' , message : mutation . error . message } )
59
+ if ( error ?. message ) {
60
+ setErrorMessage ( error . message )
61
+ }
62
+ }
21
63
}
22
64
65
+ useEffect ( ( ) => {
66
+ form . reset ( { phone : user ?. phone ?? '' , xUsername : profile ?. x_username ?? '' } )
67
+ } , [ profile ?. x_username , user ?. phone , form . reset ] )
68
+
69
+ const verificationCode = (
70
+ < VerifyCode
71
+ type = { 'phone_change' }
72
+ phone = { form . getValues ( ) . phone }
73
+ onSuccess = { async ( ) => {
74
+ toast . show ( 'Phone number updated' )
75
+ router . back ( )
76
+ if ( ! isWeb ) {
77
+ await supabase . auth . refreshSession ( )
78
+ }
79
+ } }
80
+ />
81
+ )
82
+
83
+ const personalInfoForm = (
84
+ < SchemaForm
85
+ form = { form }
86
+ schema = { AuthUserSchema }
87
+ onSubmit = { handleSubmit }
88
+ props = { {
89
+ phone : {
90
+ 'aria-label' : 'Phone number' ,
91
+ autoComplete : 'tel' ,
92
+ keyboardType : 'phone-pad' ,
93
+ autoCapitalize : 'none' ,
94
+ bc : '$color0' ,
95
+ labelProps : {
96
+ color : '$color10' ,
97
+ } ,
98
+ } ,
99
+ xUsername : {
100
+ 'aria-label' : 'X username' ,
101
+ labelProps : {
102
+ color : '$color10' ,
103
+ } ,
104
+ bc : '$color0' ,
105
+ pl : '$8' ,
106
+ iconBefore : (
107
+ < Text color = "$color10" userSelect = { 'none' } lineHeight = { 8 } >
108
+ @
109
+ </ Text >
110
+ ) ,
111
+ } ,
112
+ } }
113
+ renderAfter = { ( { submit } ) => (
114
+ < YStack ai = { 'flex-start' } >
115
+ < SubmitButton
116
+ f = { 1 }
117
+ marginTop = { '$5' }
118
+ fontWeight = { '500' }
119
+ onPress = { ( ) => submit ( ) }
120
+ theme = "green"
121
+ borderRadius = { '$3' }
122
+ px = { '$size.1.5' }
123
+ >
124
+ < Button . Text ff = { '$mono' } fontWeight = { '600' } tt = "uppercase" size = { '$5' } >
125
+ SAVE
126
+ </ Button . Text >
127
+ </ SubmitButton >
128
+ { errorMessage && (
129
+ < Paragraph marginTop = { '$5' } theme = "red" color = "$color9" >
130
+ { errorMessage }
131
+ </ Paragraph >
132
+ ) }
133
+ </ YStack >
134
+ ) }
135
+ >
136
+ { ( fields ) => < > { Object . values ( fields ) } </ > }
137
+ </ SchemaForm >
138
+ )
139
+
23
140
return (
24
141
< YStack w = { '100%' } als = { 'center' } >
25
- < XStack w = { '100%' } >
26
- < H1 size = { '$9' } fontWeight = { '600' } color = "$color12" >
27
- Personal Information
28
- </ H1 >
29
- </ XStack >
30
142
< XStack w = { '100%' } $gtLg = { { paddingTop : '$6' } } $lg = { { jc : 'center' } } >
31
143
< FormProvider { ...form } >
32
- { form . formState . isSubmitSuccessful ? (
33
- < VerifyCode
34
- type = { 'phone_change' }
35
- phone = { form . getValues ( ) . phone }
36
- onSuccess = { async ( ) => {
37
- toast . show ( 'Phone number updated' )
38
- router . back ( )
39
- if ( ! isWeb ) {
40
- await supabase . auth . refreshSession ( )
41
- }
42
- } }
43
- />
44
- ) : (
45
- < SchemaForm
46
- form = { form }
47
- schema = { AuthUserSchema }
48
- onSubmit = { ( values ) => mutation . mutate ( values ) }
49
- props = { {
50
- phone : {
51
- 'aria-label' : 'Phone number' ,
52
- autoComplete : 'tel' ,
53
- keyboardType : 'phone-pad' ,
54
- autoCapitalize : 'none' ,
55
- bc : '$color0' ,
56
- labelProps : {
57
- color : '$color10' ,
58
- } ,
59
- } ,
60
- // email: {
61
- // 'aria-label': 'Email',
62
- // },
63
- // address: {
64
- // 'aria-label': 'Address',
65
- // },
66
- } }
67
- defaultValues = { {
68
- phone : user ?. phone ?? '' ,
69
- // email: user?.email ?? '',
70
- // address: '',
71
- } }
72
- renderAfter = { ( { submit } ) => (
73
- < YStack ai = { 'flex-start' } >
74
- < SubmitButton
75
- f = { 1 }
76
- marginTop = { '$5' }
77
- fontWeight = { '500' }
78
- onPress = { ( ) => submit ( ) }
79
- theme = "green"
80
- borderRadius = { '$3' }
81
- px = { '$size.1.5' }
82
- >
83
- < Button . Text ff = { '$mono' } fontWeight = { '600' } tt = "uppercase" size = { '$5' } >
84
- SAVE
85
- </ Button . Text >
86
- </ SubmitButton >
87
- </ YStack >
88
- ) }
89
- >
90
- { ( fields ) => < > { Object . values ( fields ) } </ > }
91
- </ SchemaForm >
92
- ) }
144
+ { ( ( ) => {
145
+ switch ( formState ) {
146
+ case FormState . PersonalInfoForm :
147
+ return personalInfoForm
148
+ case FormState . VerificationCode :
149
+ return verificationCode
150
+ }
151
+ } ) ( ) }
93
152
</ FormProvider >
94
153
</ XStack >
95
154
</ YStack >
0 commit comments