Skip to content

Leader Soccer Board #36

Description

@Nathanofzion

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

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions