From 900b18da1a7235de1fad857580e94698a72d1634 Mon Sep 17 00:00:00 2001 From: Om Lanke Date: Tue, 8 Jul 2025 16:23:01 +0530 Subject: [PATCH] bhai --- .../app/(main)/jobs/[jobId]/StatusSelect.tsx | 58 ++++++++++ apps/admin/app/(main)/jobs/[jobId]/page.tsx | 100 ++++++++++-------- .../[applicationId]/status/route.ts | 25 +++++ 3 files changed, 140 insertions(+), 43 deletions(-) create mode 100644 apps/admin/app/(main)/jobs/[jobId]/StatusSelect.tsx create mode 100644 apps/admin/app/api/applications/[applicationId]/status/route.ts diff --git a/apps/admin/app/(main)/jobs/[jobId]/StatusSelect.tsx b/apps/admin/app/(main)/jobs/[jobId]/StatusSelect.tsx new file mode 100644 index 0000000..d4b91a4 --- /dev/null +++ b/apps/admin/app/(main)/jobs/[jobId]/StatusSelect.tsx @@ -0,0 +1,58 @@ +'use client'; + +import { useState, useTransition } from 'react'; +import { + Select, + SelectTrigger, + SelectContent, + SelectItem, + SelectValue, +} from '@workspace/ui/components/select'; + +const STATUS_OPTIONS = [ + 'in review', + 'Online Assessment', + 'Interview round', + 'offer given', + 'accepted', + 'rejected', +]; + +interface StatusSelectProps { + applicationId: number; + initialStatus: string; + studentId: number; +} + +export default function StatusSelect({ + applicationId, + initialStatus, + studentId, +}: StatusSelectProps) { + const [status, setStatus] = useState(initialStatus); + const [isPending, startTransition] = useTransition(); + + const handleChange = (value: string) => { + setStatus(value); // Optimistic update + startTransition(async () => { + await fetch(`/api/applications/${applicationId}/status`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ status: value, studentId }), + }); + }); + }; + + return ( + + ); +} diff --git a/apps/admin/app/(main)/jobs/[jobId]/page.tsx b/apps/admin/app/(main)/jobs/[jobId]/page.tsx index efd02cc..577fd08 100644 --- a/apps/admin/app/(main)/jobs/[jobId]/page.tsx +++ b/apps/admin/app/(main)/jobs/[jobId]/page.tsx @@ -18,6 +18,7 @@ import { Clock } from 'lucide-react'; import Link from 'next/link'; +import StatusSelect from './StatusSelect'; interface JobPageProps { params: { jobId: string }; @@ -33,7 +34,11 @@ export default async function JobDetailPage({ params }: JobPageProps) { if (jobRes.length === 0 || !jobRes[0]) notFound(); const job = jobRes[0]; - const companyRes = await db.select().from(companies).where(eq(companies.id, job.companyId)).limit(1); + const companyRes = await db + .select() + .from(companies) + .where(eq(companies.id, job.companyId)) + .limit(1); const company = companyRes[0]; const applicants = await db @@ -43,6 +48,7 @@ export default async function JobDetailPage({ params }: JobPageProps) { firstName: students.firstName, lastName: students.lastName, email: students.email, + studentId: students.id, }) .from(applications) .leftJoin(students, eq(applications.studentId, students.id)) @@ -80,9 +86,9 @@ export default async function JobDetailPage({ params }: JobPageProps) {
{company?.imageURL ? ( - {company.name} ) : ( @@ -98,11 +104,11 @@ export default async function JobDetailPage({ params }: JobPageProps) {
- @@ -131,7 +137,9 @@ export default async function JobDetailPage({ params }: JobPageProps) {

Application Deadline

-

{job.applicationDeadline.toLocaleDateString()}

+

+ {job.applicationDeadline.toLocaleDateString()} +

@@ -145,10 +153,10 @@ export default async function JobDetailPage({ params }: JobPageProps) { {/* Job Link */}
- @@ -199,22 +207,30 @@ export default async function JobDetailPage({ params }: JobPageProps) {
-
-
+
+
Dead KT: {job.allowDeadKT ? 'Allowed' : 'Not Allowed'}
-
-
+
+
Live KT: {job.allowLiveKT ? 'Allowed' : 'Not Allowed'} @@ -238,9 +254,9 @@ export default async function JobDetailPage({ params }: JobPageProps) {
{company?.imageURL ? ( - {company.name} ) : ( @@ -277,7 +293,9 @@ export default async function JobDetailPage({ params }: JobPageProps) {
Application Deadline - {job.applicationDeadline.toLocaleDateString()} + + {job.applicationDeadline.toLocaleDateString()} +
@@ -301,7 +319,9 @@ export default async function JobDetailPage({ params }: JobPageProps) {

No applications yet

-

Students will appear here once they apply for this job.

+

+ Students will appear here once they apply for this job. +

) : (
@@ -317,22 +337,16 @@ export default async function JobDetailPage({ params }: JobPageProps) { {applicants.map((applicant) => ( - {`${applicant.firstName ?? ''} ${applicant.lastName ?? ''}`.trim() || 'Unknown'} + {`${applicant.firstName ?? ''} ${applicant.lastName ?? ''}`.trim() || + 'Unknown'} {applicant.email} - - {applicant.status.charAt(0).toUpperCase() + applicant.status.slice(1)} - + ))} diff --git a/apps/admin/app/api/applications/[applicationId]/status/route.ts b/apps/admin/app/api/applications/[applicationId]/status/route.ts new file mode 100644 index 0000000..5f94957 --- /dev/null +++ b/apps/admin/app/api/applications/[applicationId]/status/route.ts @@ -0,0 +1,25 @@ +import { db, applications } from '@workspace/db'; +import { eq } from '@workspace/db/drizzle'; +import { NextRequest, NextResponse } from 'next/server'; + +export async function PATCH(req: NextRequest, { params }: { params: { applicationId: string } }) { + const applicationId = Number(params.applicationId); + if (isNaN(applicationId)) { + return NextResponse.json({ error: 'Invalid applicationId' }, { status: 400 }); + } + + const { status } = await req.json(); + if (!status) { + return NextResponse.json({ error: 'Missing status' }, { status: 400 }); + } + + const result = await db.update(applications) + .set({ status }) + .where(eq(applications.id, applicationId)); + + if (result.rowCount === 0) { + return NextResponse.json({ error: 'Application not found' }, { status: 404 }); + } + + return NextResponse.json({ success: true }); +} \ No newline at end of file