Leaderboard Modal that you can use for both games. This example assumes you have an API or Supabase table that returns leaderboard data in the following format (example may or may not be usable):
type LeaderboardEntry = {
address: string; // Passkey ID address
score: number; // Zin earned
};
1. Leaderboard Modal Component
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
Button,
useDisclosure,
Spinner,
Box,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
type LeaderboardEntry = {
address: string;
score: number;
};
interface LeaderboardModalProps {
isOpen: boolean;
onClose: () => void;
game: "space-invaders" | "blockchain-tetris";
}
const LeaderboardModal = ({ isOpen, onClose, game }: LeaderboardModalProps) => {
const [data, setData] = useState<LeaderboardEntry[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!isOpen) return;
setLoading(true);
// Replace with your API or Supabase call
fetch(`/api/leaderboard?game=${game}`)
.then((res) => res.json())
.then((entries) => {
// Sort by score descending
setData(entries.sort((a: LeaderboardEntry, b: LeaderboardEntry) => b.score - a.score));
setLoading(false);
});
}, [isOpen, game]);
return (
<Modal isOpen={isOpen} onClose={onClose} size="lg" isCentered>
<ModalOverlay />
<ModalContent>
<ModalHeader>Leader Board</ModalHeader>
<ModalCloseButton />
<ModalBody>
{loading ? (
<Box textAlign="center" py={10}><Spinner /></Box>
) : (
<Table variant="simple">
<Thead>
<Tr>
<Th>Position</Th>
<Th>Passkey ID</Th>
<Th>Zin Earned</Th>
</Tr>
</Thead>
<Tbody>
{data.map((entry, idx) => (
<Tr key={entry.address}>
<Td>{idx + 1}</Td>
<Td>
{entry.address.slice(0, 6)}...{entry.address.slice(-4)}
</Td>
<Td>{entry.score}</Td>
</Tr>
))}
</Tbody>
</Table>
)}
</ModalBody>
</ModalContent>
</Modal>
);
};
export default LeaderboardModal;
2. Add "Score Board" Button and Modal to Each Game
Example for Space Invaders (repeat for Blockchain Tetris):
// In your Space Invaders game component
import { Button, useDisclosure } from "@chakra-ui/react";
import LeaderboardModal from "@/components/LeaderboardModal";
export default function SpaceInvadersGame() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
{/* ...your game UI... */}
<Button onClick={onOpen} colorScheme="teal" mt={4}>
Score Board
</Button>
<LeaderboardModal isOpen={isOpen} onClose={onClose} game="space-invaders" />
</>
);
}
Repeat for Blockchain Tetris, changing game="blockchain-tetris".
3. Example API Route (Optional)
If you use Next.js API routes or Supabase, here’s a simple mock:
import type { NextApiRequest, NextApiResponse } from "next";
const mockData = {
"space-invaders": [
{ address: "GABC1234XYZ1", score: 120 },
{ address: "GDEF5678XYZ2", score: 90 },
// ...
],
"blockchain-tetris": [
{ address: "GHIJ9012XYZ3", score: 200 },
{ address: "GKLM3456XYZ4", score: 150 },
// ...
],
};
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { game } = req.query;
res.status(200).json(mockData[game as string] || []);
}
How it works
- Each game has a Score Board button.
- Clicking it opens a modal titled Leader Board.
- The modal fetches and displays live leaderboard data: position, Passkey ID (shortened), Zin earned.
- Works for both games by passing the
game prop.
Here’s a realistic estimate for implementing live leaderboards for both games as described:
| Task |
Estimated Hours |
| Supabase table setup & API integration |
2 |
| LeaderboardModal component (UI & logic) |
2 |
| Game UI integration (button, modal wiring) |
1 |
| Testing (live updates, edge cases, mobile) |
1 |
| Total |
6–7 hours |
Leaderboard Modal that you can use for both games. This example assumes you have an API or Supabase table that returns leaderboard data in the following format (example may or may not be usable):
1. Leaderboard Modal Component
2. Add "Score Board" Button and Modal to Each Game
Example for Space Invaders (repeat for Blockchain Tetris):
Repeat for Blockchain Tetris, changing
game="blockchain-tetris".3. Example API Route (Optional)
If you use Next.js API routes or Supabase, here’s a simple mock:
How it works
gameprop.Here’s a realistic estimate for implementing live leaderboards for both games as described: