mancala/apps/frontend/src/components/home/LiveGamesSection.tsx

90 lines
3.8 KiB
TypeScript
Raw Normal View History

import * as React from "react";
import { FunctionComponent, useEffect, useState } from "react";
import {
channel_on_live_games,
channel_subscribe_live_games,
channel_unsubscribe_live_games,
LiveGameSummary,
} from "@mancala/core";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { Context } from "../../context/context";
import { PopularGames } from "../../store/GameStore";
import { formatDate, getResultText, getScoreText } from "../../util/GameResultText";
import GamePreviewCard from "./GamePreviewCard";
import HomeSection from "./HomeSection";
const GAME_COUNT = 5;
// Live games, updated as they are played; when nothing is live, the most watched finished games.
const LiveGamesSection: FunctionComponent<{ context: Context }> = ({ context }) => {
const { t, i18n } = useTranslation();
const navigate = useNavigate();
const [popular, setPopular] = useState<PopularGames | undefined>(undefined);
useEffect(() => {
let disposed = false;
const loadPopular = () => context.gameStore.getPopularGames(GAME_COUNT)
.then((games) => !disposed && setPopular(games))
.catch((error) => console.error("(Home) Could not load popular games", error));
const onLiveGames = (message: { games: LiveGameSummary[] }) => {
if (message.games.length > 0) setPopular({ kind: "live", games: message.games });
else loadPopular();
};
// Subscribe whenever the connection is (re)established; the server forgets subscriptions of offline users.
const subscribe = () => context.rtmt.sendMessage(channel_subscribe_live_games, {});
context.rtmt.addMessageListener(channel_on_live_games, onLiveGames);
context.rtmt.on("open", subscribe);
if (context.rtmt.connectionState === "connected") subscribe();
loadPopular();
return () => {
disposed = true;
context.rtmt.off("open", subscribe);
context.rtmt.removeMessageListener(channel_on_live_games, onLiveGames);
if (context.rtmt.connectionState === "connected") context.rtmt.sendMessage(channel_unsubscribe_live_games, {});
};
}, []);
if (!popular) return <></>;
const openGame = (id: string) => navigate(`/game/${id}`);
if (popular.kind === "live") {
return (
<HomeSection context={context} title={t("LiveGames")}>
{popular.games.map((game) => (
<GamePreviewCard
key={game.id}
context={context}
id={game.id}
player1={game.player1}
player2={game.player2}
board={game.board}
turnPlayerId={game.turnPlayerId}
lines={[t("Watching", { count: game.spectatorCount }) + " · " + t("MoveNumber", { number: game.moveCount })]}
onClick={() => openGame(game.id)} />
))}
</HomeSection>
);
}
return (
<HomeSection context={context} title={t("PopularGames")} emptyText={t("NoGamesYet")}>
{popular.games.map((game) => (
<GamePreviewCard
key={game.id}
context={context}
id={game.id}
player1={game.player1}
player2={game.player2}
board={game.board}
lines={[
`${getResultText(game, undefined, t)} · ${getScoreText(game, undefined)}`,
`${formatDate(game.endedAt, i18n.language)} · ${t("Watching", { count: game.peakSpectators })}`,
]}
onClick={() => openGame(game.id)} />
))}
</HomeSection>
);
};
export default LiveGamesSection;