@@ -34,6 +34,8 @@ interface Project {
3434}
3535
3636type ApplicationFormValues = {
37+ discordUsername : string ;
38+ discordJoined : boolean ;
3739 whyThisProject : string ;
3840 motivation : string ;
3941 relevantExperience : string ;
@@ -67,6 +69,7 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
6769 const [ success , setSuccess ] = useState ( false ) ;
6870 const [ currentStep , setCurrentStep ] = useState ( 1 ) ;
6971 const [ isMentee , setIsMentee ] = useState < boolean | null > ( null ) ;
72+ const [ showDiscordPrompt , setShowDiscordPrompt ] = useState ( true ) ;
7073 const {
7174 register,
7275 handleSubmit,
@@ -75,6 +78,8 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
7578 watch,
7679 } = useForm < ApplicationFormValues > ( {
7780 defaultValues : {
81+ discordUsername : '' ,
82+ discordJoined : false ,
7883 whyThisProject : '' ,
7984 motivation : '' ,
8085 relevantExperience : '' ,
@@ -95,9 +100,10 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
95100 } ) ;
96101
97102 const availabilityValue = watch ( 'availability' ) ;
103+ const discordJoinedValue = watch ( 'discordJoined' ) ;
98104
99105 const stepFields : Record < number , ( keyof ApplicationFormValues ) [ ] > = {
100- 1 : [ 'whyThisProject' , 'motivation' ] ,
106+ 1 : [ 'discordUsername' , 'discordJoined' , ' whyThisProject', 'motivation' ] ,
101107 2 : [ 'relevantExperience' , 'technicalSkills' , 'githubProfile' , 'portfolioLinks' ] ,
102108 3 : [ 'proposal' , 'timeline' , 'expectedLearnings' ] ,
103109 4 : [ 'availability' , 'timezone' ] ,
@@ -233,13 +239,19 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
233239 } ) ;
234240 } ;
235241
242+ const isStepAccessible = ( stepId : number ) => {
243+ return stepId <= currentStep ;
244+ } ;
245+
236246 if ( loading ) {
237247 return (
238- < div className = "min-h-screen bg-background flex items-center justify-center " >
248+ < div className = "min-h-screen bg-background" >
239249 < DSOCNavbar />
240- < div className = "text-center" >
241- < div className = "inline-block w-12 h-12 border-4 border-[var(--dsoc-primary)] border-t-transparent animate-spin" />
242- < p className = "mt-4 text-muted-foreground" > Loading application...</ p >
250+ < div className = "pt-24 pb-12 flex items-center justify-center" >
251+ < div className = "text-center" >
252+ < div className = "inline-block w-12 h-12 border-4 border-[var(--dsoc-primary)] border-t-transparent animate-spin" />
253+ < p className = "mt-4 text-muted-foreground" > Loading application...</ p >
254+ </ div >
243255 </ div >
244256 </ div >
245257 ) ;
@@ -314,6 +326,34 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
314326 return (
315327 < div className = "min-h-screen bg-gradient-to-br from-[var(--dsoc-light)] via-white to-[var(--dsoc-accent)]/20" >
316328 < DSOCNavbar />
329+
330+ { showDiscordPrompt && ! discordJoinedValue && (
331+ < div className = "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4" >
332+ < div className = "neo-brutal-card p-6 max-w-md w-full" >
333+ < h2 className = "text-xl font-black mb-2" > Join Discord First</ h2 >
334+ < p className = "text-sm text-muted-foreground mb-4" >
335+ Joining Discord is mandatory before applying. Please join the DSOC Discord and the project channel.
336+ </ p >
337+ < div className = "flex flex-col sm:flex-row gap-3" >
338+ < a
339+ href = "https://discord.com/invite/Cy7Rgkf4Up"
340+ target = "_blank"
341+ rel = "noopener noreferrer"
342+ className = "neo-brutal-btn neo-brutal-btn-primary w-full"
343+ >
344+ Join Discord
345+ </ a >
346+ < button
347+ type = "button"
348+ onClick = { ( ) => setShowDiscordPrompt ( false ) }
349+ className = "neo-brutal-btn neo-brutal-btn-secondary w-full"
350+ >
351+ I Joined
352+ </ button >
353+ </ div >
354+ </ div >
355+ </ div >
356+ ) }
317357
318358 < div className = "pt-24 pb-12" >
319359 < div className = "container mx-auto px-4 sm:px-6 lg:px-8" >
@@ -411,14 +451,19 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
411451 < div key = { step . id } className = "flex items-center flex-1" >
412452 < button
413453 type = "button"
414- onClick = { ( ) => setCurrentStep ( step . id ) }
454+ onClick = { ( ) => {
455+ if ( isStepAccessible ( step . id ) ) {
456+ setCurrentStep ( step . id ) ;
457+ }
458+ } }
459+ disabled = { ! isStepAccessible ( step . id ) }
415460 className = { `flex items-center gap-3 p-3 rounded-lg transition-all w-full ${
416461 currentStep === step . id
417462 ? 'bg-[var(--dsoc-primary)] text-white'
418463 : currentStep > step . id
419464 ? 'bg-[var(--dsoc-success)] text-white'
420465 : 'bg-gray-100 text-gray-500'
421- } `}
466+ } ${ ! isStepAccessible ( step . id ) ? 'cursor-not-allowed opacity-60' : '' } `}
422467 >
423468 < div className = { `w-10 h-10 flex items-center justify-center border-2 ${
424469 currentStep >= step . id ? 'border-white' : 'border-gray-300'
@@ -479,6 +524,48 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
479524 </ p >
480525 </ div >
481526
527+ < div >
528+ < label className = "block font-bold text-sm mb-2" >
529+ Discord Username *
530+ </ label >
531+ < p className = "text-sm text-muted-foreground mb-3" >
532+ Use your Discord username (e.g., username or username#1234).
533+ </ p >
534+ < input
535+ type = "text"
536+ { ...register ( 'discordUsername' , { required : 'This field is required.' } ) }
537+ className = "neo-brutal-input"
538+ placeholder = "yourname or yourname#1234"
539+ />
540+ { errors . discordUsername ?. message && (
541+ < p className = "mt-2 text-sm font-bold text-[var(--dsoc-pink)]" >
542+ { errors . discordUsername . message }
543+ </ p >
544+ ) }
545+ </ div >
546+
547+ < div className = "flex items-start gap-3" >
548+ < input
549+ type = "checkbox"
550+ id = "discordJoined"
551+ { ...register ( 'discordJoined' , { required : 'Please confirm you have joined Discord.' } ) }
552+ className = "mt-1 h-4 w-4"
553+ />
554+ < div >
555+ < label htmlFor = "discordJoined" className = "block font-bold text-sm" >
556+ I have joined the DSOC Discord and the project channel *
557+ </ label >
558+ < p className = "text-sm text-muted-foreground" >
559+ This is required before you can apply.
560+ </ p >
561+ { errors . discordJoined ?. message && (
562+ < p className = "mt-2 text-sm font-bold text-[var(--dsoc-pink)]" >
563+ { errors . discordJoined . message }
564+ </ p >
565+ ) }
566+ </ div >
567+ </ div >
568+
482569 < div >
483570 < label className = "block font-bold text-sm mb-2" >
484571 Why are you interested in this project? *
0 commit comments