@@ -10,27 +10,33 @@ import { ArrowLeft } from "lucide-react";
1010export default function EditProjectPage ( ) {
1111 const router = useRouter ( ) ;
1212 const params = useParams ( ) ;
13- const projectId = params ?. projectId ;
13+
14+ const projectId =
15+ typeof params ?. projectId === "string" ? params . projectId : undefined ;
1416
1517 const [ userToken , setUserToken ] = useState < string | null > ( null ) ;
1618 const [ categories , setCategories ] = useState < Category [ ] > ( [ ] ) ;
1719 const [ project , setProject ] = useState < Project | null > ( null ) ;
1820 const [ loading , setLoading ] = useState ( true ) ;
1921 const [ error , setError ] = useState < string | null > ( null ) ;
2022
23+ /* ------------------ AUTH ------------------ */
2124 useEffect ( ( ) => {
2225 const unsubscribe = onAuthStateChanged ( auth , async ( user ) => {
23- if ( user ) {
24- const token = await user . getIdToken ( ) ;
25- setUserToken ( token ) ;
26- } else {
26+ if ( ! user ) {
2727 setError ( "You must be logged in to edit projects." ) ;
2828 setLoading ( false ) ;
29+ return ;
2930 }
31+
32+ const token = await user . getIdToken ( ) ;
33+ setUserToken ( token ) ;
3034 } ) ;
35+
3136 return ( ) => unsubscribe ( ) ;
3237 } , [ ] ) ;
3338
39+ /* ------------------ FETCH DATA ------------------ */
3440 useEffect ( ( ) => {
3541 if ( ! userToken || ! projectId ) return ;
3642
@@ -43,30 +49,36 @@ export default function EditProjectPage() {
4349 } ) ,
4450 ] ) ;
4551
46- if ( ! catRes . ok || ! projRes . ok ) throw new Error ( "Failed to fetch data" ) ;
52+ if ( ! catRes . ok || ! projRes . ok ) {
53+ throw new Error ( "Failed to fetch data" ) ;
54+ }
4755
48- const categoriesData = await catRes . json ( ) ;
56+ const categoriesData : Category [ ] = await catRes . json ( ) ;
4957 const projectData = await projRes . json ( ) ;
5058
5159 const selectedCategoryOptions : Record < string , string > = { } ;
52- categoriesData . forEach ( ( category : Category ) => {
53- const normalizedCategoryName = category . categoryName
54- . trim ( )
55- . toLowerCase ( ) ;
60+
61+ categoriesData . forEach ( ( category ) => {
5662 const matched = projectData . categories ?. find (
5763 ( c : any ) =>
58- c . categoryName . trim ( ) . toLowerCase ( ) === normalizedCategoryName
64+ c . categoryName . trim ( ) . toLowerCase ( ) ===
65+ category . categoryName . trim ( ) . toLowerCase ( )
5966 ) ;
67+
6068 selectedCategoryOptions [ category . categoryName ] =
6169 matched ?. optionName || "" ;
6270 } ) ;
6371
6472 setCategories ( categoriesData ) ;
73+
6574 setProject ( {
6675 ...projectData ,
6776 createdAt : projectData . createdAt . split ( "T" ) [ 0 ] ,
6877 selectedCategoryOptions,
69- members : projectData . members ?. slice ( 0 , 1 ) || [ { name : "" , linkedin : "" } ] ,
78+ members :
79+ projectData . members ?. slice ( 0 , 1 ) || [
80+ { name : "" , linkedin : "" } ,
81+ ] ,
7082 } ) ;
7183 } catch ( err : any ) {
7284 setError ( err . message ) ;
@@ -78,12 +90,14 @@ export default function EditProjectPage() {
7890 fetchData ( ) ;
7991 } , [ userToken , projectId ] ) ;
8092
93+ /* ------------------ HANDLE CHANGE ------------------ */
8194 const handleChange = (
8295 e : React . ChangeEvent <
8396 HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
8497 >
8598 ) => {
8699 if ( ! project ) return ;
100+
87101 const { name, value } = e . target ;
88102
89103 if ( name . startsWith ( "category-" ) ) {
@@ -100,11 +114,20 @@ export default function EditProjectPage() {
100114 ...project ,
101115 members : [ { ...project . members [ 0 ] , name : value } ] ,
102116 } ) ;
117+ } else if ( name === "contactLinkedIn" ) {
118+ setProject ( {
119+ ...project ,
120+ members : [ { ...project . members [ 0 ] , linkedin : value } ] ,
121+ } ) ;
103122 } else {
104- setProject ( { ...project , [ name ] : value } ) ;
123+ setProject ( {
124+ ...project ,
125+ [ name ] : value ,
126+ } ) ;
105127 }
106128 } ;
107129
130+ /* ------------------ SUBMIT ------------------ */
108131 const handleSubmit = async ( e : React . FormEvent ) => {
109132 e . preventDefault ( ) ;
110133 if ( ! project || ! userToken ) return ;
@@ -128,181 +151,134 @@ export default function EditProjectPage() {
128151 } ,
129152 body : JSON . stringify ( payload ) ,
130153 } ) ;
154+
131155 if ( ! res . ok ) throw new Error ( "Failed to update project" ) ;
156+
132157 router . push ( "/profile" ) ;
133158 } catch ( err : any ) {
134159 setError ( err . message ) ;
135160 }
136161 } ;
137162
138- if ( loading )
163+ /* ------------------ UI STATES ------------------ */
164+ if ( loading ) {
139165 return (
140166 < div className = "min-h-screen flex items-center justify-center bg-white" >
141167 < div className = "text-center" >
142- < div className = "w-12 h-12 border-4 border-blue-300 border-t-blue-600 rounded-full animate-spin mx-auto" > </ div >
168+ < div className = "w-12 h-12 border-4 border-blue-300 border-t-blue-600 rounded-full animate-spin mx-auto" / >
143169 < p className = "mt-4 text-blue-700 font-medium" >
144170 Loading your project...
145171 </ p >
146172 </ div >
147173 </ div >
148174 ) ;
175+ }
176+
177+ if ( error ) {
178+ return < div className = "p-8 text-red-600 text-center" > { error } </ div > ;
179+ }
149180
150- if ( error ) return < div className = "p-8 text-red-600 text-center" > { error } </ div > ;
151- if ( ! project ) return < div className = "p-8 text-center" > Project not found</ div > ;
181+ if ( ! project ) {
182+ return < div className = "p-8 text-center" > Project not found</ div > ;
183+ }
152184
185+ /* ------------------ FORM ------------------ */
153186 return (
154187 < div className = "min-h-screen bg-gradient-to-br from-blue-50 to-white flex items-center justify-center p-4" >
155188 < div className = "bg-white p-6 rounded-2xl shadow-xl max-w-3xl w-full max-h-[90vh] overflow-y-auto" >
156- { /* Back Button */ }
157189 < button
158190 onClick = { ( ) => router . push ( "/profile" ) }
159- className = "flex items-center text-blue-600 hover:text-blue-800 transition-colors duration-200 mb-4"
191+ className = "flex items-center text-blue-600 hover:text-blue-800 mb-4"
160192 >
161193 < ArrowLeft className = "w-5 h-5 mr-2" />
162- < span className = "font-medium" > Back to Profile</ span >
194+ Back to Profile
163195 </ button >
164196
165- < h2 className = "text-2xl font-bold mb-4 text-center text-blue-700" > Edit Project</ h2 >
197+ < h2 className = "text-2xl font-bold mb-4 text-center text-blue-700" >
198+ Edit Project
199+ </ h2 >
200+
166201 < form onSubmit = { handleSubmit } className = "space-y-4" >
167- { /* Project Name */ }
168- < div >
169- < label className = "block text-sm font-medium text-gray-700" >
170- Project Name
171- </ label >
172- < input
173- type = "text"
174- name = "projectName"
175- value = { project . projectName }
176- onChange = { handleChange }
177- required
178- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
179- />
180- </ div >
181-
182- { /* Project Description */ }
183- < div >
184- < label className = "block text-sm font-medium text-gray-700" >
185- Project Description
186- </ label >
187- < textarea
188- name = "projectDescription"
189- value = { project . projectDescription || "" }
190- onChange = { handleChange }
191- rows = { 3 }
192- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
193- />
194- </ div >
195-
196- { /* Single Member */ }
197- < div >
198- < label className = "block text-sm font-medium text-gray-700" >
199- Owner Name
200- </ label >
201- < input
202- type = "text"
203- name = "memberName"
204- value = { project . members [ 0 ] . name }
205- onChange = { handleChange }
206- required
207- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
208- />
209- </ div >
210-
211- { /* LinkedIn */ }
212- < div >
213- < label htmlFor = "contactLinkedIn" className = "block text-sm font-medium text-gray-700" >
214- LinkedIn
215- </ label >
216- < input
217- type = "text"
218- id = "contactLinkedIn"
219- name = "contactLinkedIn"
220- value = { project . members [ 0 ] . linkedin || "" }
221- onChange = { handleChange }
222- className = "mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2"
223- placeholder = "LinkedIn profile link"
224- />
225- </ div >
226-
227- { /* Project Link */ }
228- < div >
229- < label className = "block text-sm font-medium text-gray-700" >
230- Project Link
231- </ label >
232- < input
233- type = "url"
234- name = "projectLink"
235- value = { project . projectLink || "" }
236- onChange = { handleChange }
237- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
238- />
239- </ div >
240-
241- { /* Created At */ }
242- < div >
243- < label className = "block text-sm font-medium text-gray-700" >
244- Created At
245- </ label >
246- < input
247- type = "date"
248- name = "createdAt"
249- value = { project . createdAt }
250- onChange = { handleChange }
251- required
252- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
253- />
254- </ div >
202+ < input
203+ name = "projectName"
204+ value = { project . projectName }
205+ onChange = { handleChange }
206+ required
207+ className = "w-full border p-2 rounded"
208+ placeholder = "Project Name"
209+ />
210+
211+ < textarea
212+ name = "projectDescription"
213+ value = { project . projectDescription }
214+ onChange = { handleChange }
215+ rows = { 3 }
216+ className = "w-full border p-2 rounded"
217+ placeholder = "Description"
218+ />
219+
220+ < input
221+ name = "memberName"
222+ value = { project . members [ 0 ] . name }
223+ onChange = { handleChange }
224+ required
225+ className = "w-full border p-2 rounded"
226+ placeholder = "Owner Name"
227+ />
228+
229+ < input
230+ name = "contactLinkedIn"
231+ value = { project . members [ 0 ] . linkedin }
232+ onChange = { handleChange }
233+ className = "w-full border p-2 rounded"
234+ placeholder = "LinkedIn URL"
235+ />
236+
237+ < input
238+ name = "projectLink"
239+ value = { project . projectLink }
240+ onChange = { handleChange }
241+ className = "w-full border p-2 rounded"
242+ placeholder = "Project Link"
243+ />
244+
245+ < input
246+ type = "date"
247+ name = "createdAt"
248+ value = { project . createdAt }
249+ onChange = { handleChange }
250+ required
251+ className = "w-full border p-2 rounded"
252+ />
255253
256- { /* Categories */ }
257254 { categories . map ( ( category ) => (
258- < div key = { category . categoryId } >
259- < label className = "block text-sm font-medium text-gray-700" >
260- { category . categoryName }
261- </ label >
262- < select
263- name = { `category-${ category . categoryName } ` }
264- value = { project . selectedCategoryOptions [ category . categoryName ] || "" }
265- onChange = { handleChange }
266- required
267- className = "mt-1 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
268- >
269- < option value = "" > Select a { category . categoryName } </ option >
270- { category . options . map ( ( opt ) => (
271- < option key = { opt . optionId } value = { opt . optionName } >
272- { opt . optionName }
273- </ option >
274- ) ) }
275- </ select >
276- { category . categoryName === "Domain" &&
277- project . selectedCategoryOptions [ "Domain" ] === "Other" && (
278- < input
279- type = "text"
280- name = "customDomain"
281- value = { project . customDomain || "" }
282- onChange = { handleChange }
283- placeholder = "Enter custom domain"
284- required
285- className = "mt-2 block w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
286- />
287- ) }
288- </ div >
255+ < select
256+ key = { category . categoryId }
257+ name = { `category-${ category . categoryName } ` }
258+ value = {
259+ project . selectedCategoryOptions [ category . categoryName ] || ""
260+ }
261+ onChange = { handleChange }
262+ required
263+ className = "w-full border p-2 rounded"
264+ >
265+ < option value = "" >
266+ Select { category . categoryName }
267+ </ option >
268+ { category . options . map ( ( opt ) => (
269+ < option key = { opt . optionId } value = { opt . optionName } >
270+ { opt . optionName }
271+ </ option >
272+ ) ) }
273+ </ select >
289274 ) ) }
290275
291- < div className = "flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-4 mt-6" >
292- < button
293- type = "button"
294- onClick = { ( ) => router . push ( "/profile" ) }
295- className = "bg-gray-300 text-gray-800 px-4 py-2 rounded-md hover:bg-gray-400 w-full sm:w-auto"
296- >
297- Cancel
298- </ button >
299- < button
300- type = "submit"
301- className = "bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700"
302- >
303- Save Changes
304- </ button >
305- </ div >
276+ < button
277+ type = "submit"
278+ className = "bg-blue-600 text-white px-4 py-2 rounded w-full"
279+ >
280+ Save Changes
281+ </ button >
306282 </ form >
307283 </ div >
308284 </ div >
0 commit comments