feat: complete UI tasks, backend optimizations, coupon admin, user kundli

This commit is contained in:
2026-07-10 12:36:56 +05:30
parent 149d365218
commit d5199682e3
16 changed files with 782 additions and 78 deletions

View File

@@ -0,0 +1,202 @@
"use client"
import { useEffect, useState } from "react"
import { useParams, useRouter } from "next/navigation"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { ArrowLeft, Loader2, User, Mail, Target, Award, Calendar, Activity, BookOpen } from "lucide-react"
export default function StudentKundliPage() {
const params = useParams()
const router = useRouter()
const studentId = params.studentId as string
const [loading, setLoading] = useState(true)
const [userData, setUserData] = useState<any>(null)
useEffect(() => {
// Simulated fetch of student's complete "Kundli"
setTimeout(() => {
setUserData({
id: studentId,
name: "Rahul Sharma",
email: "rahul@example.com",
target: "NEET",
tier: "AI Pro",
joined: "Oct 12, 2025",
stats: {
total_tests: 42,
average_score: "78%",
streak: 45,
total_questions_solved: 3450,
ai_coach_interactions: 124
},
recent_tests: [
{ id: 1, name: "Full Syllabus NEET Mock #4", score: "620/720", date: "2 days ago", percentile: "98.5%" },
{ id: 2, name: "Physics: Kinematics DPP", score: "45/50", date: "4 days ago", percentile: "95.2%" },
{ id: 3, name: "Biology: Human Reproduction", score: "88/100", date: "1 week ago", percentile: "99.1%" }
],
payments: [
{ id: "PAY_1", amount: "₹1599", date: "Oct 12, 2025", plan: "AI Pro (Yearly)", status: "Success" }
],
weak_topics: ["Rotational Dynamics", "Organic Chemistry", "Genetics"]
})
setLoading(false)
}, 800)
}, [studentId])
if (loading) {
return <div className="h-full flex items-center justify-center"><Loader2 className="animate-spin text-muted-foreground w-8 h-8" /></div>
}
if (!userData) return <div>User not found</div>
return (
<div className="p-8 space-y-6 max-w-6xl mx-auto animate-in fade-in duration-500">
<Button variant="ghost" onClick={() => router.back()} className="text-muted-foreground hover:text-foreground mb-4">
<ArrowLeft size={16} className="mr-2" /> Back to Students
</Button>
<div className="flex flex-col md:flex-row gap-6">
{/* User Identity Card */}
<Card className="flex-1 border-border shadow-sm">
<CardHeader className="pb-4 border-b border-border">
<div className="flex items-center gap-4">
<div className="w-16 h-16 rounded-full bg-secondary flex items-center justify-center text-2xl font-bold">
{userData.name.charAt(0)}
</div>
<div>
<CardTitle className="text-2xl">{userData.name}</CardTitle>
<CardDescription className="flex items-center gap-2 mt-1">
<Mail size={14} /> {userData.email}
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="pt-6 grid grid-cols-2 gap-y-4 gap-x-8">
<div>
<div className="text-sm text-muted-foreground flex items-center gap-2 mb-1"><Target size={14}/> Target Exam</div>
<div className="font-medium">{userData.target}</div>
</div>
<div>
<div className="text-sm text-muted-foreground flex items-center gap-2 mb-1"><Award size={14}/> Plan Tier</div>
<Badge className="bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20">{userData.tier}</Badge>
</div>
<div>
<div className="text-sm text-muted-foreground flex items-center gap-2 mb-1"><Calendar size={14}/> Joined</div>
<div className="font-medium">{userData.joined}</div>
</div>
<div>
<div className="text-sm text-muted-foreground flex items-center gap-2 mb-1"><User size={14}/> User ID</div>
<div className="font-mono text-xs">{userData.id}</div>
</div>
</CardContent>
</Card>
{/* Stats Summary */}
<div className="grid grid-cols-2 gap-4 flex-1">
<Card className="bg-secondary/20 border-border">
<CardContent className="p-4 flex flex-col items-center justify-center h-full text-center">
<div className="text-3xl font-black text-[#00F0FF]">{userData.stats.total_tests}</div>
<div className="text-sm text-muted-foreground mt-1">Tests Attempted</div>
</CardContent>
</Card>
<Card className="bg-secondary/20 border-border">
<CardContent className="p-4 flex flex-col items-center justify-center h-full text-center">
<div className="text-3xl font-black text-orange-500">{userData.stats.streak}</div>
<div className="text-sm text-muted-foreground mt-1">Day Streak</div>
</CardContent>
</Card>
<Card className="bg-secondary/20 border-border">
<CardContent className="p-4 flex flex-col items-center justify-center h-full text-center">
<div className="text-3xl font-black">{userData.stats.average_score}</div>
<div className="text-sm text-muted-foreground mt-1">Avg. Accuracy</div>
</CardContent>
</Card>
<Card className="bg-secondary/20 border-border">
<CardContent className="p-4 flex flex-col items-center justify-center h-full text-center">
<div className="text-3xl font-black">{userData.stats.total_questions_solved}</div>
<div className="text-sm text-muted-foreground mt-1">Questions Solved</div>
</CardContent>
</Card>
</div>
</div>
{/* Recent Activity & Weak Topics */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<Card className="lg:col-span-2 border-border shadow-sm">
<CardHeader>
<CardTitle className="flex items-center gap-2"><Activity size={18} className="text-[#00F0FF]"/> Recent Tests</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
{userData.recent_tests.map((test: any) => (
<div key={test.id} className="flex items-center justify-between p-3 rounded-lg border border-border bg-secondary/10">
<div>
<div className="font-bold">{test.name}</div>
<div className="text-xs text-muted-foreground mt-1">{test.date}</div>
</div>
<div className="text-right">
<div className="font-mono font-bold text-[#00F0FF]">{test.score}</div>
<div className="text-xs text-muted-foreground mt-1">{test.percentile} %ile</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
<Card className="border-border shadow-sm">
<CardHeader>
<CardTitle className="flex items-center gap-2"><BookOpen size={18} className="text-red-500"/> AI Identified Weaknesses</CardTitle>
</CardHeader>
<CardContent>
<ul className="space-y-3">
{userData.weak_topics.map((topic: string, i: number) => (
<li key={i} className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-red-500" />
<span className="font-medium text-sm">{topic}</span>
</li>
))}
</ul>
</CardContent>
</Card>
</div>
{/* Payment History */}
<Card className="border-border shadow-sm">
<CardHeader>
<CardTitle>Payment History</CardTitle>
</CardHeader>
<CardContent>
<div className="border border-border rounded-lg overflow-hidden">
<table className="w-full text-left text-sm">
<thead className="bg-secondary/30">
<tr>
<th className="px-4 py-3 font-semibold">Transaction ID</th>
<th className="px-4 py-3 font-semibold">Plan</th>
<th className="px-4 py-3 font-semibold">Date</th>
<th className="px-4 py-3 font-semibold">Amount</th>
<th className="px-4 py-3 font-semibold">Status</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
{userData.payments.map((p: any) => (
<tr key={p.id}>
<td className="px-4 py-3 font-mono text-xs">{p.id}</td>
<td className="px-4 py-3 font-medium">{p.plan}</td>
<td className="px-4 py-3 text-muted-foreground">{p.date}</td>
<td className="px-4 py-3 font-bold">{p.amount}</td>
<td className="px-4 py-3"><Badge className="bg-green-500/20 text-green-500 border-green-500/30">{p.status}</Badge></td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
</div>
)
}