mancala/apps/frontend/src/components/home/RecentGamesSection.tsx
Halit Aksoy a65662f695 feat(frontend): show ongoing, live, popular and recent games on the home page
- Banner for the user's game in progress with a Continue button
- Live games as cards with the real board, updated over WebSocket; the
  most watched finished games when nothing is live
- The user's last 3 games, from their side of the board, with the result
  as they would say it
- The lobby offers to continue the game in progress when a new one is
  refused
- Spectators register once connected and identified, and again after a
  reconnect, so they are counted
- The backend includes games that ended but are not saved yet in /game/:id
  and the lists
2026-10-16 00:27:06 +03:00

51 lines
2.1 KiB
TypeScript

import * as React from "react";
import { FunctionComponent, useEffect, useState } from "react";
import { FinishedGameSummary } from "@mancala/core";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { Context } from "../../context/context";
import { formatDate, getResultText, getScoreText, getViewerSeat } from "../../util/GameResultText";
import GamePreviewCard from "./GamePreviewCard";
import HomeSection from "./HomeSection";
const GAME_COUNT = 3;
// The user's last finished games, each shown from their side of the board.
const RecentGamesSection: FunctionComponent<{ context: Context, userId: string }> = ({ context, userId }) => {
const { t, i18n } = useTranslation();
const navigate = useNavigate();
const [games, setGames] = useState<FinishedGameSummary[] | undefined>(undefined);
useEffect(() => {
let disposed = false;
context.authService.getAccessToken()
.then((token) => context.gameStore.getMyRecentGames(token, GAME_COUNT))
.then((recent) => !disposed && setGames(recent))
.catch((error) => console.error("(Home) Could not load recent games", error));
return () => { disposed = true; };
}, [userId]);
if (!games) return <></>;
return (
<HomeSection context={context} title={t("MyRecentGames")} emptyText={t("NoGamesYet")}>
{games.map((game) => (
<GamePreviewCard
key={game.id}
context={context}
id={game.id}
player1={game.player1}
player2={game.player2}
board={game.board}
revert={getViewerSeat(game, userId) === "player2"}
lines={[
`${getResultText(game, userId, t)} · ${getScoreText(game, userId)}`,
formatDate(game.endedAt, i18n.language),
]}
onClick={() => navigate(`/game/${game.id}`)} />
))}
</HomeSection>
);
};
export default RecentGamesSection;