-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathgamification-header-card.tsx
More file actions
99 lines (89 loc) · 4.99 KB
/
Copy pathgamification-header-card.tsx
File metadata and controls
99 lines (89 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"use client";
import { useGamificationSummary } from "@/lib/hooks/use-gamification-summary";
import { Progress, ProgressTrack, ProgressIndicator } from "@/components/ui/progress";
import {
IconTrophy,
IconFlame,
IconCoin,
IconStar,
} from "@tabler/icons-react";
import { cn } from "@/lib/utils";
import { Skeleton } from "@/components/ui/skeleton";
import Link from "next/link";
import { useTranslations } from "next-intl";
export function GamificationHeaderCard() {
const { summary, loading } = useGamificationSummary();
const t = useTranslations('components.gamification');
if (loading) {
return (
// #586: same `max-w-full overflow-hidden` as the loaded state below,
// so the skeleton cannot be wider than the thing it stands in for.
<div className="flex items-center gap-4 px-3 py-1.5 bg-muted/50 rounded-xl border border-border max-w-full overflow-hidden">
<Skeleton className="h-6 w-20 rounded-md" />
<Skeleton className="h-6 w-16 rounded-md" />
<Skeleton className="h-6 w-16 rounded-md" />
</div>
);
}
if (!summary) return null;
return (
<div
data-slot="gamification-header-card"
className="flex items-center gap-1 md:gap-2 bg-muted/50 border border-border rounded-xl p-1 md:p-1.5 max-w-full overflow-hidden"
>
{/* Level & XP */}
<div className="flex items-center gap-1.5 md:gap-2 px-2 md:px-2.5 py-1 rounded-lg hover:bg-accent/50 transition-colors shrink-0">
<div className="relative flex items-center justify-center">
<div className="h-6 w-6 md:h-7 md:w-7 rounded-md bg-primary/15 flex items-center justify-center">
<IconStar className="size-3.5 md:size-4 text-primary" />
</div>
<div className="absolute -top-1 -right-1.5 h-3.5 w-3.5 rounded-full bg-foreground text-[8px] font-bold flex items-center justify-center text-background border border-background">
{summary.level}
</div>
</div>
<div className="hidden sm:flex flex-col gap-0.5 w-20 md:w-24">
<div className="flex justify-between items-end">
<span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">{t('level')} {summary.level}</span>
<span className="text-[10px] text-muted-foreground">{summary.xp_progress.percentage}%</span>
</div>
<Progress value={summary.xp_progress.percentage} className="w-full gap-0">
<ProgressTrack className="h-1.5 bg-muted">
<ProgressIndicator className="bg-primary" />
</ProgressTrack>
</Progress>
</div>
<span className="sm:hidden text-[10px] font-bold leading-none">Lvl {summary.level}</span>
</div>
<div className="w-px h-5 bg-border shrink-0" />
{/* Streak */}
<div className="flex items-center gap-1.5 px-2 md:px-2.5 py-1 rounded-lg hover:bg-accent/50 transition-colors">
<div className={cn(
"p-1 rounded-md transition-colors",
summary.streak.current > 0 ? "bg-orange-500/10 text-orange-500" : "bg-muted text-muted-foreground"
)}>
<IconFlame className="size-3.5 md:size-4" />
</div>
<div className="flex flex-col">
<span className="text-xs font-bold leading-none">{summary.streak.current}</span>
<span className="text-[9px] md:text-[10px] text-muted-foreground uppercase tracking-tight hidden sm:block">{t('streak')}</span>
</div>
</div>
<div className="w-px h-5 bg-border shrink-0" />
{/* Coins */}
<div className="flex items-center gap-1.5 px-2 md:px-2.5 py-1 rounded-lg hover:bg-accent/50 transition-colors">
<div className="p-1 rounded-md bg-primary/10 text-primary transition-colors">
<IconCoin className="size-3.5 md:size-4" />
</div>
<div className="flex flex-col">
<span className="text-xs font-bold leading-none">{summary.coins}</span>
<span className="text-[9px] md:text-[10px] text-muted-foreground uppercase tracking-tight hidden sm:block">{t('coins')}</span>
</div>
</div>
{summary.features?.achievements && (
<Link href="/dashboard/student/profile#achievements" className="flex items-center justify-center p-1.5 rounded-lg hover:bg-accent text-muted-foreground hover:text-foreground transition-colors shrink-0" aria-label={t('achievements.title')}>
<IconTrophy className="size-4 md:size-[18px]" />
</Link>
)}
</div>
);
}