markout n shit

This commit is contained in:
Om Lanke
2025-07-05 21:08:14 +05:30
parent d0d6320362
commit 59f9c356ad
12 changed files with 951 additions and 66 deletions

View File

@@ -1,39 +1,47 @@
import { ColumnDef } from '@tanstack/react-table';
// Remove server-specific imports to avoid issues in client bundle
// import { createSelectSchema, students } from '@workspace/db';
// import * as z from 'zod/v4';
import { students, internships, resumes, grades } from '@workspace/db/schema';
import { Badge } from '@workspace/ui/components/badge';
// import { Button } from '@workspace/ui/components/button';
import { Avatar, AvatarFallback, AvatarImage } from '@workspace/ui/components/avatar';
import { Eye, Mail, Phone, MapPin, Calendar, GraduationCap } from 'lucide-react';
// Define the Student interface locally to avoid importing server-side code
export interface Student {
id: number;
email: string;
rollNumber: string | null;
verified: boolean;
firstName: string | null;
middleName: string | null;
lastName: string | null;
mothersName?: string | null;
gender?: string | null;
dob?: Date | null;
personalGmail?: string | null;
phoneNumber?: string | null;
address?: string | null;
profilePicture?: string | null;
degree?: string | null;
branch?: string | null;
year?: string | null;
skills?: string[] | null;
ssc?: number | null;
hsc?: number | null;
isDiploma?: boolean | null;
linkedin?: string | null;
github?: string | null;
createdAt?: Date;
}
type SelectStudent = typeof students.$inferSelect
type SelectInternships = typeof internships.$inferSelect
type SelectResume = typeof resumes.$inferSelect
type SelectGrades = typeof grades.$inferSelect
export type Student = SelectStudent & {
internships: SelectInternships[];
resumes: SelectResume[];
grades: SelectGrades[];
};
// export interface Student {
// id: number;
// email: string;
// rollNumber: string | null;
// verified: boolean;
// firstName: string | null;
// middleName: string | null;
// lastName: string | null;
// mothersName?: string | null;
// gender?: string | null;
// dob?: Date | null;
// personalGmail?: string | null;
// phoneNumber?: string | null;
// address?: string | null;
// profilePicture?: string | null;
// degree?: string | null;
// branch?: string | null;
// year?: string | null;
// skills?: string[] | null;
// ssc?: number | null;
// hsc?: number | null;
// isDiploma?: boolean | null;
// linkedin?: string | null;
// github?: string | null;
// createdAt?: Date;
// }
export const columns: ColumnDef<Student>[] = [
{

View File

@@ -2,7 +2,6 @@
import { useState } from 'react';
import {
ColumnDef,
flexRender,
getCoreRowModel,
getPaginationRowModel,
@@ -23,9 +22,10 @@ import { columns } from './columns';
interface DataTableProps {
data: Student[];
markoutAction: (id: number, state: boolean) => void;
}
export function DataTable({ data }: DataTableProps) {
export function DataTable({ data, markoutAction }: DataTableProps) {
const [selectedStudent, setSelectedStudent] = useState<Student | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
@@ -122,6 +122,9 @@ export function DataTable({ data }: DataTableProps) {
student={selectedStudent}
isOpen={isModalOpen}
onClose={handleCloseModal}
markoutAction={(state: boolean) => {
markoutAction(selectedStudent.id, state);
}}
/>
)}
</>

View File

@@ -6,30 +6,25 @@ import { Button } from '@workspace/ui/components/button';
import { revalidatePath } from 'next/cache';
import { eq } from '@workspace/db/drizzle';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Badge } from '@workspace/ui/components/badge';
import { Separator } from '@workspace/ui/components/separator';
import {
Users,
Plus,
Search,
Filter,
Download,
Mail,
Phone,
MapPin,
Calendar,
GraduationCap,
User,
Linkedin,
Github,
FileText,
Award,
BookOpen
} from 'lucide-react';
async function getData(): Promise<Student[]> {
try {
const data = await db.select().from(students);
const data = await db.query.students.findMany({
with: {
internships: true,
resumes: true,
grades: true,
},
orderBy: (students, { asc }) => [asc(students.createdAt)],
});
return data;
} catch (error) {
console.error('Database error:', error);
@@ -49,6 +44,16 @@ async function addStudent(formData: FormData) {
revalidatePath('/students');
}
async function markoutAction(id: number, state: boolean) {
'use server';
try {
await db.update(students).set({ markedOut: state }).where(eq(students.id, id));
revalidatePath('/students');
} catch (error) {
console.error('Error marking student:', error);
}
}
async function StudentsTable() {
const data = await getData();
@@ -194,7 +199,7 @@ async function StudentsTable() {
</Button>
</div>
) : (
<DataTable data={data} />
<DataTable data={data} markoutAction={markoutAction}/>
)}
</CardContent>
</Card>

View File

@@ -1,11 +1,13 @@
'use client';
import React from 'react';
import { Student } from './columns';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogClose,
} from '@workspace/ui/components/dialog';
import { Badge } from '@workspace/ui/components/badge';
import { Avatar, AvatarFallback, AvatarImage } from '@workspace/ui/components/avatar';
@@ -20,7 +22,6 @@ import {
User,
Linkedin,
Github,
FileText,
Award,
BookOpen,
ExternalLink,
@@ -29,14 +30,16 @@ import {
Download,
Share2
} from 'lucide-react';
import { Switch } from '@workspace/ui/components/switch';
interface StudentDetailsModalProps {
student: Student;
isOpen: boolean;
onClose: () => void;
markoutAction: (state: boolean) => void;
}
export function StudentDetailsModal({ student, isOpen, onClose }: StudentDetailsModalProps) {
export function StudentDetailsModal({ student, isOpen, onClose, markoutAction }: StudentDetailsModalProps) {
const fullName = [
student.firstName,
student.middleName,
@@ -57,6 +60,17 @@ export function StudentDetailsModal({ student, isOpen, onClose }: StudentDetails
return `${value}%`;
};
const [markedOut, setMarkedOut] = React.useState(student.markedOut ?? false);
React.useEffect(() => {
setMarkedOut(student.markedOut ?? false);
}, [student.markedOut]);
const handleMarkoutChange = (checked: boolean) => {
setMarkedOut(checked);
markoutAction(checked);
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
@@ -65,14 +79,28 @@ export function StudentDetailsModal({ student, isOpen, onClose }: StudentDetails
<DialogTitle className="text-2xl font-bold text-gray-800">
Student Details
</DialogTitle>
<Button
variant="ghost"
size="sm"
onClick={onClose}
className="text-gray-500 hover:text-gray-700"
>
<X className="w-5 h-5" />
</Button>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<Switch
checked={markedOut}
onCheckedChange={handleMarkoutChange}
className={
markedOut
? 'bg-red-600 border-red-600 focus-visible:ring-red-600/50'
: 'bg-white border-gray-300 focus-visible:ring-gray-300/50'
}
/>
<span className={markedOut ? 'text-red-600 font-semibold' : 'text-gray-700'}>
Marked Out
</span>
</div>
<DialogClose asChild>
<Button variant="outline" size="icon" className="text-gray-500 hover:text-gray-700">
<X className="w-5 h-5" />
<span className="sr-only">Close</span>
</Button>
</DialogClose>
</div>
</div>
</DialogHeader>
@@ -319,13 +347,9 @@ export function StudentDetailsModal({ student, isOpen, onClose }: StudentDetails
<Button variant="outline" onClick={onClose}>
Close
</Button>
<Button className="flex items-center gap-2">
<Share2 className="w-4 h-4" />
Share Profile
</Button>
</div>
</div>
</DialogContent>
</Dialog>
);
}
}