"use client"; import { useState, FormEvent, ChangeEvent } from "react"; import { JobPosition, careerService } from "@/lib/api/careerService"; interface JobApplicationFormProps { job: JobPosition; onClose?: () => void; } interface FormData { // Required fields first_name: string; last_name: string; email: string; resume: File | null; consent: boolean; // Optional fields phone: string; current_position: string; current_company: string; years_of_experience: string; cover_letter: string; portfolio_url: string; linkedin_url: string; github_url: string; website_url: string; available_from: string; notice_period: string; expected_salary: string; salary_currency: string; } const JobApplicationForm = ({ job, onClose }: JobApplicationFormProps) => { const [formData, setFormData] = useState({ // Required fields first_name: "", last_name: "", email: "", resume: null, consent: false, // Optional fields phone: "", current_position: "", current_company: "", years_of_experience: "", cover_letter: "", portfolio_url: "", linkedin_url: "", github_url: "", website_url: "", available_from: "", notice_period: "", expected_salary: "", salary_currency: "USD", }); const [isSubmitting, setIsSubmitting] = useState(false); const [message, setMessage] = useState<{ type: "success" | "error" | null; text: string }>({ type: null, text: "", }); const handleInputChange = (e: ChangeEvent) => { const { name, value, type } = e.target; if (type === "checkbox") { const checked = (e.target as HTMLInputElement).checked; setFormData(prev => ({ ...prev, [name]: checked })); } else { setFormData(prev => ({ ...prev, [name]: value })); } }; const handleFileChange = (e: ChangeEvent) => { const file = e.target.files?.[0] || null; setFormData(prev => ({ ...prev, resume: file })); if (file) { // Validate file type const allowedTypes = ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]; if (!allowedTypes.includes(file.type)) { setMessage({ type: "error", text: "Please upload a PDF, DOC, or DOCX file" }); return; } // Validate file size (5MB) if (file.size > 5 * 1024 * 1024) { setMessage({ type: "error", text: "Resume file size must be less than 5MB" }); return; } setMessage({ type: null, text: "" }); } }; const validateForm = (): boolean => { // Check required fields if (!formData.first_name.trim()) { setMessage({ type: "error", text: "First name is required" }); return false; } if (!formData.last_name.trim()) { setMessage({ type: "error", text: "Last name is required" }); return false; } if (!formData.email.trim()) { setMessage({ type: "error", text: "Email is required" }); return false; } // Basic email validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(formData.email)) { setMessage({ type: "error", text: "Please enter a valid email address" }); return false; } if (!formData.resume) { setMessage({ type: "error", text: "Resume is required" }); return false; } if (!formData.consent) { setMessage({ type: "error", text: "You must consent to data processing to apply" }); return false; } return true; }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); if (!validateForm()) { return; } setIsSubmitting(true); setMessage({ type: null, text: "" }); try { // Prepare application data exactly as backend expects const applicationData = { // Required fields job: job.id, first_name: formData.first_name.trim(), last_name: formData.last_name.trim(), email: formData.email.trim(), resume: formData.resume!, consent: formData.consent, // Optional fields - only include if not empty ...(formData.phone.trim() && { phone: formData.phone.trim() }), ...(formData.current_position.trim() && { current_position: formData.current_position.trim() }), ...(formData.current_company.trim() && { current_company: formData.current_company.trim() }), ...(formData.years_of_experience.trim() && { years_of_experience: formData.years_of_experience.trim() }), ...(formData.cover_letter.trim() && { cover_letter: formData.cover_letter.trim() }), ...(formData.portfolio_url.trim() && { portfolio_url: formData.portfolio_url.trim() }), ...(formData.linkedin_url.trim() && { linkedin_url: formData.linkedin_url.trim() }), ...(formData.github_url.trim() && { github_url: formData.github_url.trim() }), ...(formData.website_url.trim() && { website_url: formData.website_url.trim() }), ...(formData.available_from && { available_from: formData.available_from }), ...(formData.notice_period.trim() && { notice_period: formData.notice_period.trim() }), ...(formData.expected_salary && { expected_salary: parseFloat(formData.expected_salary) }), ...(formData.salary_currency && { salary_currency: formData.salary_currency }), }; const result = await careerService.submitApplication(applicationData); setMessage({ type: "success", text: "Application submitted successfully! We'll be in touch soon.", }); // Reset form setFormData({ first_name: "", last_name: "", email: "", resume: null, consent: false, phone: "", current_position: "", current_company: "", years_of_experience: "", cover_letter: "", portfolio_url: "", linkedin_url: "", github_url: "", website_url: "", available_from: "", notice_period: "", expected_salary: "", salary_currency: "USD", }); // Reset file input const fileInput = document.getElementById('resume') as HTMLInputElement; if (fileInput) fileInput.value = ''; } catch (error) { setMessage({ type: "error", text: error instanceof Error ? error.message : "Failed to submit application. Please try again.", }); } finally { setIsSubmitting(false); } }; return (
{/* Header */}
{onClose && ( )}

Apply for {job.title}

Join our team • {job.location} • {job.employment_type.replace('-', ' ')}

{/* Message */} {message.type && (
{message.type === "success" ? ( ) : ( )}
{message.text}
)} {/* Form */}
{/* Required Fields Section */}

Personal Information

Required fields are marked with *
{formData.resume && (
File selected: {formData.resume.name}
)}
{/* Professional Information */}

Professional Background

All fields are required