From 5af0835a7c53be7a984bbf03059029148acf9c19 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:52:33 +0100 Subject: [PATCH 01/15] feat(achievements): add AchievementBadge --- .../achievements/AchievementBadge.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 frontend/src/components/achievements/AchievementBadge.tsx diff --git a/frontend/src/components/achievements/AchievementBadge.tsx b/frontend/src/components/achievements/AchievementBadge.tsx new file mode 100644 index 0000000..0199565 --- /dev/null +++ b/frontend/src/components/achievements/AchievementBadge.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +interface AchievementBadgeProps { + icon: string; + name: string; + description: string; + isUnlocked: boolean; + progress?: number; + target?: number; +} + +export const AchievementBadge: React.FC = ({ + icon, + name, + description, + isUnlocked, + progress, + target, +}) => { + const progressPercent = progress && target ? (progress / target) * 100 : 0; + + return ( +
+
{isUnlocked ? icon : '🔒'}
+

{name}

+

{description}

+ {!isUnlocked && progress !== undefined && target && ( +
+
+
+
+

{progress}/{target}

+
+ )} +
+ ); +}; From 63419ac7a1f376d2b55a0b4e078712f4ee3f6809 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:52:46 +0100 Subject: [PATCH 02/15] feat(achievements): add exports --- frontend/src/components/achievements/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 frontend/src/components/achievements/index.ts diff --git a/frontend/src/components/achievements/index.ts b/frontend/src/components/achievements/index.ts new file mode 100644 index 0000000..5e546fa --- /dev/null +++ b/frontend/src/components/achievements/index.ts @@ -0,0 +1 @@ +export { AchievementBadge } from './AchievementBadge'; From 4a27c30a73db7e4f79dcc0163e4da5a991506093 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:53:06 +0100 Subject: [PATCH 03/15] feat(achievements): add useAchievements hook --- frontend/src/hooks/useAchievements.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 frontend/src/hooks/useAchievements.ts diff --git a/frontend/src/hooks/useAchievements.ts b/frontend/src/hooks/useAchievements.ts new file mode 100644 index 0000000..603a6ad --- /dev/null +++ b/frontend/src/hooks/useAchievements.ts @@ -0,0 +1,23 @@ +import { useState, useEffect } from 'react'; +import { Achievement, AchievementState } from '@/types/achievement'; + +export const useAchievements = () => { + const [achievements, setAchievements] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const fetchAchievements = async () => { + await new Promise((r) => setTimeout(r, 300)); + setAchievements([ + { id: '1', title: 'First Win', description: 'Win your first game', icon: '🎯', category: 'milestone', unlockedAt: '2025-01-15', progress: 1, target: 1, isUnlocked: true }, + { id: '2', title: 'Streak Master', description: 'Get a 7-day streak', icon: '🔥', category: 'streak', progress: 5, target: 7, isUnlocked: false }, + { id: '3', title: 'Speed Demon', description: 'Answer 50 questions in under 10s', icon: '⚡', category: 'time', progress: 35, target: 50, isUnlocked: false }, + { id: '4', title: 'Trivia Expert', description: 'Answer 500 questions correctly', icon: '🧠', category: 'skill', progress: 420, target: 500, isUnlocked: false }, + ]); + setIsLoading(false); + }; + fetchAchievements(); + }, []); + + return { achievements, isLoading }; +}; From 95f3eef3be32e8d510423eddbb3a2a81c99946be Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:53:51 +0100 Subject: [PATCH 04/15] feat(achievements): add layout --- frontend/src/app/achievements/layout.tsx | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 frontend/src/app/achievements/layout.tsx diff --git a/frontend/src/app/achievements/layout.tsx b/frontend/src/app/achievements/layout.tsx new file mode 100644 index 0000000..3dff01d --- /dev/null +++ b/frontend/src/app/achievements/layout.tsx @@ -0,0 +1,4 @@ +import { ReactNode } from 'react'; +export default function AchievementsLayout({ children }: { children: ReactNode }) { + return <>{children}; +} From e151d7e7865f191566de6b06d27ada33b074c4d4 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:54:09 +0100 Subject: [PATCH 05/15] feat(achievements): add tournament types --- frontend/src/types/tournament.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frontend/src/types/tournament.ts diff --git a/frontend/src/types/tournament.ts b/frontend/src/types/tournament.ts new file mode 100644 index 0000000..a4ad99b --- /dev/null +++ b/frontend/src/types/tournament.ts @@ -0,0 +1,11 @@ +export interface Tournament { + id: string; + name: string; + description: string; + startDate: Date; + endDate: Date; + prizePool: number; + participants: number; + maxParticipants: number; + status: 'upcoming' | 'active' | 'completed'; +} From 9199d091b0aeeef47891ca73ee5d0272b59a4a39 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:54:31 +0100 Subject: [PATCH 06/15] feat(achievements): add tournament constants --- frontend/src/constants/tournament.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 frontend/src/constants/tournament.ts diff --git a/frontend/src/constants/tournament.ts b/frontend/src/constants/tournament.ts new file mode 100644 index 0000000..4e77056 --- /dev/null +++ b/frontend/src/constants/tournament.ts @@ -0,0 +1,16 @@ +import { Tournament } from '@/types/tournament'; + +export const TOURNAMENT_CONFIG = { + MIN_PARTICIPANTS: 10, + MAX_PARTICIPANTS: 1000, + DURATION_DAYS: 7, +}; + +export const formatTournamentStatus = (status: string) => { + const colors = { + upcoming: 'bg-blue-100 text-blue-700', + active: 'bg-green-100 text-green-700', + completed: 'bg-gray-100 text-gray-700', + }; + return colors[status as keyof typeof colors] || ''; +}; From 1829016a3b882b0df3d5c880725039f95288ddae Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:54:51 +0100 Subject: [PATCH 07/15] feat(achievements): add useTournaments hook --- frontend/src/hooks/useTournaments.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 frontend/src/hooks/useTournaments.ts diff --git a/frontend/src/hooks/useTournaments.ts b/frontend/src/hooks/useTournaments.ts new file mode 100644 index 0000000..109a05d --- /dev/null +++ b/frontend/src/hooks/useTournaments.ts @@ -0,0 +1,21 @@ +import { useState, useEffect } from 'react'; +import { Tournament } from '@/types/tournament'; + +export const useTournaments = () => { + const [tournaments, setTournaments] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const fetchTournaments = async () => { + await new Promise((r) => setTimeout(r, 300)); + setTournaments([ + { id: '1', name: 'Weekly Championship', description: 'Compete for the top spot', startDate: new Date(), endDate: new Date(Date.now() + 7 * 86400000), prizePool: 10000, participants: 150, maxParticipants: 500, status: 'active' }, + { id: '2', name: 'Weekend Warrior', description: 'Special weekend tournament', startDate: new Date(Date.now() + 3 * 86400000), endDate: new Date(Date.now() + 5 * 86400000), prizePool: 5000, participants: 0, maxParticipants: 200, status: 'upcoming' }, + ]); + setIsLoading(false); + }; + fetchTournaments(); + }, []); + + return { tournaments, isLoading }; +}; From 1bf7983fcb572f0f722f21cb8ed91fbdaa77ca40 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:55:11 +0100 Subject: [PATCH 08/15] feat(achievements): add TournamentCard --- .../components/tournaments/TournamentCard.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 frontend/src/components/tournaments/TournamentCard.tsx diff --git a/frontend/src/components/tournaments/TournamentCard.tsx b/frontend/src/components/tournaments/TournamentCard.tsx new file mode 100644 index 0000000..1ae35ef --- /dev/null +++ b/frontend/src/components/tournaments/TournamentCard.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { Tournament } from '@/types/tournament'; +import { formatTournamentStatus } from '@/constants/tournament'; + +interface TournamentCardProps { + tournament: Tournament; + onJoin?: (id: string) => void; +} + +export const TournamentCard: React.FC = ({ tournament, onJoin }) => { + return ( +
+
+

{tournament.name}

+ + {tournament.status} + +
+

{tournament.description}

+
+
+

Prize Pool

+

{tournament.prizePool}

+
+
+

Participants

+

{tournament.participants}/{tournament.maxParticipants}

+
+
+ {tournament.status === 'upcoming' && onJoin && ( + + )} +
+ ); +}; From 2b0dd0d8e92e25500c8cd8f6ce03d10fb8fa4e76 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:55:27 +0100 Subject: [PATCH 09/15] feat(achievements): add tournaments exports --- frontend/src/components/tournaments/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 frontend/src/components/tournaments/index.ts diff --git a/frontend/src/components/tournaments/index.ts b/frontend/src/components/tournaments/index.ts new file mode 100644 index 0000000..9baff9e --- /dev/null +++ b/frontend/src/components/tournaments/index.ts @@ -0,0 +1 @@ +export { TournamentCard } from './TournamentCard'; From 464f483dcff85610a24fc7c02d24ab3668796a1b Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:55:48 +0100 Subject: [PATCH 10/15] feat(achievements): add tournaments page --- frontend/src/app/tournaments/page.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 frontend/src/app/tournaments/page.tsx diff --git a/frontend/src/app/tournaments/page.tsx b/frontend/src/app/tournaments/page.tsx new file mode 100644 index 0000000..6f9fc0e --- /dev/null +++ b/frontend/src/app/tournaments/page.tsx @@ -0,0 +1,26 @@ +'use client'; + +import React from 'react'; +import { TournamentCard } from '@/components/tournaments'; +import { useTournaments } from '@/hooks/useTournaments'; + +export default function TournamentsPage() { + const { tournaments, isLoading } = useTournaments(); + + if (isLoading) { + return
Loading...
; + } + + return ( +
+
+

Tournaments

+
+ {tournaments.map((t) => ( + + ))} +
+
+
+ ); +} From 4bc9e8b8b7d4219df415e20a69c6c6ef9a93317c Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:56:03 +0100 Subject: [PATCH 11/15] feat(achievements): add tournaments layout --- frontend/src/app/tournaments/layout.tsx | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 frontend/src/app/tournaments/layout.tsx diff --git a/frontend/src/app/tournaments/layout.tsx b/frontend/src/app/tournaments/layout.tsx new file mode 100644 index 0000000..9bc095b --- /dev/null +++ b/frontend/src/app/tournaments/layout.tsx @@ -0,0 +1,4 @@ +import { ReactNode } from 'react'; +export default function TournamentsLayout({ children }: { children: ReactNode }) { + return <>{children}; +} From 05057903cd5e78918fc95044a1f207719bcede0b Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:56:22 +0100 Subject: [PATCH 12/15] feat(achievements): add reward tiers --- frontend/src/constants/rewards.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 frontend/src/constants/rewards.ts diff --git a/frontend/src/constants/rewards.ts b/frontend/src/constants/rewards.ts new file mode 100644 index 0000000..f57c94a --- /dev/null +++ b/frontend/src/constants/rewards.ts @@ -0,0 +1,13 @@ +export interface RewardTier { + tier: number; + name: string; + minPoints: number; + rewards: string[]; +} + +export const REWARD_TIERS: RewardTier[] = [ + { tier: 1, name: 'Bronze', minPoints: 0, rewards: ['Bronze Badge', '5% bonus'] }, + { tier: 2, name: 'Silver', minPoints: 5000, rewards: ['Silver Badge', '10% bonus', 'Early access'] }, + { tier: 3, name: 'Gold', minPoints: 15000, rewards: ['Gold Badge', '15% bonus', 'Exclusive events'] }, + { tier: 4, name: 'Platinum', minPoints: 50000, rewards: ['Platinum Badge', '20% bonus', 'VIP support'] }, +]; From 11fe8a6b4bfda64cfcb4cfd66b152f28b5403009 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:56:49 +0100 Subject: [PATCH 13/15] feat(achievements): add RewardProgress --- .../src/components/rewards/RewardProgress.tsx | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 frontend/src/components/rewards/RewardProgress.tsx diff --git a/frontend/src/components/rewards/RewardProgress.tsx b/frontend/src/components/rewards/RewardProgress.tsx new file mode 100644 index 0000000..72073db --- /dev/null +++ b/frontend/src/components/rewards/RewardProgress.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { REWARD_TIERS } from '@/constants/rewards'; + +interface RewardProgressProps { + currentPoints: number; +} + +export const RewardProgress: React.FC = ({ currentPoints }) => { + const currentTier = REWARD_TIERS.slice().reverse().find(t => currentPoints >= t.minPoints) || REWARD_TIERS[0]; + const nextTier = REWARD_TIERS.find(t => t.minPoints > currentPoints); + const progress = nextTier + ? ((currentPoints - currentTier.minPoints) / (nextTier.minPoints - currentTier.minPoints)) * 100 + : 100; + + return ( +
+

Your Rewards

+
+

{currentPoints} pts

+

{currentTier.name} Tier

+
+ {nextTier && ( +
+
+
+
+

{nextTier.minPoints - currentPoints} points to {nextTier.name}

+
+ )} +
+ ); +}; From 61e63c8c59f93b0b6617485b1c50777bea81ec85 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:57:03 +0100 Subject: [PATCH 14/15] feat(achievements): add rewards exports --- frontend/src/components/rewards/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 frontend/src/components/rewards/index.ts diff --git a/frontend/src/components/rewards/index.ts b/frontend/src/components/rewards/index.ts new file mode 100644 index 0000000..67fed1d --- /dev/null +++ b/frontend/src/components/rewards/index.ts @@ -0,0 +1 @@ +export { RewardProgress } from './RewardProgress'; From 561b664d7473234a58bec47f171b61c8371acf8e Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 02:57:21 +0100 Subject: [PATCH 15/15] docs(achievements): add documentation --- README_ACHIEVEMENTS.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 README_ACHIEVEMENTS.md diff --git a/README_ACHIEVEMENTS.md b/README_ACHIEVEMENTS.md new file mode 100644 index 0000000..91ef1e5 --- /dev/null +++ b/README_ACHIEVEMENTS.md @@ -0,0 +1,25 @@ +# Achievements & Tournaments + +## Achievements + +Unlock achievements by completing challenges and milestones. + +### Categories +- **Milestone**: Major accomplishments +- **Streak**: Consecutive day bonuses +- **Time**: Speed-based achievements +- **Skill**: Accuracy and knowledge + +## Tournaments + +Compete in weekly and special tournaments for bigger prizes. + +### Status Types +- **Upcoming**: Registration open +- **Active**: Tournament in progress +- **Completed**: Results finalized + +### Features +- Prize pools +- Participant tracking +- Multiple tournament types