hydra/src/renderer/pages/game-details/hero-panel.tsx
2024-04-20 20:40:16 +01:00

196 lines
5 KiB
TypeScript

import { format } from "date-fns";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDownload } from "@renderer/hooks";
import type { Game, ShopDetails } from "@types";
import { formatDownloadProgress } from "@renderer/helpers";
import { BinaryNotFoundModal } from "../shared-modals/binary-not-found-modal";
import * as styles from "./hero-panel.css";
import { useDate } from "@renderer/hooks/use-date";
import { formatBytes } from "@renderer/utils";
import { HeroPanelActions } from "./hero-panel-actions";
export interface HeroPanelProps {
game: Game | null;
gameDetails: ShopDetails | null;
color: string;
isGamePlaying: boolean;
openRepacksModal: () => void;
getGame: () => void;
}
export function HeroPanel({
game,
gameDetails,
color,
openRepacksModal,
getGame,
isGamePlaying,
}: HeroPanelProps) {
const { t } = useTranslation("game_details");
const [showBinaryNotFoundModal, setShowBinaryNotFoundModal] = useState(false);
const [lastTimePlayed, setLastTimePlayed] = useState("");
const { formatDistance } = useDate();
const {
game: gameDownloading,
isDownloading,
progress,
eta,
numPeers,
numSeeds,
isGameDeleting,
} = useDownload();
const isGameDownloading = isDownloading && gameDownloading?.id === game?.id;
const updateLastTimePlayed = useCallback(() => {
setLastTimePlayed(
formatDistance(game.lastTimePlayed, new Date(), {
addSuffix: true,
})
);
}, [game?.lastTimePlayed, formatDistance]);
useEffect(() => {
if (game?.lastTimePlayed) {
updateLastTimePlayed();
const interval = setInterval(() => {
updateLastTimePlayed();
}, 1000);
return () => {
clearInterval(interval);
};
}
}, [game?.lastTimePlayed, updateLastTimePlayed]);
const finalDownloadSize = useMemo(() => {
if (!game) return "N/A";
if (game.fileSize) return formatBytes(game.fileSize);
if (gameDownloading?.fileSize && isGameDownloading)
return formatBytes(gameDownloading.fileSize);
return game.repack?.fileSize ?? "N/A";
}, [game, isGameDownloading, gameDownloading]);
const getInfo = () => {
if (!gameDetails) return null;
if (isGameDeleting(game?.id)) {
return <p>{t("deleting")}</p>;
}
if (isGameDownloading) {
return (
<>
<p className={styles.downloadDetailsRow}>
{progress}
{eta && <small>{t("eta", { eta })}</small>}
</p>
{gameDownloading?.status !== "downloading" ? (
<>
<p>{t(gameDownloading?.status)}</p>
{eta && <small>{t("eta", { eta })}</small>}
</>
) : (
<p className={styles.downloadDetailsRow}>
{formatBytes(gameDownloading?.bytesDownloaded)} /{" "}
{finalDownloadSize}
<small>
{numPeers} peers / {numSeeds} seeds
</small>
</p>
)}
</>
);
}
if (game?.status === "paused") {
return (
<>
<p>
{t("paused_progress", {
progress: formatDownloadProgress(game.progress),
})}
</p>
<p>
{formatBytes(game.bytesDownloaded)} / {finalDownloadSize}
</p>
</>
);
}
if (game?.status === "seeding" || (game && !game.status)) {
if (!game.lastTimePlayed) {
return <p>{t("not_played_yet", { title: game.title })}</p>;
}
return (
<>
<p>
{t("play_time", {
amount: formatDistance(0, game.playTimeInMilliseconds),
})}
</p>
{isGamePlaying ? (
<p>{t("playing_now")}</p>
) : (
<p>
{t("last_time_played", {
period: lastTimePlayed,
})}
</p>
)}
</>
);
}
const [latestRepack] = gameDetails.repacks;
if (latestRepack) {
const lastUpdate = format(latestRepack.uploadDate!, "dd/MM/yyyy");
const repacksCount = gameDetails.repacks.length;
return (
<>
<p>{t("updated_at", { updated_at: lastUpdate })}</p>
<p>{t("download_options", { count: repacksCount })}</p>
</>
);
}
return <p>{t("no_downloads")}</p>;
};
return (
<>
<BinaryNotFoundModal
visible={showBinaryNotFoundModal}
onClose={() => setShowBinaryNotFoundModal(false)}
/>
<div style={{ backgroundColor: color }} className={styles.panel}>
<div className={styles.content}>{getInfo()}</div>
<div className={styles.actions}>
<HeroPanelActions
game={game}
gameDetails={gameDetails}
getGame={getGame}
openRepacksModal={openRepacksModal}
openBinaryNotFoundModal={() => setShowBinaryNotFoundModal(true)}
isGamePlaying={isGamePlaying}
isGameDownloading={isGameDownloading}
/>
</div>
</div>
</>
);
}