From 578c968eb9f87e050db0b97f4e246f350112cb38 Mon Sep 17 00:00:00 2001 From: Unchanted Date: Tue, 2 Sep 2025 17:20:28 +0530 Subject: [PATCH] feat(student): added eligible and non eligible tabs --- apps/student/app/(main)/jobs/JobClient.tsx | 80 +++++++++++++++---- apps/student/app/(main)/jobs/page.tsx | 48 ++++++++++- .../components/job-application-modal.tsx | 30 ++++--- 3 files changed, 133 insertions(+), 25 deletions(-) diff --git a/apps/student/app/(main)/jobs/JobClient.tsx b/apps/student/app/(main)/jobs/JobClient.tsx index 8e8be92..98355b7 100644 --- a/apps/student/app/(main)/jobs/JobClient.tsx +++ b/apps/student/app/(main)/jobs/JobClient.tsx @@ -43,28 +43,33 @@ export type Job = InferSelectModel & { export type Resume = typeof resumes.$inferSelect; export default function JobsPage({ - jobs, + eligibleJobs, + ineligibleJobs, resumes, studentId, appliedJobIds = [], }: { - jobs: Job[]; + eligibleJobs: Job[]; + ineligibleJobs: Job[]; resumes: Resume[]; studentId: number; appliedJobIds?: number[]; }) { const [filteredJobs, setFilteredJobs] = useState([]); + const [activeTab, setActiveTab] = useState<'eligible' | 'ineligible'>('eligible'); const [searchTerm, setSearchTerm] = useState(''); const [locationFilter, setLocationFilter] = useState('all'); const [jobTypeFilter, setJobTypeFilter] = useState('all'); const [showLoadMore, setShowLoadMore] = useState(false); + const allJobs = [...eligibleJobs, ...ineligibleJobs]; useEffect(() => { filterJobs(); - }, [jobs, searchTerm, locationFilter, jobTypeFilter]); + }, [eligibleJobs, ineligibleJobs, activeTab, searchTerm, locationFilter, jobTypeFilter]); const filterJobs = () => { - let filtered = [...jobs]; + let base = activeTab === 'eligible' ? eligibleJobs : ineligibleJobs; + let filtered = [...base]; // Search filter if (searchTerm) { @@ -180,7 +185,7 @@ export default function JobsPage({ Clear Filters - {filteredJobs.length} of {jobs.length} jobs + {filteredJobs.length} of {allJobs.length} jobs )} @@ -194,7 +199,7 @@ export default function JobsPage({

Total Jobs

-

{jobs.length}

+

{allJobs.length}

@@ -207,7 +212,7 @@ export default function JobsPage({

Active Companies

- {new Set(jobs.map((job) => job.company.name)).size} + {new Set(allJobs.map((job) => job.company.name)).size}

@@ -221,7 +226,7 @@ export default function JobsPage({

Remote Jobs

- {jobs.filter((job) => job.location.toLowerCase().includes('remote')).length} + {allJobs.filter((job) => job.location.toLowerCase().includes('remote')).length}

@@ -242,6 +247,42 @@ export default function JobsPage({ + {/* Tabs */} + + +
+

Select a category to view jobs

+

Switch between eligible and not eligible jobs based on your profile

+
+
+
+ + +
+
+
+
+ {/* Jobs Grid */}
{displayedJobs.map((job) => ( @@ -298,13 +339,24 @@ export default function JobsPage({
- + {activeTab === 'eligible' ? ( + + ) : ( + + )} {job.link && ( - diff --git a/apps/student/app/(main)/jobs/page.tsx b/apps/student/app/(main)/jobs/page.tsx index b943875..8f486d4 100644 --- a/apps/student/app/(main)/jobs/page.tsx +++ b/apps/student/app/(main)/jobs/page.tsx @@ -1,6 +1,6 @@ import JobsClient from './JobClient'; import { auth } from '@/auth'; -import { db, resumes } from '@workspace/db'; +import { db, resumes, students } from '@workspace/db'; import { eq } from '@workspace/db/drizzle'; import { getStudentApplicationJobIds } from '../actions'; @@ -18,5 +18,49 @@ export default async function JobsPage() { const { success, appliedJobIds } = await getStudentApplicationJobIds(studentId); const studentAppliedJobIds = success ? appliedJobIds : []; - return ; + // Fetch student with grades for eligibility computation + const student = await db.query.students.findFirst({ + where: eq(students.id, studentId), + with: { grades: true }, + }); + + const studentSSC = Number((student as any)?.ssc ?? 0); + const studentHSC = Number((student as any)?.hsc ?? 0); + const grades = (student?.grades || []).map((g) => ({ + sem: g.sem, + sgpi: Number(g.sgpi), + isKT: Boolean(g.isKT), + deadKT: Boolean(g.deadKT), + })); + const hasLiveKT = grades.some((g) => g.isKT); + const hasDeadKT = grades.some((g) => g.deadKT); + const avgCGPA = grades.length > 0 ? Number((grades.reduce((a, b) => a + (b.sgpi || 0), 0) / grades.length).toFixed(2)) : 0; + + const isEligible = (job: typeof jobs[number]) => { + const minCGPA = Number(job.minCGPA || 0); + const minSSC = Number(job.minSSC || 0); + const minHSC = Number(job.minHSC || 0); + const allowDeadKT = Boolean(job.allowDeadKT); + const allowLiveKT = Boolean(job.allowLiveKT); + + if (avgCGPA < minCGPA) return false; + if (studentSSC < minSSC) return false; + if (studentHSC < minHSC) return false; + if (!allowLiveKT && hasLiveKT) return false; + if (!allowDeadKT && hasDeadKT) return false; + return true; + }; + + const eligibleJobs = jobs.filter(isEligible); + const ineligibleJobs = jobs.filter((j) => !isEligible(j)); + + return ( + + ); } diff --git a/apps/student/components/job-application-modal.tsx b/apps/student/components/job-application-modal.tsx index 1cb60ed..5fad9c2 100644 --- a/apps/student/components/job-application-modal.tsx +++ b/apps/student/components/job-application-modal.tsx @@ -69,18 +69,30 @@ export default function JobApplicationModal({ job, studentId, resumes, isApplied } }; - const isDeadlinePassed = new Date() > job.applicationDeadline; + const isDeadlinePassed = new Date() > new Date(job.applicationDeadline as any); + const cannotApplyReason = isApplied + ? 'You have already applied to this job' + : resumes.length === 0 + ? 'No resumes found. Please upload a resume first.' + : isDeadlinePassed + ? 'Application deadline has passed' + : null; return ( - +
+ + {cannotApplyReason && ( + {cannotApplyReason} + )} +
@@ -180,7 +192,7 @@ export default function JobApplicationModal({ job, studentId, resumes, isApplied