Skip to content

Commit 601e032

Browse files
authored
feat(leaderboard): finalize components and fix lint errors (#259)
1 parent 7b8f89a commit 601e032

4 files changed

Lines changed: 25 additions & 32 deletions

File tree

frontend/components/dashboard/QuizSavedBanner.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,18 @@ export function QuizSavedBanner() {
1919

2020
useEffect(() => {
2121
const saved = sessionStorage.getItem('quiz_just_saved');
22-
if (saved) {
23-
try {
24-
setInfo(JSON.parse(saved));
25-
sessionStorage.removeItem('quiz_just_saved');
26-
} catch (error) {
27-
console.error(
28-
'Failed to parse quiz_just_saved from sessionStorage:',
29-
error
30-
);
22+
if (!saved) return;
23+
24+
try {
25+
const parsed = JSON.parse(saved) as SavedQuizInfo;
26+
const timer = setTimeout(() => {
27+
setInfo(parsed);
3128
sessionStorage.removeItem('quiz_just_saved');
32-
}
29+
}, 0);
30+
return () => clearTimeout(timer);
31+
} catch (error) {
32+
console.error('Failed to parse quiz info:', error);
33+
sessionStorage.removeItem('quiz_just_saved');
3334
}
3435
}, []);
3536

frontend/components/leaderboard/LeaderboardClient.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { DynamicGridBackground } from '@/components/shared/DynamicGridBackground
77

88
import { LeaderboardPodium } from './LeaderboardPodium';
99
import { LeaderboardTable } from './LeaderboardTable';
10-
import { CurrentUser,User } from './types';
10+
import { CurrentUser, User } from './types';
1111

1212
interface LeaderboardClientProps {
1313
initialUsers: User[];

frontend/components/leaderboard/LeaderboardTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use client';
22

33
import { motion } from 'framer-motion';
4-
import { Medal,TrendingUp, Trophy } from 'lucide-react';
4+
import { Medal, TrendingUp, Trophy } from 'lucide-react';
55
import { useTranslations } from 'next-intl';
66

77
import { cn } from '@/lib/utils';
88

9-
import { CurrentUser,User } from './types';
9+
import { CurrentUser, User } from './types';
1010

1111
interface LeaderboardTableProps {
1212
users: User[];

frontend/components/shared/CookieBanner.tsx

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,37 @@
22

33
import { X } from 'lucide-react';
44
import { useTranslations } from 'next-intl';
5-
import { useEffect,useState } from 'react';
5+
import { useEffect, useState } from 'react';
66

77
import { Button } from '@/components/ui/button';
88
import { Link } from '@/i18n/routing';
99

1010
export function CookieBanner() {
1111
const t = useTranslations('CookieBanner');
12-
const [isVisible, setIsVisible] = useState(false);
13-
const [isMounted, setIsMounted] = useState(false);
12+
const [isVisible, setIsVisible] = useState<boolean | null>(null);
1413

1514
useEffect(() => {
16-
setIsMounted(true);
1715
const consent = localStorage.getItem('cookie-consent');
1816
if (!consent) {
1917
const timer = setTimeout(() => setIsVisible(true), 500);
2018
return () => clearTimeout(timer);
19+
} else {
20+
const timer = setTimeout(() => setIsVisible(false), 0);
21+
return () => clearTimeout(timer);
2122
}
2223
}, []);
2324

24-
const handleAccept = () => {
25-
try {
26-
localStorage.setItem('cookie-consent', 'accepted');
27-
} catch (error) {
28-
console.error('Failed to save cookie consent:', error);
29-
}
30-
setIsVisible(false);
31-
};
25+
if (isVisible === null || !isVisible) return null;
3226

33-
const handleDecline = () => {
27+
const handleAction = (type: 'accepted' | 'declined') => {
3428
try {
35-
localStorage.setItem('cookie-consent', 'declined');
29+
localStorage.setItem('cookie-consent', type);
3630
} catch (error) {
3731
console.error('Failed to save cookie consent:', error);
3832
}
3933
setIsVisible(false);
4034
};
4135

42-
if (!isMounted || !isVisible) return null;
43-
4436
return (
4537
<div className="animate-in slide-in-from-bottom-full fade-in fixed right-0 bottom-0 left-0 z-[100] p-4 duration-700 md:p-6">
4638
<div className="mx-auto max-w-4xl rounded-2xl border border-gray-200 bg-white/90 p-5 shadow-2xl backdrop-blur-md md:flex md:items-center md:justify-between md:gap-6 dark:border-gray-800 dark:bg-gray-900/90">
@@ -64,23 +56,23 @@ export function CookieBanner() {
6456
<Button
6557
variant="outline"
6658
size="sm"
67-
onClick={handleDecline}
59+
onClick={() => handleAction('declined')}
6860
className="w-full sm:w-auto"
6961
>
7062
{t('decline')}
7163
</Button>
7264
<Button
7365
variant="primary"
7466
size="sm"
75-
onClick={handleAccept}
67+
onClick={() => handleAction('accepted')}
7668
className="w-full shadow-lg shadow-blue-500/20 sm:w-auto"
7769
>
7870
{t('accept')}
7971
</Button>
8072
</div>
8173

8274
<button
83-
onClick={handleDecline}
75+
onClick={() => handleAction('declined')}
8476
className="absolute top-2 right-2 rounded-full p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 md:hidden dark:hover:bg-gray-800 dark:hover:text-gray-300"
8577
aria-label={t('decline')}
8678
>

0 commit comments

Comments
 (0)