diff --git a/apps/student/app/(main)/actions.ts b/apps/student/app/(main)/actions.ts index 5fe9baf..a1bee83 100644 --- a/apps/student/app/(main)/actions.ts +++ b/apps/student/app/(main)/actions.ts @@ -1,6 +1,6 @@ 'use server'; import { signOut } from '@/auth'; -import { db, applications, jobs, students, resumes } from '@workspace/db'; +import { db, applications, jobs, students, resumes, grades, internships } from '@workspace/db'; import { eq, and } from '@workspace/db/drizzle'; import { revalidatePath } from 'next/cache'; @@ -76,22 +76,119 @@ export async function getStudentProfile(studentId: number) { export async function updateStudentProfile(studentId: number, data: any) { try { - await db - .update(students) - .set({ - ...data, - updatedAt: new Date(), - }) - .where(eq(students.id, studentId)); + const { section, ...updateData } = data; - revalidatePath('/profile'); - return { success: true }; + switch (section) { + case 'grades': + return await updateGrades(studentId, updateData.grades); + + case 'internships': + return await updateInternships(studentId, updateData.internships); + + case 'resumes': + return await updateResumes(studentId, updateData.resumes); + + default: + // Update student basic information + await db + .update(students) + .set({ + ...updateData, + updatedAt: new Date(), + }) + .where(eq(students.id, studentId)); + + revalidatePath('/profile'); + return { success: true }; + } } catch (error) { console.error('Error updating student profile:', error); return { success: false, error: 'Failed to update profile' }; } } +async function updateGrades(studentId: number, gradesList: any[]) { + try { + // Delete existing grades for this student + await db.delete(grades).where(eq(grades.studentId, studentId)); + + // Insert new grades + if (gradesList && gradesList.length > 0) { + const validGrades = gradesList.filter(grade => grade.sgpi > 0); // Only save grades with SGPI > 0 + + if (validGrades.length > 0) { + await db.insert(grades).values( + validGrades.map(grade => ({ + studentId, + sem: parseInt(grade.sem), + sgpi: parseFloat(grade.sgpi).toFixed(2), + isKT: Boolean(grade.isKT), + deadKT: Boolean(grade.deadKT), + })) + ); + } + } + + revalidatePath('/profile'); + return { success: true }; + } catch (error) { + console.error('Error updating grades:', error); + return { success: false, error: 'Failed to update grades' }; + } +} + +async function updateInternships(studentId: number, internshipsList: any[]) { + try { + // Delete existing internships for this student + await db.delete(internships).where(eq(internships.studentId, studentId)); + + // Insert new internships + if (internshipsList && internshipsList.length > 0) { + await db.insert(internships).values( + internshipsList.map(internship => ({ + studentId, + title: internship.title, + company: internship.company, + location: internship.location, + description: internship.description, + startDate: new Date(internship.startDate), + endDate: new Date(internship.endDate), + })) + ); + } + + revalidatePath('/profile'); + return { success: true }; + } catch (error) { + console.error('Error updating internships:', error); + return { success: false, error: 'Failed to update internships' }; + } +} + +async function updateResumes(studentId: number, resumesList: any[]) { + try { + // Delete existing resumes for this student + await db.delete(resumes).where(eq(resumes.studentId, studentId)); + + // Insert new resumes + if (resumesList && resumesList.length > 0) { + await db.insert(resumes).values( + resumesList.map(resume => ({ + studentId, + title: resume.title, + link: resume.link, + })) + ); + } + + revalidatePath('/profile'); + return { success: true }; + } catch (error) { + console.error('Error updating resumes:', error); + return { success: false, error: 'Failed to update resumes' }; + } +} + export async function getAvailableJobs() { try { const availableJobs = await db.query.jobs.findMany({ diff --git a/apps/student/app/(main)/profile/page.tsx b/apps/student/app/(main)/profile/page.tsx index c328694..151ccd3 100644 --- a/apps/student/app/(main)/profile/page.tsx +++ b/apps/student/app/(main)/profile/page.tsx @@ -1,7 +1,7 @@ 'use client'; /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useTransition } from 'react'; import { useSession } from 'next-auth/react'; import { Card, CardContent, CardHeader, CardTitle } from "@workspace/ui/components/card" import { Button } from "@workspace/ui/components/button" @@ -53,6 +53,8 @@ export default function ProfilePage() { const [editingGrades, setEditingGrades] = useState([]); const [editingInternships, setEditingInternships] = useState([]); const [editingResumes, setEditingResumes] = useState([]); + const [successMessage, setSuccessMessage] = useState(null); + const [isPending, startTransition] = useTransition(); const [newInternship, setNewInternship] = useState({ title: '', company: '', @@ -92,6 +94,7 @@ export default function ProfilePage() { const handleEdit = (section: string) => { setEditingSection(section); setEditData({}); + setError(null); // Clear any previous errors }; const handleCancel = () => { @@ -100,21 +103,22 @@ export default function ProfilePage() { }; const handleSave = async (section: string) => { - setIsSaving(true); - try { - const result = await updateStudentProfile(student.id, editData); - if (result.success) { - setStudent((prev: Record | null) => ({ ...(prev || {}), ...editData })); - setEditingSection(null); - setEditData({}); - } else { - setError(result.error || 'Failed to update profile'); + startTransition(async () => { + try { + const result = await updateStudentProfile(student.id, editData); + if (result.success) { + setStudent((prev: Record | null) => ({ ...(prev || {}), ...editData })); + setEditingSection(null); + setEditData({}); + setSuccessMessage('Profile updated successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); + } else { + setError(result.error || 'Failed to update profile'); + } + } catch (err) { + setError('Failed to update profile'); } - } catch (err) { - setError('Failed to update profile'); - } finally { - setIsSaving(false); - } + }); }; const handleInputChange = (field: string, value: string) => { @@ -143,40 +147,59 @@ export default function ProfilePage() { }; const saveSkills = async () => { - setIsSaving(true); - try { - const result = await updateStudentProfile(student.id, { skills: editingSkills }); - if (result.success) { - setStudent((prev: Record | null) => ({ ...(prev || {}), skills: editingSkills })); - setEditingSection(null); - } else { - setError(result.error || 'Failed to update skills'); + startTransition(async () => { + try { + const result = await updateStudentProfile(student.id, { skills: editingSkills }); + if (result.success) { + setStudent((prev: Record | null) => ({ ...(prev || {}), skills: editingSkills })); + setEditingSection(null); + setSuccessMessage('Skills updated successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); + } else { + setError(result.error || 'Failed to update skills'); + } + } catch (err) { + setError('Failed to update skills'); } - } catch (err) { - setError('Failed to update skills'); - } finally { - setIsSaving(false); - } + }); }; const handleEditSkills = () => { - setEditingSkills(student.skills || []); + setEditingSkills([...(student.skills || [])]); setEditingSection('skills'); + setError(null); // Clear any previous errors }; const handleEditGrades = () => { - setEditingGrades(student.grades || []); + // Initialize with existing grades or create default grades for 8 semesters + const existingGrades = student.grades || []; + const defaultGrades = []; + + for (let sem = 1; sem <= 8; sem++) { + const existingGrade = existingGrades.find((g: any) => g.sem === sem); + defaultGrades.push({ + sem, + sgpi: existingGrade?.sgpi || 0, + isKT: existingGrade?.isKT || false, + deadKT: existingGrade?.deadKT || false, + }); + } + + setEditingGrades(defaultGrades); setEditingSection('grades'); + setError(null); // Clear any previous errors }; const handleEditInternships = () => { - setEditingInternships(student.internships || []); + setEditingInternships([...(student.internships || [])]); setEditingSection('internships'); + setError(null); // Clear any previous errors }; const handleEditResumes = () => { - setEditingResumes(student.resumes || []); + setEditingResumes([...(student.resumes || [])]); setEditingSection('resumes'); + setError(null); // Clear any previous errors }; const updateGrade = (sem: number, field: string, value: any) => { @@ -217,54 +240,57 @@ export default function ProfilePage() { }; const saveGrades = async () => { - setIsSaving(true); - try { - const result = await updateStudentProfile(student.id, { grades: editingGrades }); - if (result.success) { - setStudent((prev: Record | null) => ({ ...(prev || {}), grades: editingGrades })); - setEditingSection(null); - } else { - setError(result.error || 'Failed to update grades'); + startTransition(async () => { + try { + const result = await updateStudentProfile(student.id, { section: 'grades', grades: editingGrades }); + if (result.success) { + setStudent((prev: Record | null) => ({ ...(prev || {}), grades: editingGrades })); + setEditingSection(null); + setSuccessMessage('Grades updated successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); + } else { + setError(result.error || 'Failed to update grades'); + } + } catch (err) { + setError('Failed to update grades'); } - } catch (err) { - setError('Failed to update grades'); - } finally { - setIsSaving(false); - } + }); }; const saveInternships = async () => { - setIsSaving(true); - try { - const result = await updateStudentProfile(student.id, { internships: editingInternships }); - if (result.success) { - setStudent((prev: Record | null) => ({ ...(prev || {}), internships: editingInternships })); - setEditingSection(null); - } else { - setError(result.error || 'Failed to update internships'); + startTransition(async () => { + try { + const result = await updateStudentProfile(student.id, { section: 'internships', internships: editingInternships }); + if (result.success) { + setStudent((prev: Record | null) => ({ ...(prev || {}), internships: editingInternships })); + setEditingSection(null); + setSuccessMessage('Internships updated successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); + } else { + setError(result.error || 'Failed to update internships'); + } + } catch (err) { + setError('Failed to update internships'); } - } catch (err) { - setError('Failed to update internships'); - } finally { - setIsSaving(false); - } + }); }; const saveResumes = async () => { - setIsSaving(true); - try { - const result = await updateStudentProfile(student.id, { resumes: editingResumes }); - if (result.success) { - setStudent((prev: Record | null) => ({ ...(prev || {}), resumes: editingResumes })); - setEditingSection(null); - } else if ('error' in result) { - setError(result.error || 'Failed to update resumes'); + startTransition(async () => { + try { + const result = await updateStudentProfile(student.id, { section: 'resumes', resumes: editingResumes }); + if (result.success) { + setStudent((prev: Record | null) => ({ ...(prev || {}), resumes: editingResumes })); + setEditingSection(null); + setSuccessMessage('Resumes updated successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); + } else { + setError(result.error || 'Failed to update resumes'); + } + } catch (err) { + setError('Failed to update resumes'); } - } catch (err) { - setError('Failed to update resumes'); - } finally { - setIsSaving(false); - } + }); }; const handleDragOver = (e: React.DragEvent) => { @@ -344,6 +370,12 @@ export default function ProfilePage() { {error} )} + {successMessage && ( +
+ + {successMessage} +
+ )}
@@ -467,9 +499,9 @@ export default function ProfilePage() { ) : (
- ) : (
- ) : (
- ) : (
- ) : (
- ) : (
-