mirror of
https://github.com/nihonbuzz/nihonbuzz-academy.git
synced 2026-01-26 05:25:37 +07:00
171 lines
11 KiB
TypeScript
171 lines
11 KiB
TypeScript
import DashboardLayout from '@/Layouts/DashboardLayout';
|
|
import { Head, Link } from '@inertiajs/react';
|
|
import { Card } from "@/Components/ui/card";
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/Components/ui/avatar";
|
|
import { Button } from "@/Components/ui/button";
|
|
import { BookOpen, Flame, Trophy, Play, Plus, Brain } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface DashboardProps {
|
|
stats: {
|
|
xp_points: number;
|
|
current_streak: number;
|
|
active_courses: number;
|
|
certificates: number;
|
|
srs_due: number;
|
|
srs_new: number;
|
|
};
|
|
activeCourses: Array<any>;
|
|
user: any;
|
|
}
|
|
|
|
export default function Dashboard({
|
|
stats = { xp_points: 0, current_streak: 0, active_courses: 0, certificates: 0, srs_due: 0, srs_new: 0 },
|
|
activeCourses = [],
|
|
user
|
|
}: Partial<DashboardProps>) {
|
|
|
|
// Stitch Heatmap Simulation
|
|
const heatmapIntensity = ['bg-gray-200 dark:bg-white/5', 'bg-[#FF4500]/20', 'bg-[#FF4500]/40', 'bg-[#FF4500]/60', 'bg-[#FF4500]'];
|
|
const heatmapCells = Array.from({ length: 84 }, () => Math.floor(Math.random() * 5));
|
|
|
|
return (
|
|
<DashboardLayout>
|
|
<Head title="Dashboard" />
|
|
|
|
<div className="grid grid-cols-12 gap-6 animate-in fade-in duration-500">
|
|
|
|
{/* SRS Review Card (Large) */}
|
|
<div className="col-span-12 lg:col-span-8 bg-white/60 dark:bg-[#161618]/60 backdrop-blur-md border border-gray-200 dark:border-white/5 rounded-xl p-8 relative overflow-hidden group shadow-sm transition-colors duration-300">
|
|
<div className="absolute top-0 right-0 p-8 opacity-10 group-hover:opacity-20 transition-opacity">
|
|
<Brain size={120} className="text-[#FF4500]" />
|
|
</div>
|
|
<div className="relative z-10 flex flex-col h-full justify-between gap-8">
|
|
<div>
|
|
<h2 className="text-[#FF4500] font-bold uppercase tracking-widest text-xs mb-2">SRS Status</h2>
|
|
<p className="text-5xl font-bold text-gray-900 dark:text-white tracking-tight">{stats.srs_due} Reviews Due</p>
|
|
<p className="text-gray-500 dark:text-white/60 mt-2 max-w-md">
|
|
{stats.srs_due > 0
|
|
? "You have Kanji and Vocabulary items waiting. Keep your streak alive!"
|
|
: "All caught up! Why not learn some new words?"}
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<Link href={route('srs.index')}>
|
|
<Button className="bg-[#FF4500] hover:bg-[#FF4500]/90 text-white px-8 py-6 rounded-lg font-bold text-base shadow-[0_0_15px_rgba(255,68,0,0.3)] hover:scale-[1.02] active:scale-[0.98] transition-all flex items-center gap-2">
|
|
Start Session
|
|
<Play size={20} className="fill-current" />
|
|
</Button>
|
|
</Link>
|
|
<div className="text-xs font-medium text-gray-500 dark:text-white/40 flex flex-col">
|
|
<span>Estimated time</span>
|
|
<span className="text-gray-900 dark:text-white">~{Math.ceil(stats.srs_due * 0.5)} minutes</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Streak Widget */}
|
|
<div className="col-span-12 md:col-span-6 lg:col-span-4 bg-[#FF4500]/5 dark:bg-[#FF4500]/[0.03] border border-[#FF4500]/20 backdrop-blur-md rounded-xl p-6 flex flex-col justify-between shadow-sm transition-colors duration-300">
|
|
<div className="flex justify-between items-start">
|
|
<div className="size-12 rounded bg-[#FF4500]/20 flex items-center justify-center">
|
|
<Flame size={24} className="text-[#FF4500] fill-current" />
|
|
</div>
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-[#FF4500] bg-[#FF4500]/10 px-2 py-1 rounded">Daily Goal Met</span>
|
|
</div>
|
|
<div className="mt-4">
|
|
<p className="text-4xl font-bold text-gray-900 dark:text-white tracking-tighter">{stats.current_streak} Day Streak</p>
|
|
<p className="text-gray-500 dark:text-white/40 text-sm mt-1">Don't break the chain. Keep going!</p>
|
|
</div>
|
|
<div className="mt-6 flex gap-1">
|
|
{[1, 1, 1, 1, 0, 0, 0].map((active, i) => (
|
|
<div
|
|
key={i}
|
|
className={cn(
|
|
"h-1.5 flex-1 rounded-full",
|
|
active ? "bg-[#FF4500] shadow-[0_0_8px_rgba(255,68,0,0.4)]" : "bg-gray-200 dark:bg-white/10"
|
|
)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Study Heatmap */}
|
|
<div className="col-span-12 lg:col-span-8 bg-white/60 dark:bg-[#161618]/60 backdrop-blur-md border border-gray-200 dark:border-white/5 rounded-xl p-6 shadow-sm transition-colors duration-300">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h3 className="text-gray-900 dark:text-white font-bold">Study Activity</h3>
|
|
<p className="text-gray-500 dark:text-white/40 text-xs">Consistent effort yields results</p>
|
|
</div>
|
|
<div className="flex gap-2 items-center text-[10px] text-gray-400 dark:text-white/40">
|
|
<span>Less</span>
|
|
{heatmapIntensity.map((bg, i) => (
|
|
<div key={i} className={cn("size-3 rounded-sm", bg)} />
|
|
))}
|
|
<span>More</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-12 gap-2">
|
|
<div className="col-span-12 flex gap-1.5 flex-wrap">
|
|
{heatmapCells.map((level, i) => (
|
|
<div key={i} className={cn("w-[11px] h-[11px] rounded-sm", heatmapIntensity[level])} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 flex justify-between text-[11px] font-medium text-gray-400 dark:text-white/40 uppercase tracking-widest">
|
|
<span>October</span>
|
|
<span>November</span>
|
|
<span>December</span>
|
|
<span>January</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Level Progress (Circular) */}
|
|
<div className="col-span-12 md:col-span-6 lg:col-span-4 bg-white/60 dark:bg-[#161618]/60 backdrop-blur-md border border-gray-200 dark:border-white/5 rounded-xl p-6 flex flex-col items-center justify-center text-center shadow-sm transition-colors duration-300">
|
|
<div className="relative size-32 flex items-center justify-center">
|
|
<svg className="absolute inset-0 size-full -rotate-90">
|
|
<circle className="text-gray-200 dark:text-white/5" cx="64" cy="64" fill="transparent" r="58" stroke="currentColor" strokeWidth="8"></circle>
|
|
<circle className="text-[#FF4500]" cx="64" cy="64" fill="transparent" r="58" stroke="currentColor" strokeDasharray="364.4" strokeDashoffset="127.5" strokeLinecap="round" strokeWidth="8"></circle>
|
|
</svg>
|
|
<div className="flex flex-col items-center">
|
|
<span className="text-3xl font-bold text-gray-900 dark:text-white">65%</span>
|
|
<span className="text-[10px] font-bold text-gray-500 dark:text-white/40 uppercase">N5 Progress</span>
|
|
</div>
|
|
</div>
|
|
<div className="mt-6">
|
|
<h4 className="text-gray-900 dark:text-white font-bold text-lg">JLPT N5 Path</h4>
|
|
<p className="text-gray-500 dark:text-white/40 text-sm mt-1">242 / 800 Kanji mastered</p>
|
|
</div>
|
|
<Link href={route('courses.index')} className="w-full mt-4">
|
|
<Button variant="outline" className="w-full border-gray-200 dark:border-white/10 hover:bg-gray-100 dark:hover:bg-white/5 text-xs font-bold text-gray-700 dark:text-white/80">
|
|
VIEW CURRICULUM
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Quick Stats Footer */}
|
|
<div className="col-span-12 grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div className="bg-white/60 dark:bg-[#161618]/60 border border-gray-200 dark:border-white/5 p-4 rounded-lg shadow-sm">
|
|
<p className="text-[10px] font-bold text-gray-500 dark:text-white/40 uppercase tracking-widest">Items Learned</p>
|
|
<p className="text-xl font-bold text-gray-900 dark:text-white">1,402</p>
|
|
</div>
|
|
<div className="bg-white/60 dark:bg-[#161618]/60 border border-gray-200 dark:border-white/5 p-4 rounded-lg shadow-sm">
|
|
<p className="text-[10px] font-bold text-gray-500 dark:text-white/40 uppercase tracking-widest">Retention Rate</p>
|
|
<p className="text-xl font-bold text-gray-900 dark:text-white">88.4%</p>
|
|
</div>
|
|
<div className="bg-white/60 dark:bg-[#161618]/60 border border-gray-200 dark:border-white/5 p-4 rounded-lg shadow-sm">
|
|
<p className="text-[10px] font-bold text-gray-500 dark:text-white/40 uppercase tracking-widest">Global Rank</p>
|
|
<p className="text-xl font-bold text-gray-900 dark:text-white">#412</p>
|
|
</div>
|
|
<div className="bg-white/60 dark:bg-[#161618]/60 border border-gray-200 dark:border-white/5 p-4 rounded-lg shadow-sm">
|
|
<p className="text-[10px] font-bold text-gray-500 dark:text-white/40 uppercase tracking-widest">Total XP</p>
|
|
<p className="text-xl font-bold text-gray-900 dark:text-white">{stats.xp_points.toLocaleString()}</p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</DashboardLayout>
|
|
);
|
|
}
|