1- import { ref , uploadBytes } from '@firebase/storage' ;
1+ import { getDownloadURL , ref , uploadBytes } from '@firebase/storage' ;
22import { zodResolver } from '@hookform/resolvers/zod' ;
33import * as ImagePicker from 'expo-image-picker' ;
4- import { useRouter } from 'expo-router' ;
4+ import { useLocalSearchParams , useRouter } from 'expo-router' ;
55import {
66 collection ,
77 doc ,
88 getDocs ,
99 query ,
10+ serverTimestamp ,
1011 setDoc ,
12+ updateDoc ,
1113 where ,
1214} from 'firebase/firestore' ;
1315import { Upload } from 'lucide-react-native' ;
14- import { useState } from 'react' ;
16+ import { useEffect , useState } from 'react' ;
1517import { useForm } from 'react-hook-form' ;
1618import { Image , KeyboardAvoidingView } from 'react-native' ;
1719import * as z from 'zod' ;
1820
1921import { db , storage } from '@/api' ;
2022import { useAuth } from '@/core' ;
2123import { Button , ControlledInput , Header , ScreenContainer , View } from '@/ui' ;
24+
2225const profileSchema = z . object ( {
2326 displayName : z . string ( ) . min ( 2 , 'Display name is required' ) ,
2427 username : z . string ( ) . min ( 2 , 'Username is required' ) ,
@@ -29,10 +32,30 @@ type ProfileFormType = z.infer<typeof profileSchema>;
2932export default function CreateProfile ( ) {
3033 const router = useRouter ( ) ;
3134 const currentUid = useAuth . getState ( ) . user ?. uid ;
32- const defaultProfilePic = require ( '/assets/images/default_profile_pic.jpg ' ) ;
35+ const defaultProfilePic = require ( '/assets/images/default_profile_pic.png ' ) ;
3336 const [ profileImage , setProfileImage ] = useState < string | null > ( null ) ;
3437 const [ isUploading , setIsUploading ] = useState ( false ) ;
35- const [ isCreatingProfile , setIsCreatingProfile ] = useState ( false ) ;
38+ const [ isSubmiting , setIsSubmiting ] = useState ( false ) ;
39+
40+ const { mode } = useLocalSearchParams < {
41+ mode : 'edit' | 'create' ;
42+ } > ( ) ;
43+
44+ useEffect ( ( ) => {
45+ const fetchProfilePic = async ( ) => {
46+ if ( mode !== 'edit' || ! currentUid ) return ;
47+
48+ try {
49+ const profilePicRef = ref ( storage , `profilePics/${ currentUid } ` ) ;
50+ const url = await getDownloadURL ( profilePicRef ) ;
51+ setProfileImage ( url ) ;
52+ } catch ( error ) {
53+ console . log ( 'No profile image found, using default.' ) ;
54+ }
55+ } ;
56+
57+ fetchProfilePic ( ) ;
58+ } , [ mode , currentUid ] ) ;
3659
3760 const { handleSubmit, control, setError } = useForm < ProfileFormType > ( {
3861 resolver : zodResolver ( profileSchema ) ,
@@ -77,9 +100,9 @@ export default function CreateProfile() {
77100 }
78101 } ;
79102
80- const onSubmit = async ( data : ProfileFormType ) => {
81- setIsCreatingProfile ( true ) ;
103+ const createProfile = async ( data : ProfileFormType ) => {
82104 if ( ! currentUid ) return ;
105+ setIsSubmiting ( true ) ;
83106 try {
84107 // check if username taken
85108 const usernameQuery = query (
@@ -93,7 +116,7 @@ export default function CreateProfile() {
93116 type : 'custom' ,
94117 message : 'This username is already taken' ,
95118 } ) ;
96- setIsCreatingProfile ( false ) ;
119+ setIsSubmiting ( false ) ;
97120 return ;
98121 }
99122
@@ -103,21 +126,64 @@ export default function CreateProfile() {
103126 await setDoc ( userDocRef , {
104127 displayName : data . displayName ,
105128 username : data . username ,
106- createdAt : new Date ( ) . toLocaleDateString ( 'en-CA' ) ,
129+ createdAt : serverTimestamp ( ) ,
107130 } ) ;
108131
109132 // upload profile pic to storage
110133 await uploadProfileImage ( ) ;
111134
112135 router . push ( '/' ) ;
113136 } catch ( error ) {
114- console . error ( 'Error updating profile' , error ) ;
137+ console . error ( 'Error creating profile' , error ) ;
115138 setError ( 'root' , {
116139 type : 'custom' ,
117140 message : 'Something went wrong creating profile' ,
118141 } ) ;
119142 } finally {
120- setIsCreatingProfile ( false ) ;
143+ setIsSubmiting ( false ) ;
144+ }
145+ } ;
146+
147+ const editProfile = async ( data : ProfileFormType ) => {
148+ if ( ! currentUid ) return ;
149+ setIsSubmiting ( true ) ;
150+ try {
151+ // check if username taken
152+ const usernameQuery = query (
153+ collection ( db , 'users' ) ,
154+ where ( 'username' , '==' , data . username ) ,
155+ ) ;
156+ const usernameSnapshot = await getDocs ( usernameQuery ) ;
157+
158+ if ( ! usernameSnapshot . empty ) {
159+ setError ( 'username' , {
160+ type : 'custom' ,
161+ message : 'This username is already taken' ,
162+ } ) ;
163+ setIsSubmiting ( false ) ;
164+ return ;
165+ }
166+
167+ // update user document in firestore
168+ const userDocRef = doc ( db , 'users' , currentUid ) ;
169+
170+ await updateDoc ( userDocRef , {
171+ displayName : data . displayName ,
172+ username : data . username
173+ } ) ;
174+
175+ // update profile picture in storage
176+ await uploadProfileImage ( ) ;
177+
178+ router . push ( '/' ) ;
179+ } catch ( error ) {
180+ console . error ( 'Error updating profile' , error ) ;
181+ setError ( 'root' , {
182+ type : 'custom' ,
183+ message : 'Something went wrong updating profile' ,
184+ } ) ;
185+ } finally {
186+ setIsSubmiting ( false ) ;
121187 }
122188 } ;
123189
@@ -129,7 +195,9 @@ export default function CreateProfile() {
129195 keyboardVerticalOffset = { 10 }
130196 >
131197 < View className = "flex flex-1 flex-col gap-4" >
132- < Header title = "Create Profile" />
198+ < Header
199+ title = { mode === 'create' ? 'Create Profile' : 'Edit Profile' }
200+ />
133201
134202 < View className = "flex flex-row items-center gap-4 px-2" >
135203 < Image
@@ -158,9 +226,13 @@ export default function CreateProfile() {
158226 />
159227
160228 < Button
161- label = "Complete Profile"
162- loading = { isCreatingProfile }
163- onPress = { handleSubmit ( onSubmit ) }
229+ label = { mode === 'create' ? 'Complete Profile' : 'Save Changes' }
230+ loading = { isSubmiting }
231+ onPress = {
232+ mode === 'create'
233+ ? handleSubmit ( createProfile )
234+ : handleSubmit ( editProfile )
235+ }
164236 />
165237 </ View >
166238 </ KeyboardAvoidingView >
0 commit comments