@@ -5,7 +5,13 @@ import { ArrowLeft, Save, XCircle } from "lucide-react";
55import Link from "next/link" ;
66
77const submissionYears = [ 2025 , 2024 , 2023 , 2022 , 2021 ] ;
8- const projectTypes = [ "Final Year Project" , "Mini Project" , "Research Project" , "Personal Project" , "Others" ] ;
8+ const projectTypes = [
9+ "Final Year Project" ,
10+ "Mini Project" ,
11+ "Research Project" ,
12+ "Personal Project" ,
13+ "Others"
14+ ] ;
915const departments = [ "CSE" , "IT" , "ECE" , "EEE" , "MECH" , "CIVIL" , "Other" ] ;
1016const availableDomains = [
1117 "Other" ,
@@ -83,55 +89,70 @@ const AddProjectPage = () => {
8389 projectName : "" ,
8490 projectDescription : "" ,
8591 yearOfSubmission : "2025" ,
86- projectType : "Personal Project " ,
92+ projectType : "Personal project " ,
8793 department : "" ,
8894 domain : "Web Development" ,
8995 customDomain : "" ,
9096 projectLink : "" ,
91- members : [ { name : "" , linkedin : "" } ] ,
97+ members : [ { name : "" , linkedin : "" } ]
9298 } ;
9399
94100 const [ formData , setFormData ] = useState ( initialFormState ) ;
95- const [ loading , setLoading ] = useState ( false ) ; // Prevents duplicate submissions
96- const [ showPopup , setShowPopup ] = useState ( false ) ;
101+ const [ showPopup , setShowPopup ] = useState ( false ) ; // State for pop-up visibility
102+ const [ loading , setLoading ] = useState ( false ) ; // Loading state to prevent duplicate submissions
97103
98104 const handleSubmit = async ( e : React . FormEvent ) => {
99105 e . preventDefault ( ) ;
100106 if ( loading ) return ; // Prevent multiple submissions
101- setLoading ( true ) ;
102107
103- const hasValidMember = formData . members . some ( member => member . name . trim ( ) !== "" ) ;
108+ // Ensure at least one member has a name
109+ const hasValidMember = formData . members . some (
110+ ( member ) => member . name . trim ( ) !== ""
111+ ) ;
104112 if ( ! hasValidMember ) {
105113 alert ( "Please enter at least one member name." ) ;
106- setLoading ( false ) ;
107114 return ;
108115 }
109116
110- const filteredMembers = formData . members . filter ( member => member . name . trim ( ) !== "" ) ;
111- const projectData = { ...formData , members : filteredMembers , createdAt : new Date ( ) . toISOString ( ) } ;
117+ setLoading ( true ) ; // Begin submission
118+
119+ // Filter out empty members
120+ const filteredMembers = formData . members . filter (
121+ ( member ) => member . name . trim ( ) !== ""
122+ ) ;
123+
124+ const projectData = {
125+ ...formData ,
126+ members : filteredMembers ,
127+ createdAt : new Date ( ) . toISOString ( )
128+ } ;
112129
113130 try {
114131 const response = await fetch ( "/api/saveProject" , {
115132 method : "POST" ,
116133 headers : { "Content-Type" : "application/json" } ,
117- body : JSON . stringify ( projectData ) ,
134+ body : JSON . stringify ( projectData )
118135 } ) ;
119136
120137 if ( response . ok ) {
121138 setFormData ( initialFormState ) ;
122- setShowPopup ( true ) ;
123- setTimeout ( ( ) => setShowPopup ( false ) , 3000 ) ;
139+ setShowPopup ( true ) ; // Show the congratulatory pop-up
140+ setTimeout ( ( ) => setShowPopup ( false ) , 3000 ) ; // Hide it after 3 seconds
124141 } else {
125142 alert ( "Failed to save project." ) ;
126143 }
127144 } catch ( error ) {
128145 console . error ( "Error saving project:" , error ) ;
129146 } finally {
130- setLoading ( false ) ; // Re-enable button
147+ setLoading ( false ) ; // End submission
131148 }
132149 } ;
133150
134- const handleChange = ( e : React . ChangeEvent < HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement > ) => {
151+ const handleChange = (
152+ e : React . ChangeEvent <
153+ HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
154+ >
155+ ) => {
135156 const { name, value } = e . target ;
136157 setFormData ( ( prev ) => ( { ...prev , [ name ] : value } ) ) ;
137158 } ;
@@ -143,7 +164,10 @@ const AddProjectPage = () => {
143164 } ;
144165
145166 const addMember = ( ) => {
146- setFormData ( { ...formData , members : [ ...formData . members , { name : "" , linkedin : "" } ] } ) ;
167+ setFormData ( {
168+ ...formData ,
169+ members : [ ...formData . members , { name : "" , linkedin : "" } ]
170+ } ) ;
147171 } ;
148172
149173 const removeMember = ( index : number ) => {
@@ -166,49 +190,194 @@ const AddProjectPage = () => {
166190 </ div >
167191 </ div >
168192
193+ { /* Pop-up Message */ }
169194 { showPopup && (
170- < div className = "fixed top-20 left-1/2 transform -translate-x-1/2 bg-green-500 text-white px-6 py-3 rounded-lg text-lg font-bold" >
171- 🎉 Project saved successfully! 🎉
195+ < div
196+ style = { {
197+ position : "fixed" ,
198+ top : "20%" ,
199+ left : "50%" ,
200+ transform : "translateX(-50%)" ,
201+ backgroundColor : "#4CAF50" ,
202+ color : "white" ,
203+ padding : "20px" ,
204+ borderRadius : "10px" ,
205+ fontSize : "20px" ,
206+ fontWeight : "bold" ,
207+ animation : "popIn 0.6s ease-in-out"
208+ } }
209+ >
210+ 🎉 Congratulations! Your project was saved successfully! 🎉
172211 </ div >
173212 ) }
174213
175214 < div className = "max-w-3xl mx-auto px-4 py-8" >
176- < form onSubmit = { handleSubmit } className = "bg-white rounded-xl shadow-lg p-6 space-y-6" >
177- < input type = "text" name = "projectName" required className = "w-full px-4 py-2 border rounded-lg" placeholder = "Project Name" onChange = { handleChange } value = { formData . projectName } />
178- < textarea name = "projectDescription" required rows = { 4 } className = "w-full px-4 py-2 border rounded-lg" placeholder = "Project Description" onChange = { handleChange } value = { formData . projectDescription } />
179- < select name = "yearOfSubmission" required className = "w-full px-4 py-2 border rounded-lg" onChange = { handleChange } value = { formData . yearOfSubmission } >
180- { submissionYears . map ( ( year ) => ( < option key = { year } value = { year } > { year } </ option > ) ) }
215+ < form
216+ onSubmit = { handleSubmit }
217+ className = "bg-white rounded-xl shadow-lg p-6 space-y-6"
218+ >
219+ < input
220+ type = "text"
221+ name = "projectName"
222+ required
223+ className = "w-full px-4 py-2 border rounded-lg"
224+ placeholder = "Project Name"
225+ onChange = { handleChange }
226+ value = { formData . projectName }
227+ />
228+ < textarea
229+ name = "projectDescription"
230+ required
231+ rows = { 4 }
232+ className = "w-full px-4 py-2 border rounded-lg"
233+ placeholder = "Project Description"
234+ onChange = { handleChange }
235+ value = { formData . projectDescription }
236+ />
237+ < select
238+ name = "yearOfSubmission"
239+ required
240+ className = "w-full px-4 py-2 border rounded-lg"
241+ onChange = { handleChange }
242+ value = { formData . yearOfSubmission }
243+ >
244+ { submissionYears . map ( ( year ) => (
245+ < option key = { year } value = { year } >
246+ { year }
247+ </ option >
248+ ) ) }
181249 </ select >
182- < select name = "projectType" required className = "w-full px-4 py-2 border rounded-lg" onChange = { handleChange } value = { formData . projectType } >
183- { projectTypes . map ( ( type ) => ( < option key = { type } value = { type } > { type } </ option > ) ) }
250+ < select
251+ name = "projectType"
252+ required
253+ className = "w-full px-4 py-2 border rounded-lg"
254+ onChange = { handleChange }
255+ value = { formData . projectType }
256+ >
257+ { projectTypes . map ( ( type ) => (
258+ < option key = { type } value = { type } >
259+ { type }
260+ </ option >
261+ ) ) }
184262 </ select >
185- < select name = "department" required className = "w-full px-4 py-2 border rounded-lg" onChange = { handleChange } value = { formData . department } >
186- { departments . map ( ( dept ) => ( < option key = { dept } value = { dept } > { dept } </ option > ) ) }
263+ < select
264+ name = "department"
265+ required
266+ className = "w-full px-4 py-2 border rounded-lg"
267+ onChange = { handleChange }
268+ value = { formData . department }
269+ >
270+ { departments . map ( ( dept ) => (
271+ < option key = { dept } value = { dept } >
272+ { dept }
273+ </ option >
274+ ) ) }
187275 </ select >
188- < input type = "url" name = "projectLink" required className = "w-full px-4 py-2 border rounded-lg" placeholder = "Project Link" onChange = { handleChange } value = { formData . projectLink } />
276+ < select
277+ name = "domain"
278+ required
279+ className = "w-full px-4 py-2 border rounded-lg"
280+ onChange = { handleChange }
281+ value = { formData . domain }
282+ >
283+ { availableDomains . map ( ( domain ) => (
284+ < option key = { domain } value = { domain } >
285+ { domain }
286+ </ option >
287+ ) ) }
288+ </ select >
289+ { formData . domain === "Other" && (
290+ < input
291+ type = "text"
292+ name = "customDomain"
293+ className = "w-full px-4 py-2 border rounded-lg"
294+ placeholder = "Enter custom domain"
295+ onChange = { handleChange }
296+ value = { formData . customDomain }
297+ />
298+ ) }
299+ < input
300+ type = "url"
301+ name = "projectLink"
302+ required
303+ className = "w-full px-4 py-2 border rounded-lg"
304+ placeholder = "Github link or google drive link of project contents"
305+ onChange = { handleChange }
306+ value = { formData . projectLink }
307+ />
189308
309+ { /* Members Section */ }
190310 { formData . members . map ( ( member , index ) => (
191311 < div key = { index } className = "flex items-center gap-2" >
192- < input type = "text" className = "px-4 py-2 border rounded-lg w-1/2" placeholder = "Member Name" value = { member . name } onChange = { ( e ) => handleMemberChange ( index , "name" , e . target . value ) } />
193- < input type = "url" className = "px-4 py-2 border rounded-lg w-1/2" placeholder = "LinkedIn Profile" value = { member . linkedin } onChange = { ( e ) => handleMemberChange ( index , "linkedin" , e . target . value ) } disabled = { ! member . name . trim ( ) } />
312+ < input
313+ type = "text"
314+ className = "px-4 py-2 border rounded-lg w-1/2"
315+ placeholder = "Member Name"
316+ value = { member . name }
317+ onChange = { ( e ) =>
318+ handleMemberChange ( index , "name" , e . target . value )
319+ }
320+ />
321+ < input
322+ type = "url"
323+ className = "px-4 py-2 border rounded-lg w-1/2"
324+ placeholder = "LinkedIn Profile"
325+ value = { member . linkedin }
326+ onChange = { ( e ) =>
327+ handleMemberChange ( index , "linkedin" , e . target . value )
328+ }
329+ disabled = { ! member . name . trim ( ) }
330+ />
194331 { formData . members . length > 1 && (
195- < button type = "button" className = "text-red-500" onClick = { ( ) => removeMember ( index ) } >
332+ < button
333+ type = "button"
334+ className = "text-red-500"
335+ onClick = { ( ) => removeMember ( index ) }
336+ >
196337 < XCircle className = "h-6 w-6" />
197338 </ button >
198339 ) }
199340 </ div >
200341 ) ) }
201342
202- < button type = "button" className = "w-full bg-gray-200 px-4 py-2 rounded-lg" onClick = { addMember } >
343+ < button
344+ type = "button"
345+ className = "w-full bg-gray-200 px-4 py-2 rounded-lg"
346+ onClick = { addMember }
347+ >
203348 Add Member
204349 </ button >
205350
206351 < div className = "flex gap-4" >
207- < button type = "submit" className = { `flex-1 bg-blue-600 text-white px-4 py-3 rounded-lg flex items-center justify-center ${ loading ? "opacity-50 cursor-not-allowed" : "" } ` } disabled = { loading } >
208- { loading ? < Save className = "h-5 w-5 mr-2 animate-spin" /> : < Save className = "h-5 w-5 mr-2" /> }
209- { loading ? "Saving..." : "Save Project" }
352+ < button
353+ type = "submit"
354+ className = { `flex-1 bg-blue-600 text-white px-4 py-3 rounded-lg flex items-center justify-center ${
355+ loading ||
356+ formData . members . every ( ( m ) => m . name . trim ( ) === "" )
357+ ? "opacity-50 cursor-not-allowed"
358+ : ""
359+ } `}
360+ disabled = {
361+ loading || formData . members . every ( ( m ) => m . name . trim ( ) === "" )
362+ }
363+ >
364+ { loading ? (
365+ < >
366+ < Save className = "h-5 w-5 mr-2 animate-spin" />
367+ < span > Saving...</ span >
368+ </ >
369+ ) : (
370+ < >
371+ < Save className = "h-5 w-5 mr-2" />
372+ < span > Save Project</ span >
373+ </ >
374+ ) }
210375 </ button >
211- < button type = "button" className = "flex-1 bg-red-500 text-white px-4 py-3 rounded-lg flex items-center justify-center" onClick = { clearForm } >
376+ < button
377+ type = "button"
378+ className = "flex-1 bg-red-500 text-white px-4 py-3 rounded-lg flex items-center justify-center"
379+ onClick = { clearForm }
380+ >
212381 < XCircle className = "h-5 w-5 mr-2" />
213382 < span > Clear</ span >
214383 </ button >
0 commit comments