feat: complete premium NEET/JEE platform with admin, student dashboards, and upgraded branding
This commit is contained in:
87
src/app/admin/agents/page.tsx
Normal file
87
src/app/admin/agents/page.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Activity, BrainCircuit, Zap, Server, ShieldCheck } from "lucide-react"
|
||||
|
||||
export default function AgentsPage() {
|
||||
const agents = [
|
||||
{ name: "DPP Generator Node", status: "Healthy", latency: "140ms", tokens: "4.2M", successRate: "99.9%" },
|
||||
{ name: "Tutor Agent (Physics)", status: "Healthy", latency: "320ms", tokens: "8.1M", successRate: "98.5%" },
|
||||
{ name: "Tutor Agent (Chem/Bio)", status: "Healthy", latency: "290ms", tokens: "6.5M", successRate: "99.1%" },
|
||||
{ name: "Evaluator Node", status: "Under Load", latency: "850ms", tokens: "12.4M", successRate: "97.2%" },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">AI Agents Monitor</h1>
|
||||
<p className="text-muted-foreground mt-1">Real-time telemetry for internal LLM orchestration nodes.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<Card className="border-border bg-secondary/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Global API Status</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold flex items-center gap-3">
|
||||
<div className="size-3 rounded-full bg-[#00F0FF] animate-pulse"></div> Operational
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border bg-secondary/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Total Tokens Used (24h)</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-primary">31.2M</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border bg-secondary/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Avg Generation Latency</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold">400ms</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl font-bold pt-4 border-b border-border pb-2">Active Microservices</h2>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{agents.map((agent, i) => (
|
||||
<Card key={i} className={`border ${agent.status === 'Healthy' ? 'border-border' : 'border-yellow-500/50 shadow-[0_0_15px_-5px_rgba(234,179,8,0.3)]'} bg-background`}>
|
||||
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
||||
<CardTitle className="text-lg font-bold flex items-center gap-2">
|
||||
<BrainCircuit className="text-[#00F0FF]" size={20} /> {agent.name}
|
||||
</CardTitle>
|
||||
<div className={`px-2.5 py-0.5 rounded-full text-xs font-bold ${agent.status === 'Healthy' ? 'bg-[#00F0FF]/10 text-[#00F0FF]' : 'bg-yellow-500/10 text-yellow-500 animate-pulse'}`}>
|
||||
{agent.status}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-3 gap-4 mt-4">
|
||||
<div className="space-y-1">
|
||||
<div className="text-xs text-muted-foreground flex items-center gap-1"><Zap size={12}/> Latency</div>
|
||||
<div className="font-mono text-lg">{agent.latency}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-xs text-muted-foreground flex items-center gap-1"><Server size={12}/> Tokens</div>
|
||||
<div className="font-mono text-lg">{agent.tokens}</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-xs text-muted-foreground flex items-center gap-1"><ShieldCheck size={12}/> Success</div>
|
||||
<div className="font-mono text-lg">{agent.successRate}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full bg-secondary h-1.5 rounded-full mt-6 overflow-hidden">
|
||||
<div
|
||||
className={`h-full ${agent.status === 'Healthy' ? 'bg-[#00F0FF]' : 'bg-yellow-500'}`}
|
||||
style={{ width: agent.successRate }}
|
||||
></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
62
src/app/admin/layout.tsx
Normal file
62
src/app/admin/layout.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
"use client"
|
||||
|
||||
import { ReactNode } from "react"
|
||||
import { LayoutDashboard, Users, Database, Terminal, Settings } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
import { usePathname } from "next/navigation"
|
||||
|
||||
export default function AdminLayout({ children }: { children: ReactNode }) {
|
||||
const pathname = usePathname()
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-background overflow-hidden text-foreground selection:bg-[#00F0FF]/20">
|
||||
{/* Sidebar */}
|
||||
<aside className="w-64 border-r border-border bg-secondary/10 flex flex-col hidden md:flex">
|
||||
<div className="p-6 border-b border-border">
|
||||
<Link href="/admin" className="block relative h-16 w-full hover:opacity-90 transition-opacity">
|
||||
<Image
|
||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
|
||||
alt="PragatiVeer Admin" fill className="object-contain object-left scale-135 origin-left dark:hidden" priority
|
||||
/>
|
||||
<Image
|
||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_dark_background.svg"
|
||||
alt="PragatiVeer Admin" fill className="object-contain object-left scale-135 origin-left hidden dark:block" priority
|
||||
/>
|
||||
</Link>
|
||||
<div className="mt-3 text-xs font-bold uppercase tracking-widest text-[#00F0FF]">Admin Panel</div>
|
||||
</div>
|
||||
<nav className="flex-1 px-4 space-y-1.5 mt-6">
|
||||
<NavItem href="/admin" icon={<LayoutDashboard size={18} />} label="Command Center" active={pathname === "/admin"} />
|
||||
<NavItem href="/admin/questions" icon={<Database size={18} />} label="Question Bank" active={pathname.startsWith("/admin/questions")} />
|
||||
<NavItem href="/admin/agents" icon={<Terminal size={18} />} label="AI Agents" active={pathname.startsWith("/admin/agents")} />
|
||||
<NavItem href="/admin/students" icon={<Users size={18} />} label="Students" active={pathname.startsWith("/admin/students")} />
|
||||
</nav>
|
||||
<div className="p-4 border-t border-border">
|
||||
<NavItem href="/admin/settings" icon={<Settings size={18} />} label="System Settings" active={pathname.startsWith("/admin/settings")} />
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 overflow-y-auto bg-background">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function NavItem({ href, icon, label, active }: { href: string, icon: React.ReactNode, label: string, active?: boolean }) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className={`flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all duration-300 ${
|
||||
active
|
||||
? "bg-[#00F0FF]/10 text-[#00F0FF] font-medium border border-[#00F0FF]/20"
|
||||
: "text-muted-foreground hover:bg-secondary hover:text-foreground font-medium"
|
||||
}`}
|
||||
>
|
||||
{icon}
|
||||
<span className="text-sm">{label}</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
200
src/app/admin/page.tsx
Normal file
200
src/app/admin/page.tsx
Normal file
@@ -0,0 +1,200 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Terminal, Users, Database, Activity, RefreshCw } from "lucide-react"
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'recharts'
|
||||
|
||||
const data = [
|
||||
{ name: 'Mon', accuracy: 88, tokens: 1.2 },
|
||||
{ name: 'Tue', accuracy: 90, tokens: 1.5 },
|
||||
{ name: 'Wed', accuracy: 89, tokens: 1.8 },
|
||||
{ name: 'Thu', accuracy: 92, tokens: 2.1 },
|
||||
{ name: 'Fri', accuracy: 95, tokens: 2.4 },
|
||||
{ name: 'Sat', accuracy: 94, tokens: 2.2 },
|
||||
{ name: 'Sun', accuracy: 96, tokens: 2.8 },
|
||||
];
|
||||
|
||||
export default function AdminDashboard() {
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500">
|
||||
<header className="flex items-center justify-between border-b border-border pb-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tighter text-foreground">Command Center</h1>
|
||||
<p className="text-muted-foreground mt-1 font-medium">Real-time system monitoring and agent status.</p>
|
||||
</div>
|
||||
<Button variant="outline" className="gap-2 border-[#00F0FF]/50 text-[#00F0FF] bg-[#00F0FF]/5 hover:bg-[#00F0FF]/10 hover:text-[#00F0FF] rounded-xl font-medium shadow-[0_0_15px_-5px_#00F0FF]">
|
||||
<RefreshCw size={16} /> Refresh Data
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
{/* KPI Stats */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<Card className="bg-secondary/10 border-border/50 rounded-2xl">
|
||||
<CardHeader className="pb-2 flex flex-row items-center justify-between">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Total Revenue</CardTitle>
|
||||
<div className="p-2 bg-primary/20 text-primary rounded-lg"><Activity size={16}/></div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">₹12.4M</div>
|
||||
<p className="text-xs text-primary mt-1 font-medium">+14.2% from last month</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-secondary/10 border-border/50 rounded-2xl">
|
||||
<CardHeader className="pb-2 flex flex-row items-center justify-between">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Active Students</CardTitle>
|
||||
<div className="p-2 bg-secondary text-foreground rounded-lg"><Users size={16}/></div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">45,231</div>
|
||||
<p className="text-xs text-muted-foreground mt-1 font-medium">+2,401 this week</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-[#00F0FF]/5 border-[#00F0FF]/30 shadow-[0_0_20px_-10px_#00F0FF] rounded-2xl">
|
||||
<CardHeader className="pb-2 flex flex-row items-center justify-between">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">AI Agent Accuracy</CardTitle>
|
||||
<div className="p-2 bg-[#00F0FF]/20 text-[#00F0FF] rounded-lg"><Terminal size={16}/></div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-[#00F0FF]">96.4%</div>
|
||||
<p className="text-xs text-[#00F0FF]/70 mt-1 font-medium">Based on 1.2M interactions</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="bg-secondary/10 border-border/50 rounded-2xl">
|
||||
<CardHeader className="pb-2 flex flex-row items-center justify-between">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">Question Bank</CardTitle>
|
||||
<div className="p-2 bg-secondary text-foreground rounded-lg"><Database size={16}/></div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">142k</div>
|
||||
<p className="text-xs text-muted-foreground mt-1 font-medium">1.2k added today</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Charts */}
|
||||
<Card className="lg:col-span-2 bg-background border-border rounded-3xl">
|
||||
<CardHeader>
|
||||
<CardTitle>AI Token Usage vs Accuracy</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="h-[300px] w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={data} margin={{ top: 10, right: 30, left: 0, bottom: 0 }}>
|
||||
<defs>
|
||||
<linearGradient id="colorTokens" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#00F0FF" stopOpacity={0.3}/>
|
||||
<stop offset="95%" stopColor="#00F0FF" stopOpacity={0}/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#262626" vertical={false} />
|
||||
<XAxis dataKey="name" stroke="#737373" fontSize={12} tickLine={false} axisLine={false} />
|
||||
<YAxis stroke="#737373" fontSize={12} tickLine={false} axisLine={false} tickFormatter={(value) => `${value}M`} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: '#0a0a0a', borderColor: '#262626', borderRadius: '12px' }}
|
||||
itemStyle={{ color: '#00F0FF', fontWeight: 'bold' }}
|
||||
/>
|
||||
<Area type="monotone" dataKey="tokens" stroke="#00F0FF" strokeWidth={3} fillOpacity={1} fill="url(#colorTokens)" />
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Live Agent Status */}
|
||||
<Card className="bg-background border-border flex flex-col rounded-3xl">
|
||||
<CardHeader>
|
||||
<CardTitle>Live Agent Status</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 overflow-y-auto pr-2 space-y-4">
|
||||
<div className="flex items-center justify-between p-4 rounded-2xl border border-border bg-secondary/10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative flex h-3 w-3">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-emerald-500"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-bold">DPP Generator</h4>
|
||||
<p className="text-xs text-muted-foreground font-mono mt-1">Latency: 142ms</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="outline" className="text-emerald-500 border-emerald-500/30 bg-emerald-500/10 font-bold">Healthy</Badge>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between p-4 rounded-2xl border border-border bg-secondary/10">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative flex h-3 w-3">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-emerald-500"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-bold">Tutor Agent</h4>
|
||||
<p className="text-xs text-muted-foreground font-mono mt-1">Latency: 840ms</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="outline" className="text-emerald-500 border-emerald-500/30 bg-emerald-500/10 font-bold">Healthy</Badge>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between p-4 rounded-2xl border border-amber-500/30 bg-amber-500/5">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative flex h-3 w-3">
|
||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-amber-500"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-bold text-amber-500">Evaluator Node</h4>
|
||||
<p className="text-xs text-amber-500/70 font-mono mt-1">Latency: 2100ms</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="outline" className="text-amber-500 border-amber-500/30 bg-amber-500/10 font-bold">Degraded</Badge>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Question Bank Manager Preview */}
|
||||
<Card className="bg-background border-border rounded-3xl">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<CardTitle>Recent Question Uploads</CardTitle>
|
||||
</div>
|
||||
<Button size="sm" className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-bold rounded-xl h-10 px-4">Add Question</Button>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="rounded-2xl border border-border overflow-hidden">
|
||||
<table className="w-full text-sm text-left">
|
||||
<thead className="bg-secondary/50 text-muted-foreground font-medium border-b border-border">
|
||||
<tr>
|
||||
<th className="px-5 py-4">ID</th>
|
||||
<th className="px-5 py-4">Subject</th>
|
||||
<th className="px-5 py-4">Topic</th>
|
||||
<th className="px-5 py-4">Preview</th>
|
||||
<th className="px-5 py-4 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-border">
|
||||
<tr className="hover:bg-secondary/20 transition-colors">
|
||||
<td className="px-5 py-4 font-mono text-muted-foreground font-medium">#Q-8942</td>
|
||||
<td className="px-5 py-4"><Badge variant="outline" className="bg-background">Physics</Badge></td>
|
||||
<td className="px-5 py-4 font-medium">Thermodynamics</td>
|
||||
<td className="px-5 py-4 text-muted-foreground truncate max-w-[300px]">An ideal gas undergoes an isothermal expansion...</td>
|
||||
<td className="px-5 py-4 text-right">
|
||||
<Button variant="ghost" size="sm" className="text-[#00F0FF] hover:text-[#00F0FF] hover:bg-[#00F0FF]/10 font-bold rounded-lg">Edit</Button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="hover:bg-secondary/20 transition-colors">
|
||||
<td className="px-5 py-4 font-mono text-muted-foreground font-medium">#Q-8941</td>
|
||||
<td className="px-5 py-4"><Badge variant="outline" className="bg-background">Math</Badge></td>
|
||||
<td className="px-5 py-4 font-medium">Calculus</td>
|
||||
<td className="px-5 py-4 text-muted-foreground truncate max-w-[300px]">Evaluate the integral of e^x sin(x) dx...</td>
|
||||
<td className="px-5 py-4 text-right">
|
||||
<Button variant="ghost" size="sm" className="text-[#00F0FF] hover:text-[#00F0FF] hover:bg-[#00F0FF]/10 font-bold rounded-lg">Edit</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
102
src/app/admin/questions/page.tsx
Normal file
102
src/app/admin/questions/page.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Search, Plus, Filter, MoreHorizontal, Edit, Trash } from "lucide-react"
|
||||
|
||||
export default function QuestionsPage() {
|
||||
const questions = [
|
||||
{ id: "Q-NEET-2026-001", subject: "Physics", chapter: "Thermodynamics", type: "MCQ", difficulty: "Hard", status: "Active" },
|
||||
{ id: "Q-NEET-2026-002", subject: "Chemistry", chapter: "Organic Chemistry", type: "Assertion/Reason", difficulty: "Medium", status: "Active" },
|
||||
{ id: "Q-JEE-2026-003", subject: "Mathematics", chapter: "Calculus", type: "Numerical", difficulty: "Expert", status: "Review" },
|
||||
{ id: "Q-NEET-2026-004", subject: "Biology", chapter: "Genetics", type: "MCQ", difficulty: "Easy", status: "Active" },
|
||||
{ id: "Q-JEE-2026-005", subject: "Physics", chapter: "Mechanics", type: "MCQ", difficulty: "Medium", status: "Draft" },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Question Bank</h1>
|
||||
<p className="text-muted-foreground mt-1">Manage and curate the global repository for NEET/JEE.</p>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Button variant="outline" className="border-border hover:bg-secondary"><Filter size={16} className="mr-2"/> Filter</Button>
|
||||
<Button className="bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 font-bold"><Plus size={16} className="mr-2"/> Add Question</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-secondary/10 border border-border rounded-xl overflow-hidden backdrop-blur-sm">
|
||||
<div className="p-4 border-b border-border flex items-center gap-4">
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" size={16} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search by ID, concept, or chapter..."
|
||||
className="w-full bg-background border border-border rounded-lg pl-10 pr-4 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#00F0FF]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left text-sm whitespace-nowrap">
|
||||
<thead className="bg-secondary/30 text-muted-foreground border-b border-border">
|
||||
<tr>
|
||||
<th className="px-6 py-4 font-semibold">Question ID</th>
|
||||
<th className="px-6 py-4 font-semibold">Subject</th>
|
||||
<th className="px-6 py-4 font-semibold">Chapter</th>
|
||||
<th className="px-6 py-4 font-semibold">Type</th>
|
||||
<th className="px-6 py-4 font-semibold">Difficulty</th>
|
||||
<th className="px-6 py-4 font-semibold">Status</th>
|
||||
<th className="px-6 py-4 font-semibold text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-border">
|
||||
{questions.map((q) => (
|
||||
<tr key={q.id} className="hover:bg-secondary/20 transition-colors">
|
||||
<td className="px-6 py-4 font-mono font-medium">{q.id}</td>
|
||||
<td className="px-6 py-4">
|
||||
<Badge variant="outline" className="bg-background">{q.subject}</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-4">{q.chapter}</td>
|
||||
<td className="px-6 py-4 text-muted-foreground">{q.type}</td>
|
||||
<td className="px-6 py-4">
|
||||
<Badge className={
|
||||
q.difficulty === "Expert" ? "bg-red-500/10 text-red-500 border-red-500/20" :
|
||||
q.difficulty === "Hard" ? "bg-orange-500/10 text-orange-500 border-orange-500/20" :
|
||||
q.difficulty === "Medium" ? "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" :
|
||||
"bg-green-500/10 text-green-500 border-green-500/20"
|
||||
} variant="outline">
|
||||
{q.difficulty}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<Badge className={
|
||||
q.status === "Active" ? "bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20" :
|
||||
q.status === "Review" ? "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" :
|
||||
"bg-muted/50 text-muted-foreground border-border"
|
||||
} variant="outline">
|
||||
{q.status}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-right">
|
||||
<div className="flex justify-end gap-2 text-muted-foreground">
|
||||
<button className="p-1.5 hover:text-[#00F0FF] hover:bg-secondary rounded"><Edit size={16} /></button>
|
||||
<button className="p-1.5 hover:text-red-500 hover:bg-secondary rounded"><Trash size={16} /></button>
|
||||
<button className="p-1.5 hover:text-foreground hover:bg-secondary rounded"><MoreHorizontal size={16} /></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 border-t border-border flex justify-between items-center text-sm text-muted-foreground">
|
||||
<span>Showing 1 to 5 of 12,405 entries</span>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" disabled>Previous</Button>
|
||||
<Button variant="outline" size="sm">Next</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
69
src/app/admin/settings/page.tsx
Normal file
69
src/app/admin/settings/page.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
|
||||
export default function SettingsPage() {
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500 max-w-4xl">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">System Settings</h1>
|
||||
<p className="text-muted-foreground mt-1">Configure global application variables and security protocols.</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card className="border-border bg-secondary/10">
|
||||
<CardHeader>
|
||||
<CardTitle>AI Inference Configuration</CardTitle>
|
||||
<CardDescription>Manage the underlying LLM models and API keys for the AI agents.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-bold">Primary Model Name</label>
|
||||
<input type="text" defaultValue="gemini-1.5-pro-experimental" className="w-full bg-background border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#00F0FF]" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-bold">OpenAI API Key (Fallback)</label>
|
||||
<input type="password" defaultValue="sk-........................" className="w-full bg-background border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-[#00F0FF]" />
|
||||
</div>
|
||||
<Button className="bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 font-bold">Save Configuration</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-border bg-secondary/10">
|
||||
<CardHeader>
|
||||
<CardTitle>Platform Maintenance</CardTitle>
|
||||
<CardDescription>Global toggles for site availability.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="flex items-center justify-between p-4 bg-background border border-border rounded-xl">
|
||||
<div>
|
||||
<div className="font-bold">Maintenance Mode</div>
|
||||
<div className="text-sm text-muted-foreground">Disable all student access and show maintenance screen.</div>
|
||||
</div>
|
||||
<div className="h-6 w-11 rounded-full bg-secondary border border-border relative cursor-pointer">
|
||||
<div className="absolute left-1 top-1 size-4 bg-muted-foreground rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-4 bg-background border border-border rounded-xl">
|
||||
<div>
|
||||
<div className="font-bold">Allow New Registrations</div>
|
||||
<div className="text-sm text-muted-foreground">Open the `/signup` route for new users.</div>
|
||||
</div>
|
||||
<div className="h-6 w-11 rounded-full bg-primary border border-primary relative cursor-pointer shadow-[0_0_10px_var(--color-primary)]">
|
||||
<div className="absolute right-1 top-1 size-4 bg-primary-foreground rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-red-500/20 bg-red-500/5">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-red-500">Danger Zone</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button className="bg-red-500 text-white hover:bg-red-600 font-bold">Purge Generated Cache</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
79
src/app/admin/students/page.tsx
Normal file
79
src/app/admin/students/page.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Search, Download, MoreVertical } from "lucide-react"
|
||||
|
||||
export default function StudentsPage() {
|
||||
const students = [
|
||||
{ id: "STU-001", name: "Rahul Sharma", email: "rahul@example.com", tier: "AI Pro", target: "NEET", joined: "Oct 12, 2025", tests: 42 },
|
||||
{ id: "STU-002", name: "Priya Patel", email: "priya@example.com", tier: "Basic", target: "JEE Main", joined: "Nov 05, 2025", tests: 14 },
|
||||
{ id: "STU-003", name: "Amit Kumar", email: "amit@example.com", tier: "AI Pro", target: "JEE Adv", joined: "Dec 01, 2025", tests: 89 },
|
||||
{ id: "STU-004", name: "Sneha Reddy", email: "sneha@example.com", tier: "AI Pro", target: "NEET", joined: "Dec 15, 2025", tests: 34 },
|
||||
{ id: "STU-005", name: "Vikram Singh", email: "vikram@example.com", tier: "Basic", target: "NEET", joined: "Jan 10, 2026", tests: 5 },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Student Directory</h1>
|
||||
<p className="text-muted-foreground mt-1">Manage users, view engagement, and handle subscriptions.</p>
|
||||
</div>
|
||||
<Button variant="outline" className="border-border hover:bg-secondary"><Download size={16} className="mr-2"/> Export CSV</Button>
|
||||
</div>
|
||||
|
||||
<div className="bg-secondary/10 border border-border rounded-xl overflow-hidden backdrop-blur-sm">
|
||||
<div className="p-4 border-b border-border flex items-center gap-4">
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" size={16} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search by name, email, or ID..."
|
||||
className="w-full bg-background border border-border rounded-lg pl-10 pr-4 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-primary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left text-sm whitespace-nowrap">
|
||||
<thead className="bg-secondary/30 text-muted-foreground border-b border-border">
|
||||
<tr>
|
||||
<th className="px-6 py-4 font-semibold">Student</th>
|
||||
<th className="px-6 py-4 font-semibold">Plan Tier</th>
|
||||
<th className="px-6 py-4 font-semibold">Target Exam</th>
|
||||
<th className="px-6 py-4 font-semibold">Tests Taken</th>
|
||||
<th className="px-6 py-4 font-semibold">Joined Date</th>
|
||||
<th className="px-6 py-4 font-semibold text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-border">
|
||||
{students.map((s) => (
|
||||
<tr key={s.id} className="hover:bg-secondary/20 transition-colors">
|
||||
<td className="px-6 py-4">
|
||||
<div className="font-bold">{s.name}</div>
|
||||
<div className="text-muted-foreground text-xs">{s.email}</div>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<Badge className={
|
||||
s.tier === "AI Pro" ? "bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20 font-bold" : "bg-secondary text-foreground border-border"
|
||||
} variant="outline">
|
||||
{s.tier}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-4 font-medium">{s.target}</td>
|
||||
<td className="px-6 py-4 font-mono">{s.tests}</td>
|
||||
<td className="px-6 py-4 text-muted-foreground">{s.joined}</td>
|
||||
<td className="px-6 py-4 text-right">
|
||||
<button className="p-1.5 hover:text-foreground hover:bg-secondary rounded"><MoreVertical size={16} /></button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 border-t border-border text-sm text-muted-foreground text-center">
|
||||
Showing top 5 active students out of 12,400 total.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user