Files
encoach_frontend_v4/src/pages/admin/AdminBatchDetail.tsx
Yamen Ahmad 11a7265460 feat(v3): restructure project + add complete frontend
- Restructure: move backend from new_project/ to backend/
- Add full React/TypeScript frontend (37 pages, 17 services, 16 type defs, 11 query hooks)
- Add docs/ with SRS specs, user stories, and workflow documentation
- Update .gitignore for new directory layout

Workflows implemented:
  WF1 User Signup, WF2 Placement Test, WF3 Exam Configuration,
  WF4 General English Exam, WF5 Course Generation,
  WF6 Entity Student Onboarding, AI Course Generation,
  Adaptive Learning Engine UI, White-Label Branding, Score Release

Made-with: Cursor
2026-04-10 17:26:42 +04:00

90 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useParams, Link } from "react-router-dom";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useBatches, useStudents, useTimetable } from "@/hooks/queries";
import { ArrowLeft, Users, Calendar, BookOpen } from "lucide-react";
export default function AdminBatchDetail() {
const { id } = useParams();
const batchId = id ? Number(id) : NaN;
const { data: batchesData, isLoading: lb } = useBatches();
const { data: studentsData, isLoading: ls } = useStudents(
Number.isFinite(batchId) ? { batch_id: batchId, size: 500 } : { size: 500 },
);
const { data: timetableData, isLoading: ltt } = useTimetable();
const batches = batchesData?.items ?? [];
const students = studentsData?.items ?? [];
const timetableSessions = Array.isArray(timetableData) ? timetableData : [];
if (lb || ls || ltt) return <div className="flex items-center justify-center min-h-[400px]"><div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" /></div>;
const batch = batches.find(b => String(b.id) === id);
if (!batch) return <div className="p-8 text-center text-muted-foreground">Batch not found.</div>;
const studentIds = Array.isArray(batch.student_ids) ? batch.student_ids : [];
const batchStudents = Number.isFinite(batchId)
? students.filter((s) => s.batch_id === batchId)
: students.filter((s) => studentIds.includes(s.id));
const coursePrefix = (batch.course_name || "").split(" ")[0];
const batchSessions = timetableSessions.filter(s =>
s.batch_name === batch.name || (coursePrefix && (s.course_name || "").includes(coursePrefix)),
);
return (
<div className="space-y-6">
<div className="flex items-center gap-3">
<Button variant="ghost" size="icon" asChild><Link to="/admin/batches"><ArrowLeft className="h-4 w-4" /></Link></Button>
<div>
<h1 className="text-2xl font-bold">{batch.name}</h1>
<p className="text-muted-foreground">{batch.course_name} · {batch.teacher_name}</p>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-4 gap-4">
<Card><CardContent className="pt-4"><Users className="h-4 w-4 text-primary mb-1" /><p className="text-lg font-bold">{batch.student_count}/{batch.capacity}</p><p className="text-xs text-muted-foreground">Students</p></CardContent></Card>
<Card><CardContent className="pt-4"><Calendar className="h-4 w-4 text-info mb-1" /><p className="text-sm font-bold">{batch.schedule}</p><p className="text-xs text-muted-foreground">Schedule</p></CardContent></Card>
<Card><CardContent className="pt-4"><BookOpen className="h-4 w-4 text-success mb-1" /><p className="text-sm font-bold">{batch.start_date} {batch.end_date}</p><p className="text-xs text-muted-foreground">Duration</p></CardContent></Card>
<Card><CardContent className="pt-4"><Badge variant={batch.status === "active" ? "default" : "secondary"} className="capitalize">{batch.status}</Badge><p className="text-xs text-muted-foreground mt-1">Status</p></CardContent></Card>
</div>
<Card>
<CardHeader><CardTitle className="text-lg">Enrolled Students</CardTitle></CardHeader>
<CardContent>
<Table>
<TableHeader><TableRow><TableHead>Student</TableHead><TableHead>Attendance</TableHead><TableHead>Avg Grade</TableHead><TableHead>Risk</TableHead></TableRow></TableHeader>
<TableBody>
{batchStudents.map(s => (
<TableRow key={s.id}>
<TableCell className="font-medium">{s.name}</TableCell>
<TableCell></TableCell>
<TableCell></TableCell>
<TableCell><Badge variant="secondary" className="capitalize"></Badge></TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card>
<CardHeader><CardTitle className="text-lg">Timetable</CardTitle></CardHeader>
<CardContent className="space-y-2">
{batchSessions.length === 0 ? (
<p className="text-muted-foreground text-sm">No sessions scheduled.</p>
) : batchSessions.map(s => (
<div key={s.id} className="flex items-center justify-between p-3 rounded border">
<div>
<p className="text-sm font-medium">{s.day} {s.start_time}{s.end_time}</p>
<p className="text-xs text-muted-foreground">{s.room}</p>
</div>
<span className="text-xs px-2 py-1 rounded text-white bg-primary">{s.course_name}</span>
</div>
))}
</CardContent>
</Card>
</div>
);
}