From 592af3216e9ec5497916f4ac8627672c2846a46a Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Tue, 23 Dec 2025 08:29:15 -0300 Subject: [PATCH] feat: connect Apply Now to applications API Frontend changes: - Add applicationsApi with create() and getByJob() in api.ts - Update apply/page.tsx to fetch job from API and submit to backend - Fix job detail page requirements null check - Use ApiJob type instead of mock Job type - Replace job.company with job.companyName throughout Note: Backend has type mismatch issues that need fixing: - jobs endpoint: varchar vs integer comparison - applications: null id constraint --- frontend/src/app/jobs/[id]/apply/page.tsx | 75 +++++++++++++++++------ frontend/src/app/jobs/[id]/page.tsx | 24 +++++--- frontend/src/lib/api.ts | 60 ++++++++++++++++++ 3 files changed, 131 insertions(+), 28 deletions(-) diff --git a/frontend/src/app/jobs/[id]/apply/page.tsx b/frontend/src/app/jobs/[id]/apply/page.tsx index 96336d5..f842020 100644 --- a/frontend/src/app/jobs/[id]/apply/page.tsx +++ b/frontend/src/app/jobs/[id]/apply/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, use } from "react"; +import { useState, use, useEffect } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { motion, AnimatePresence } from "framer-motion"; @@ -15,6 +15,7 @@ import { MessageSquare, Save, ArrowLeft, + Loader2, } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -42,7 +43,7 @@ import { Separator } from "@/components/ui/separator"; import { Navbar } from "@/components/navbar"; import { Footer } from "@/components/footer"; import { useNotify } from "@/contexts/notification-context"; -import { mockJobs } from "@/lib/mock-data"; +import { jobsApi, applicationsApi, type ApiJob } from "@/lib/api"; // Step definitions const steps = [ @@ -65,9 +66,8 @@ export default function JobApplicationPage({ const notify = useNotify(); const [currentStep, setCurrentStep] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); - - // Find job details - const job = mockJobs.find((j) => j.id === id) || mockJobs[0]; + const [job, setJob] = useState(null); + const [loading, setLoading] = useState(true); // Form state const [formData, setFormData] = useState({ @@ -161,17 +161,56 @@ export default function JobApplicationPage({ } }; + useEffect(() => { + async function fetchJob() { + try { + setLoading(true); + const response = await jobsApi.getById(id); + if (response) { + setJob(response); + } + } catch (err) { + console.error("Error fetching job:", err); + notify.error("Error", "Failed to load job details"); + } finally { + setLoading(false); + } + } + fetchJob(); + }, [id, notify]); + const handleSubmit = async () => { setIsSubmitting(true); - // Simulate API call - await new Promise((resolve) => setTimeout(resolve, 2000)); + try { + await applicationsApi.create({ + jobId: id, + name: formData.fullName, + email: formData.email, + phone: formData.phone, + linkedin: formData.linkedin, + coverLetter: formData.coverLetter, + portfolioUrl: formData.portfolioUrl, + salaryExpectation: formData.salaryExpectation, + hasExperience: formData.hasExperience, + whyUs: formData.whyUs, + availability: formData.availability, + }); - notify.success( - "Application submitted!", - `Good luck! Your application for ${job.title} has been received.` - ); + notify.success( + "Application submitted!", + `Good luck! Your application for ${job?.title || 'this position'} has been received.` + ); - router.push("/dashboard/my-applications"); + router.push("/dashboard/my-applications"); + } catch (error: any) { + console.error("Submit error:", error); + notify.error( + "Error submitting", + error.message || "Please try again later." + ); + } finally { + setIsSubmitting(false); + } }; const handleSaveDraft = () => { @@ -206,7 +245,7 @@ export default function JobApplicationPage({ Application: {job.title}

- {job.company} • {job.location} + {job.companyName || 'Company'} • {job.location || 'Remote'}

@@ -241,10 +280,10 @@ export default function JobApplicationPage({