11"use client" ;
22
3- import { useState } from "react" ;
3+ import { useState , useEffect } from "react" ;
44import { useForm } from "react-hook-form" ;
55import { zodResolver } from "@hookform/resolvers/zod" ;
66import { z } from "zod" ;
@@ -17,16 +17,20 @@ import { Label } from "@codevs/ui/label";
1717import { Textarea } from "@codevs/ui/textarea" ;
1818import { useToast } from "@/components/ui/use-toast" ;
1919import { JobListing } from "../_types/job-listings" ;
20+ import { createClientClientComponent } from "@/utils/supabase/client" ;
2021
2122const applicationSchema = z . object ( {
2223 firstName : z . string ( ) . min ( 2 , "First name must be at least 2 characters" ) ,
2324 lastName : z . string ( ) . min ( 2 , "Last name must be at least 2 characters" ) ,
2425 email : z . string ( ) . email ( "Invalid email address" ) ,
2526 phone : z . string ( ) . min ( 10 , "Phone number must be at least 10 digits" ) ,
2627 linkedIn : z . string ( ) . url ( "Invalid LinkedIn URL" ) . optional ( ) . or ( z . literal ( "" ) ) ,
28+ github : z . string ( ) . url ( "Invalid GitHub URL" ) . optional ( ) . or ( z . literal ( "" ) ) ,
2729 portfolio : z . string ( ) . url ( "Invalid portfolio URL" ) . optional ( ) . or ( z . literal ( "" ) ) ,
30+ yearsOfExperience : z . string ( ) . min ( 1 , "Years of experience is required" ) ,
2831 coverLetter : z . string ( ) . min ( 50 , "Cover letter must be at least 50 characters" ) ,
2932 experience : z . string ( ) . min ( 20 , "Please describe your relevant experience" ) ,
33+ referredBy : z . string ( ) . optional ( ) ,
3034 resume : z . any ( ) . optional ( ) ,
3135} ) ;
3236
@@ -52,10 +56,12 @@ export default function JobApplicationModal({
5256 handleSubmit,
5357 formState : { errors } ,
5458 reset,
59+ setValue,
5560 } = useForm < ApplicationFormData > ( {
5661 resolver : zodResolver ( applicationSchema ) ,
5762 } ) ;
5863
64+
5965 const handleFileChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
6066 const file = e . target . files ?. [ 0 ] ;
6167 if ( file ) {
@@ -77,19 +83,48 @@ export default function JobApplicationModal({
7783 setIsSubmitting ( true ) ;
7884
7985 try {
80- // Simulate API call
81- await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
86+ const supabase = createClientClientComponent ( ) ;
87+
88+ // Upload resume if provided
89+ let resumeUrl = null ;
90+ if ( resumeFile ) {
91+ const fileExt = resumeFile . name . split ( '.' ) . pop ( ) ;
92+ const fileName = `${ data . email . replace ( '@' , '_' ) } _${ Date . now ( ) } .${ fileExt } ` ;
93+
94+ const { data : uploadData , error : uploadError } = await supabase . storage
95+ . from ( 'resumes' )
96+ . upload ( fileName , resumeFile ) ;
97+
98+ if ( uploadError ) {
99+ console . error ( 'Resume upload error:' , uploadError ) ;
100+ } else {
101+ resumeUrl = uploadData . path ;
102+ }
103+ }
82104
83- // Here you would typically send the application to your backend
84- const applicationData = {
85- ...data ,
86- jobId : job . id ,
87- jobTitle : job . title ,
88- resume : resumeFile ?. name ,
89- appliedAt : new Date ( ) . toISOString ( ) ,
90- } ;
105+ // Save application to database
106+ const { error } = await supabase
107+ . from ( 'job_applications' )
108+ . insert ( {
109+ job_id : job . id ,
110+ first_name : data . firstName ,
111+ last_name : data . lastName ,
112+ email : data . email ,
113+ phone : data . phone ,
114+ linkedin : data . linkedIn || null ,
115+ github : data . github || null ,
116+ portfolio : data . portfolio || null ,
117+ years_of_experience : parseInt ( data . yearsOfExperience ) ,
118+ cover_letter : data . coverLetter ,
119+ experience : data . experience ,
120+ resume_url : resumeUrl ,
121+ status : 'pending' ,
122+ notes : data . referredBy ? `Referred by: ${ data . referredBy } ` : 'Direct Application'
123+ } ) ;
91124
92- console . log ( "Application submitted:" , applicationData ) ;
125+ if ( error ) {
126+ throw error ;
127+ }
93128
94129 toast ( {
95130 title : "Application Submitted!" ,
@@ -100,6 +135,7 @@ export default function JobApplicationModal({
100135 setResumeFile ( null ) ;
101136 onClose ( ) ;
102137 } catch ( error ) {
138+ console . error ( 'Application submission error:' , error ) ;
103139 toast ( {
104140 title : "Submission failed" ,
105141 description : "Please try again later." ,
@@ -189,6 +225,40 @@ export default function JobApplicationModal({
189225 < p className = "text-sm text-red-400" > { errors . phone . message } </ p >
190226 ) }
191227 </ div >
228+
229+ < div className = "grid grid-cols-2 gap-4" >
230+ < div className = "space-y-2" >
231+ < Label htmlFor = "yearsOfExperience" className = "text-gray-300" >
232+ Years of Experience *
233+ </ Label >
234+ < Input
235+ id = "yearsOfExperience"
236+ type = "number"
237+ min = "0"
238+ { ...register ( "yearsOfExperience" ) }
239+ className = "bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
240+ placeholder = "5"
241+ />
242+ { errors . yearsOfExperience && (
243+ < p className = "text-sm text-red-400" > { errors . yearsOfExperience . message } </ p >
244+ ) }
245+ </ div >
246+
247+ < div className = "space-y-2" >
248+ < Label htmlFor = "referredBy" className = "text-gray-300" >
249+ Referred By (Optional)
250+ </ Label >
251+ < Input
252+ id = "referredBy"
253+ { ...register ( "referredBy" ) }
254+ className = "bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
255+ placeholder = "Name of referrer (if any)"
256+ />
257+ { errors . referredBy && (
258+ < p className = "text-sm text-red-400" > { errors . referredBy . message } </ p >
259+ ) }
260+ </ div >
261+ </ div >
192262 </ div >
193263
194264 { /* Professional Links */ }
@@ -211,6 +281,22 @@ export default function JobApplicationModal({
211281 ) }
212282 </ div >
213283
284+ < div className = "space-y-2" >
285+ < Label htmlFor = "github" className = "text-gray-300" >
286+ GitHub Profile
287+ </ Label >
288+ < Input
289+ id = "github"
290+ type = "url"
291+ { ...register ( "github" ) }
292+ className = "bg-gray-800 border-gray-700 text-white placeholder:text-gray-500"
293+ placeholder = "https://github.com/johndoe"
294+ />
295+ { errors . github && (
296+ < p className = "text-sm text-red-400" > { errors . github . message } </ p >
297+ ) }
298+ </ div >
299+
214300 < div className = "space-y-2" >
215301 < Label htmlFor = "portfolio" className = "text-gray-300" >
216302 Portfolio/Website
0 commit comments