import { format } from "date-fns"; import prettyBytes from "pretty-bytes"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Button } from "@renderer/components"; import { useDownload, useLibrary } from "@renderer/hooks"; import type { Game, ShopDetails } from "@types"; import { formatDownloadProgress } from "@renderer/helpers"; import { NoEntryIcon, PlusCircleIcon } from "@primer/octicons-react"; import { BinaryNotFoundModal } from "../shared-modals/binary-not-found-modal"; import * as styles from "./hero-panel.css"; import { useDate } from "@renderer/hooks/use-date"; 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, resumeDownload, pauseDownload, cancelDownload, removeGame, isGameDeleting, } = useDownload(); const { updateLibrary, library } = useLibrary(); const [toggleLibraryGameDisabled, setToggleLibraryGameDisabled] = useState(false); const gameOnLibrary = library.find( ({ objectID }) => objectID === gameDetails?.objectID ); 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 openGameInstaller = () => { window.electron.openGameInstaller(game.id).then((isBinaryInPath) => { if (!isBinaryInPath) setShowBinaryNotFoundModal(true); updateLibrary(); }); }; const openGame = () => { if (game.executablePath) { window.electron.openGame(game.id, game.executablePath); return; } if (game?.executablePath) { window.electron.openGame(game.id, game.executablePath); return; } window.electron .showOpenDialog({ properties: ["openFile"], filters: [{ name: "Game executable (.exe)", extensions: ["exe"] }], }) .then(({ filePaths }) => { if (filePaths && filePaths.length > 0) { const path = filePaths[0]; window.electron.openGame(game.id, path); } }); }; const closeGame = () => { window.electron.closeGame(game.id); }; const finalDownloadSize = useMemo(() => { if (!game) return "N/A"; if (game.fileSize) return prettyBytes(game.fileSize); if (gameDownloading?.fileSize && isGameDownloading) return prettyBytes(gameDownloading.fileSize); return game.repack?.fileSize ?? "N/A"; }, [game, isGameDownloading, gameDownloading]); const toggleLibraryGame = async () => { setToggleLibraryGameDisabled(true); try { if (gameOnLibrary) { await window.electron.removeGame(gameOnLibrary.id); } else { await window.electron.addGameToLibrary( gameDetails.objectID, gameDetails.name, "steam" ); } await updateLibrary(); } finally { setToggleLibraryGameDisabled(false); } }; const getInfo = () => { if (!gameDetails) return null; if (isGameDeleting(game?.id)) { return
{t("deleting")}
; } if (isGameDownloading) { return ( <>{progress} {eta && {t("eta", { eta })}}
{gameDownloading?.status !== "downloading" ? ( <>{t(gameDownloading?.status)}
{eta && {t("eta", { eta })}} > ) : ({prettyBytes(gameDownloading?.bytesDownloaded)} /{" "} {finalDownloadSize} {numPeers} peers / {numSeeds} seeds
)} > ); } if (game?.status === "paused") { return ( <>{t("paused_progress", { progress: formatDownloadProgress(game.progress), })}
{prettyBytes(game.bytesDownloaded)} / {finalDownloadSize}
> ); } if (game?.status === "seeding") { if (!game.lastTimePlayed) { return{t("not_played_yet", { title: game.title })}
; } return ( <>{t("play_time", { amount: formatDistance(0, game.playTimeInMilliseconds), })}
{t("last_time_played", { period: lastTimePlayed, })}
> ); } const [latestRepack] = gameDetails.repacks; if (latestRepack) { const lastUpdate = format(latestRepack.uploadDate!, "dd/MM/yyyy"); const repacksCount = gameDetails.repacks.length; return ( <>{t("updated_at", { updated_at: lastUpdate })}
{t("download_options", { count: repacksCount })}
> ); } return{t("no_downloads")}
; }; const getActions = () => { const deleting = isGameDeleting(game?.id); const toggleGameOnLibraryButton = ( ); if (isGameDownloading) { return ( <> > ); } if (game?.status === "paused") { return ( <> > ); } if (game?.status === "seeding") { return ( <> {isGamePlaying ? ( ) : ( )} > ); } if (game?.status === "cancelled") { return ( <> > ); } if (gameDetails && gameDetails.repacks.length) { return ( <> {toggleGameOnLibraryButton} > ); } return toggleGameOnLibraryButton; }; return ( <>