mirror of
https://github.com/nihonbuzz/nihonbuzz-academy.git
synced 2026-01-26 13:32:07 +07:00
first commit
This commit is contained in:
186
resources/js/Pages/Dashboard.tsx
Normal file
186
resources/js/Pages/Dashboard.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
||||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/Components/ui/card";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/Components/ui/avatar";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { BookOpen, Flame, GraduationCap, Trophy, Play } from "lucide-react";
|
||||
import CourseCard from '@/Components/CourseCard';
|
||||
|
||||
interface DashboardProps {
|
||||
stats: {
|
||||
xp_points: number;
|
||||
current_streak: number;
|
||||
active_courses: number;
|
||||
certificates: number;
|
||||
srs_due: number;
|
||||
srs_new: number;
|
||||
};
|
||||
activeCourses: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
thumbnail: string;
|
||||
level: string;
|
||||
progress: number;
|
||||
lessonsCount: number;
|
||||
completedLessons: number;
|
||||
slug: string;
|
||||
}>;
|
||||
user: {
|
||||
name: string;
|
||||
avatar: string;
|
||||
rank: string;
|
||||
xp_points?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export default function Dashboard({
|
||||
stats: propStats = { xp_points: 0, current_streak: 0, active_courses: 0, certificates: 0, srs_due: 0, srs_new: 0 },
|
||||
activeCourses: propCourses = [],
|
||||
user: propUser = { name: 'Student', avatar: '', rank: 'Genin' }
|
||||
}: Partial<DashboardProps>) {
|
||||
|
||||
const activeCourses = propCourses ?? [];
|
||||
const userData = propUser ?? { name: 'Student', avatar: '', rank: 'Genin' };
|
||||
const stats = propStats ?? { xp_points: 0, current_streak: 0, active_courses: 0, certificates: 0, srs_due: 0, srs_new: 0 };
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
header={
|
||||
<div className="flex flex-col gap-1">
|
||||
<h2 className="text-2xl font-bold tracking-tight">Dashboard Siswa</h2>
|
||||
<p className="text-muted-foreground text-sm">Selamat datang kembali! Yuk, lanjutkan progres belajarmu hari ini.</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Head title="Dashboard" />
|
||||
|
||||
<div className="space-y-8 animate-in fade-in duration-700">
|
||||
{/* Stats Grid */}
|
||||
<div className="grid gap-4 grid-cols-2 lg:grid-cols-4">
|
||||
<Card className="border-border/50 bg-card/50 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Total XP</CardTitle>
|
||||
<Trophy className="h-4 w-4 text-yellow-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-black">{stats.xp_points.toLocaleString()}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border/50 bg-card/50 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Streak</CardTitle>
|
||||
<Flame className="h-4 w-4 text-orange-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-black">{stats.current_streak} Hari</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border/50 bg-card/50 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Kursus</CardTitle>
|
||||
<BookOpen className="h-4 w-4 text-blue-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-black">{stats.active_courses} Aktif</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border/50 bg-card/50 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">Sertifikat</CardTitle>
|
||||
<GraduationCap className="h-4 w-4 text-green-500" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-black">{stats.certificates} Diraih</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-8 lg:grid-cols-12">
|
||||
{/* Main Content: Course List */}
|
||||
<div className="lg:col-span-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-bold tracking-tight">Lanjutkan Belajar</h3>
|
||||
<Link href="#" className="text-xs font-semibold text-primary hover:underline">Lihat Semua</Link>
|
||||
</div>
|
||||
|
||||
<div className="grid sm:grid-cols-2 gap-6">
|
||||
{activeCourses.length > 0 ? activeCourses.map((course, i) => (
|
||||
<CourseCard key={i} {...course} />
|
||||
)) : (
|
||||
<div className="col-span-full border-2 border-dashed border-border/50 rounded-3xl py-12 flex flex-col items-center justify-center text-center px-6">
|
||||
<div className="w-16 h-16 bg-muted rounded-full flex items-center justify-center mb-4">
|
||||
<BookOpen className="text-muted-foreground" size={32} />
|
||||
</div>
|
||||
<h4 className="font-bold text-foreground">Belum ada kursus aktif</h4>
|
||||
<p className="text-sm text-muted-foreground max-w-xs mt-1 mb-6">Mulai perjalanan belajarmu sekarang dengan memilih paket kursus yang tersedia.</p>
|
||||
<Button className="rounded-full px-8">Explorasi Kursus</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sidebar: Profile & SRS */}
|
||||
<div className="lg:col-span-4 space-y-6">
|
||||
<Card className="overflow-hidden border-border/50 bg-card/50 backdrop-blur-xl">
|
||||
<div className="h-24 bg-gradient-to-br from-primary/20 via-primary/10 to-transparent dark:from-primary/30 dark:via-primary/5" />
|
||||
<CardContent className="relative pt-0 px-6 pb-6">
|
||||
<Avatar className="h-20 w-20 absolute -top-10 border-4 border-background ring-1 ring-border/20">
|
||||
<AvatarImage src={userData.avatar} />
|
||||
<AvatarFallback className="bg-primary text-primary-foreground font-bold">{userData.name.charAt(0)}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="mt-12">
|
||||
<h3 className="font-bold text-xl">{userData.name}</h3>
|
||||
<p className="text-sm text-muted-foreground font-medium">Rank: <span className="text-primary italic font-bold">{userData.rank}</span></p>
|
||||
</div>
|
||||
<div className="mt-6 pt-6 border-t border-border/50 grid grid-cols-2 gap-4 text-center">
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-xl font-black">{stats.xp_points.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-muted-foreground uppercase font-bold tracking-wider">Total XP</p>
|
||||
</div>
|
||||
<div className="space-y-0.5">
|
||||
<p className="text-xl font-black">{stats.current_streak}</p>
|
||||
<p className="text-[10px] text-muted-foreground uppercase font-bold tracking-wider">Streak</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button variant="outline" className="w-full mt-6 rounded-xl text-xs font-bold border-border/50">Edit Profil</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* SRS Reminder */}
|
||||
<Card className="bg-primary text-primary-foreground border-none shadow-xl shadow-primary/20 relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 p-8 opacity-10 transform translate-x-4 -translate-y-4 group-hover:scale-110 transition-transform duration-700">
|
||||
<Flame size={120} />
|
||||
</div>
|
||||
<CardHeader className="relative z-10">
|
||||
<CardTitle className="flex items-center gap-2 text-lg">
|
||||
Hafalan (SRS)
|
||||
</CardTitle>
|
||||
<CardDescription className="text-primary-foreground/80 font-medium">
|
||||
{stats.srs_due > 0 ? (
|
||||
<>Ada <span className="font-black text-white">{stats.srs_due} kata</span> yang perlu diulas hari ini.</>
|
||||
) : stats.srs_new > 0 ? (
|
||||
<>Tidak ada ulasan, tapi ada <span className="font-black text-white">{stats.srs_new} kata baru</span> siap dipelajari!</>
|
||||
) : (
|
||||
<>Luar biasa! Semua hafalanmu sudah selesai untuk hari ini.</>
|
||||
)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="relative z-10">
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full font-black text-primary rounded-xl h-11"
|
||||
size="lg"
|
||||
onClick={() => window.location.href = route('srs.index')}
|
||||
>
|
||||
{stats.srs_due > 0 ? 'Mulai Sesi Review' : 'Buka Koleksi Kata'}
|
||||
<Play className="ml-2 w-4 h-4 fill-current" />
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AuthenticatedLayout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user