Files
encoach_backend_new_v3/frontend/src/pages/RubricsPage.tsx
Yamen Ahmad f1c4953a63 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

123 lines
5.6 KiB
TypeScript

import { useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Search, Plus } from "lucide-react";
import AiTipBanner from "@/components/ai/AiTipBanner";
import AiCreationAssistant from "@/components/ai/AiCreationAssistant";
const rubrics = [
{ id: 1, name: "IELTS Writing Task 2", levels: ["A1","A2","B1","B2","C1","C2"], criteria: 4, created: "2025-01-05" },
{ id: 2, name: "Speaking Fluency", levels: ["A1","A2","B1","B2","C1","C2"], criteria: 3, created: "2025-01-10" },
{ id: 3, name: "Reading Comprehension", levels: ["A1","A2","B1","B2","C1"], criteria: 5, created: "2025-02-01" },
];
const rubricGroups = [
{ id: 1, name: "Academic IELTS Full", rubrics: ["IELTS Writing Task 2", "Speaking Fluency", "Reading Comprehension"], created: "2025-02-15" },
{ id: 2, name: "Business English", rubrics: ["Speaking Fluency"], created: "2025-03-01" },
];
export default function RubricsPage() {
const [search, setSearch] = useState("");
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold tracking-tight">Rubrics</h1>
<p className="text-muted-foreground">Create and manage evaluation rubrics with level-based descriptors.</p>
</div>
<div className="flex gap-2">
<AiCreationAssistant type="rubric" />
<Dialog>
<DialogTrigger asChild>
<Button size="sm"><Plus className="h-4 w-4 mr-1" /> Create Rubric</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader><DialogTitle>Create Rubric</DialogTitle></DialogHeader>
<div className="space-y-4">
<div className="space-y-2"><Label>Rubric Name</Label><Input placeholder="e.g. IELTS Writing Task 1" /></div>
<div className="space-y-3">
<Label>Level Descriptors</Label>
{["A1","A2","B1","B2","C1","C2"].map(level => (
<div key={level} className="space-y-1">
<Label className="text-xs text-muted-foreground">{level}</Label>
<Textarea placeholder={`Descriptor for level ${level}...`} className="h-16" />
</div>
))}
</div>
<Button className="w-full">Create Rubric</Button>
</div>
</DialogContent>
</Dialog>
</div>
</div>
<AiTipBanner context="rubrics" variant="recommendation" />
<div className="relative max-w-sm">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search rubrics..." className="pl-9" value={search} onChange={(e) => setSearch(e.target.value)} />
</div>
<Tabs defaultValue="rubrics">
<TabsList>
<TabsTrigger value="rubrics">Rubrics List</TabsTrigger>
<TabsTrigger value="groups">Rubric Groups</TabsTrigger>
</TabsList>
<TabsContent value="rubrics" className="mt-4">
<Card className="border-0 shadow-sm">
<CardContent className="p-0">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead><TableHead>Levels</TableHead><TableHead>Criteria</TableHead><TableHead>Created</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rubrics.map((r) => (
<TableRow key={r.id}>
<TableCell className="font-medium">{r.name}</TableCell>
<TableCell><div className="flex gap-1">{r.levels.map(l => <Badge key={l} variant="outline" className="text-xs">{l}</Badge>)}</div></TableCell>
<TableCell>{r.criteria}</TableCell>
<TableCell>{r.created}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="groups" className="mt-4">
<Card className="border-0 shadow-sm">
<CardContent className="p-0">
<Table>
<TableHeader>
<TableRow>
<TableHead>Group Name</TableHead><TableHead>Rubrics</TableHead><TableHead>Created</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rubricGroups.map((g) => (
<TableRow key={g.id}>
<TableCell className="font-medium">{g.name}</TableCell>
<TableCell><div className="flex gap-1 flex-wrap">{g.rubrics.map(r => <Badge key={r} variant="secondary" className="text-xs">{r}</Badge>)}</div></TableCell>
<TableCell>{g.created}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</div>
);
}