1+ import React , { useEffect , useState } from 'react' ;
2+ import { useForm , SubmitHandler } from 'react-hook-form' ;
3+ import { useGetUserByIdQuery , useUpdateUserMutation } from '../../services/userApi' ;
4+ import Input from '../common/Input' ;
5+ import { useSelector } from 'react-redux' ;
6+
7+ export interface UserFormValues {
8+ firstName : string ;
9+ lastName : string ;
10+ phoneNumber : string ;
11+ email : string ;
12+ photoUrl ?: any ;
13+ }
14+
15+ const Profile : React . FC = ( ) => {
16+ const [ isEditing , setIsEditing ] = useState ( false ) ;
17+ const [ showSuccessMessage , setShowSuccessMessage ] = useState ( false ) ;
18+ const id = useSelector ( ( state : any ) => state . user . userId ) ;
19+
20+ const { data } = useGetUserByIdQuery ( id ) ;
21+ const [ userData , setUserData ] = useState ( data ?. message ) ;
22+
23+ const {
24+ register,
25+ handleSubmit,
26+ setValue,
27+ formState : { errors, isSubmitting } ,
28+ } = useForm < UserFormValues > ( ) ;
29+
30+ useEffect ( ( ) => {
31+ if ( data ?. message ) {
32+ setUserData ( data . message ) ;
33+ }
34+ } , [ data ] ) ;
35+
36+ useEffect ( ( ) => {
37+ if ( userData ) {
38+ setValue ( 'firstName' , userData . firstName ) ;
39+ setValue ( 'lastName' , userData . lastName ) ;
40+ setValue ( 'email' , userData . email ) ;
41+ setValue ( 'phoneNumber' , userData . phoneNumber ) ;
42+ }
43+ } , [ userData , setValue ] ) ;
44+
45+ const [ updateUser , { isLoading, isError, error } ] = useUpdateUserMutation ( ) ;
46+
47+ const onSubmit : SubmitHandler < UserFormValues > = async data => {
48+ const formData = new FormData ( ) ;
49+ formData . append ( 'firstName' , data . firstName ) ;
50+ formData . append ( 'lastName' , data . lastName ) ;
51+ formData . append ( 'phoneNumber' , data . phoneNumber ) ;
52+ formData . append ( 'email' , data . email ) ;
53+ formData . append ( 'profileImage' , data . photoUrl [ 0 ] ) ;
54+
55+
56+ try {
57+ const response = await updateUser ( formData ) . unwrap ( ) ;
58+ setUserData ( response . message ) ;
59+ setIsEditing ( false ) ;
60+ setShowSuccessMessage ( true ) ;
61+ setTimeout ( ( ) => setShowSuccessMessage ( false ) , 3000 ) ;
62+ } catch ( err ) {
63+ console . error ( 'Failed to update profile:' , err ) ;
64+ }
65+ } ;
66+
67+ const getErrorMessage = ( error : any ) => {
68+ if ( 'data' in error ) {
69+ return error . data ?. message || 'Error updating profile' ;
70+ } else {
71+ return 'An unexpected error occurred' ;
72+ }
73+ } ;
74+
75+ return (
76+ < div className = 'container mx-auto px-4' >
77+ < div className = 'flex flex-col items-center' >
78+ { showSuccessMessage && (
79+ < div className = 'w-full md:w-7/12 xl:w-4/12 bg-[#38a169] text-[#ffffff] p-4 rounded-lg mb-6 text-center' >
80+ Profile updated successfully!
81+ </ div >
82+ ) }
83+ < h1 className = 'text-2xl font-bold my-6 text-[#000000]' > My Profile</ h1 >
84+ < div className = 'w-full md:w-7/12 xl:w-4/12 border border-[#d1d5db] p-4 rounded-lg shadow-md mb-6' >
85+ < div className = 'flex items-center justify-between' >
86+ < div className = 'flex items-center' >
87+ < img
88+ className = 'h-20 w-20 rounded-full'
89+ src = { userData ?. photoUrl || '/default-profile.png' }
90+ alt = { userData ?. firstName }
91+ />
92+ < div className = 'ml-4' >
93+ < div className = 'text-xl font-medium text-[#000000]' >
94+ { userData ?. firstName } { userData ?. lastName }
95+ </ div >
96+ < p className = 'text-[#6b7280] font-light mt-1' > { userData ?. role } </ p >
97+ </ div >
98+ </ div >
99+ < button
100+ type = 'button'
101+ className = 'p-2 rounded-lg bg-[#d1d5db] hover:bg-[#9ca3af] transition-all text-[#000000] font-bold'
102+ onClick = { ( ) => setIsEditing ( true ) }
103+ >
104+ Edit
105+ </ button >
106+ </ div >
107+ </ div >
108+ { isEditing && (
109+ < div className = 'w-full md:w-7/12 xl:w-4/12 border border-[#d1d5db] rounded-xl p-8 shadow-md' >
110+ < h2 className = 'text-lg font-semibold mb-4 text-[#000000]' > Personal Information</ h2 >
111+ { isError && error && (
112+ < p className = 'text-lg bg-[#f56565] text-[#ffffff] mt-4 py-2 rounded-lg px-3' > { getErrorMessage ( error ) } </ p >
113+ ) }
114+ < form onSubmit = { handleSubmit ( onSubmit ) } className = 'space-y-6' >
115+ < div >
116+ < label className = 'block text-sm font-medium text-[#000000]' > Profile Picture</ label >
117+ < input type = 'file' accept = 'image/*' className = 'mt-2' { ...register ( 'photoUrl' ) } />
118+ </ div >
119+ < div className = 'grid grid-cols-2 gap-4' >
120+ < div className = 'text-[#000000]' >
121+ < Input
122+ id = 'firstName'
123+ label = 'First Name'
124+ type = 'text'
125+ placeholder = 'Enter first name'
126+ { ...register ( 'firstName' ) }
127+ error = { errors ?. firstName ?. message }
128+ />
129+ </ div >
130+ < div className = 'text-[#000000]' >
131+ < Input
132+ id = 'lastName'
133+ label = 'Last Name'
134+ type = 'text'
135+ placeholder = 'Enter last name'
136+ { ...register ( 'lastName' ) }
137+ error = { errors ?. lastName ?. message }
138+ />
139+ </ div >
140+ </ div >
141+ < div className = 'text-[#000000]' >
142+ < Input
143+ id = 'phoneNumber'
144+ label = 'Contact Number'
145+ type = 'tel'
146+ placeholder = 'Enter your contact number'
147+ { ...register ( 'phoneNumber' ) }
148+ error = { errors ?. phoneNumber ?. message }
149+ />
150+ </ div >
151+ < div className = 'text-[#000000]' >
152+ < Input
153+ id = 'email'
154+ label = 'Email'
155+ type = 'email'
156+ disabled
157+ placeholder = 'Enter your email'
158+ { ...register ( 'email' ) }
159+ error = { errors ?. email ?. message }
160+ />
161+ </ div >
162+ < div className = 'flex justify-between gap-4' >
163+ < button
164+ type = 'submit'
165+ className = 'p-2 rounded-lg bg-[#38a169] hover:bg-[#2f855a] transition-all text-[#ffffff] font-bold'
166+ disabled = { isSubmitting || isLoading }
167+ >
168+ { isSubmitting || isLoading ? 'Loading...' : 'Save' }
169+ </ button >
170+ < button
171+ type = 'button'
172+ onClick = { ( ) => setIsEditing ( false ) }
173+ className = 'p-2 rounded-lg bg-[#d1d5db] hover:border-[#38a169] transition-all text-[#000000]'
174+ >
175+ Cancel
176+ </ button >
177+ </ div >
178+ </ form >
179+ </ div >
180+ ) }
181+ </ div >
182+ </ div >
183+ ) ;
184+ } ;
185+
186+ export default Profile ;
0 commit comments