// Due to the length and complexity of the complete updated form, the full implementation is provided modularly. // This file only includes the top-level form layout and updated schema logic. Other components (InternshipModal, ResumeModal, etc.) // should be created as separate files or extracted for cleanliness. 'use client'; import { useState, useTransition } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; // Only import used UI components import { Button } from '@workspace/ui/components/button'; import { Progress } from '@workspace/ui/components/progress'; import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card'; import { Form } from '@workspace/ui/components/form'; import { useRouter } from 'next/navigation'; import { useRef } from 'react'; import { studentSignupSchema, StudentSignup } from './schema'; import PersonalDetailsStep from './steps/PersonalDetailsStep'; import AcademicDetailsStep from './steps/AcademicDetailsStep'; import SemesterGradesStep from './steps/SemesterGradesStep'; import AdditionalDetailsStep from './steps/AdditionalDetailsStep'; import InternshipStep from './steps/InternshipStep'; import ResumeStep from './steps/ResumeStep'; import { signupAction } from './action'; const steps = [ { id: 1, title: 'Personal Details', fields: [ 'firstName', 'lastName', 'mothersName', 'rollNumber', 'phoneNumber', 'address', 'gender', 'dob', 'personalGmail', ], }, { id: 2, title: 'Academic Details', fields: ['degree', 'year', 'branch', 'ssc', 'hsc', 'isDiploma'], }, { id: 3, title: 'Semester Grades', fields: ['sgpi'] }, { id: 4, title: 'Additional Details', fields: ['linkedin', 'github', 'skills'] }, { id: 5, title: 'Internships', fields: ['internships'] }, { id: 6, title: 'Resumes', fields: ['resume'] }, ]; export default function StudentRegistrationForm() { const [currentStep, setCurrentStep] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); const [isPending, startTransition] = useTransition(); const router = useRouter(); const formRef = useRef(null); const form = useForm({ resolver: zodResolver(studentSignupSchema), defaultValues: { firstName: '', middleName: '', lastName: '', mothersName: '', rollNumber: '', phoneNumber: '', address: '', gender: '', dob: new Date(), personalGmail: '', degree: '', branch: '', year: '', skills: [], linkedin: '', github: '', ssc: 0, hsc: 0, isDiploma: false, sgpi: Array.from({ length: 8 }, (_, i) => ({ sem: i + 1, sgpi: 0, kt: false, ktDead: false, })), internships: [], resume: [], }, }); // console.log(form.formState.errors) const validateCurrentStep = async () => { const current = steps.find((s) => s.id === currentStep); if (!current) return false; try { const result = await form.trigger(current.fields as (keyof StudentSignup)[]); return result; } catch (error) { console.error('Validation error:', error); return false; } }; const nextStep = async () => { const isValid = await validateCurrentStep(); if (isValid && currentStep < steps.length) { setCurrentStep((prev) => prev + 1); } else if (!isValid) { alert('Please fill all required fields before proceeding.'); } }; const prevStep = () => { if (currentStep > 1) setCurrentStep((prev) => prev - 1); }; const onSubmit = async (data: StudentSignup) => { // Only submit if on the last step if (currentStep !== steps.length) return; setIsSubmitting(true); try { const result = await signupAction(data); if (result && result.success) { router.push('/'); return; } if (result && result.error) { const errorMessage = Array.isArray(result.error) ? result.error.map((e) => e.message || e).join(', ') : result.error; alert('Submission failed: ' + errorMessage); } else { alert('Submission failed. Try again.'); } } catch (err) { console.error('Submission error:', err); alert('Submission failed. Try again.'); } finally { setIsSubmitting(false); } }; const renderStep = () => { switch (currentStep) { case 1: return ; case 2: return ; case 3: return ; case 4: return ; case 5: return ; case 6: return ; default: return null; } }; const progress = (currentStep / steps.length) * 100; // Map field keys to user-friendly names const fieldLabels: Record = { firstName: 'First Name', middleName: 'Middle Name', lastName: 'Last Name', mothersName: "Mother's Name", rollNumber: 'Roll Number', phoneNumber: 'Phone Number', address: 'Address', gender: 'Gender', dob: 'Date of Birth', personalGmail: 'Personal Email', degree: 'Degree', branch: 'Branch', year: 'Year', skills: 'Skills', linkedin: 'LinkedIn', github: 'GitHub', ssc: 'SSC %', hsc: 'HSC %', isDiploma: 'Diploma Holder', sgpi: 'Semester Grades', internships: 'Internships', resume: 'Resumes', }; // Helper to recursively extract error fields function extractErrorFields(errors: any, prefix = ''): string[] { let fields: string[] = []; for (const key in errors) { if (typeof errors[key] === 'object' && errors[key] !== null && 'message' in errors[key]) { fields.push(prefix + key); } else if (typeof errors[key] === 'object' && errors[key] !== null) { fields = fields.concat(extractErrorFields(errors[key], prefix + key + '.')); } } return fields; } return (
{/* Animated floating blobs with more vibrant colors */}
{/* Welcoming heading - now always at the top */}

Welcome to NextPlacement

Register below to get started with your placement journey. Fill in your details step by step and let your career take off!

Student Registration Form
Step {currentStep} of {steps.length} {steps[currentStep - 1]?.title}
{ // Get all error fields const errorFields = extractErrorFields(form.formState.errors); // Map to user-friendly names const prettyFields = errorFields.map((key) => { // Try to map top-level, or fallback to key const topKey = String(key.split('.')[0]); return fieldLabels[topKey] || key; }); alert( 'Please fill all required fields before submitting.\n' + (prettyFields.length > 0 ? 'Missing/invalid: ' + prettyFields.join(', ') : '') ); }) : (e) => e.preventDefault() } className="space-y-8" onKeyDown={(e) => { if ( e.key === 'Enter' && e.target instanceof HTMLElement && e.target.tagName !== 'TEXTAREA' ) { e.preventDefault(); } }} > {renderStep()}
{currentStep === steps.length ? ( ) : ( )}
{/* Animated gradient and blob styles */}
); }