import Color from "color"; import { average } from "color.js"; import { useCallback, useEffect, useRef, useState } from "react"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import type { Game, GameShop, HowLongToBeatCategory, ShopDetails, SteamAppDetails, } from "@types"; import { AsyncImage, Button } from "@renderer/components"; import { setHeaderTitle } from "@renderer/features"; import { getSteamLanguage, steamUrlBuilder } from "@renderer/helpers"; import { useAppDispatch, useDownload } from "@renderer/hooks"; import starsAnimation from "@renderer/assets/lottie/stars.json"; import { vars } from "@renderer/theme.css"; import Lottie from "lottie-react"; import { useTranslation } from "react-i18next"; import { SkeletonTheme } from "react-loading-skeleton"; import { DescriptionHeader } from "./description-header"; import { GameDetailsSkeleton } from "./game-details-skeleton"; import * as styles from "./game-details.css"; import { HeroPanel } from "./hero-panel"; import { HowLongToBeatSection } from "./how-long-to-beat-section"; import { RepacksModal } from "./repacks-modal"; export function GameDetails() { const { objectID, shop } = useParams(); const [isLoading, setIsLoading] = useState(false); const [color, setColor] = useState(""); const [gameDetails, setGameDetails] = useState(null); const [howLongToBeat, setHowLongToBeat] = useState<{ isLoading: boolean; data: HowLongToBeatCategory[] | null; }>({ isLoading: true, data: null }); const [game, setGame] = useState(null); const [isGamePlaying, setIsGamePlaying] = useState(false); const [activeRequirement, setActiveRequirement] = useState("minimum"); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); const dispatch = useAppDispatch(); const { game: gameDownloading, startDownload, isDownloading } = useDownload(); const getRandomGame = useCallback(() => { window.electron.getRandomGame().then((objectID) => { randomGameObjectID.current = objectID; }); }, []); const handleImageSettled = useCallback((url: string) => { average(url, { amount: 1, format: "hex" }) .then((color) => { setColor(new Color(color).darken(0.6).toString() as string); }) .catch(() => {}); }, []); const getGame = useCallback(() => { window.electron .getGameByObjectID(objectID) .then((result) => setGame(result)); }, [setGame, objectID]); useEffect(() => { getGame(); }, [getGame, gameDownloading?.id]); useEffect(() => { setGame(null); setIsLoading(true); setIsGamePlaying(false); dispatch(setHeaderTitle("")); getRandomGame(); window.electron .getGameShopDetails(objectID, "steam", getSteamLanguage(i18n.language)) .then((result) => { if (!result) { navigate(-1); return; } window.electron .getHowLongToBeat(objectID, "steam", result.name) .then((data) => { setHowLongToBeat({ isLoading: false, data }); }); setGameDetails(result); dispatch(setHeaderTitle(result.name)); }) .finally(() => { setIsLoading(false); }); getGame(); setHowLongToBeat({ isLoading: true, data: null }); }, [getGame, getRandomGame, dispatch, navigate, objectID, i18n.language]); const isGameDownloading = isDownloading && gameDownloading?.id === game?.id; useEffect(() => { if (isGameDownloading) setGame((prev) => ({ ...prev, status: gameDownloading?.status })); }, [isGameDownloading, gameDownloading?.status]); useEffect(() => { const listeners = [ window.electron.onGameClose(() => { if (isGamePlaying) setIsGamePlaying(false); }), window.electron.onPlaytime((gameId) => { if (gameId === game?.id) { if (!isGamePlaying) setIsGamePlaying(true); getGame(); } }), ]; return () => { listeners.forEach((unsubscribe) => unsubscribe()); }; }, [game?.id, isGamePlaying, getGame]); const handleStartDownload = async ( repackId: number, downloadPath: string ) => { return startDownload( repackId, gameDetails.objectID, gameDetails.name, shop as GameShop, downloadPath ).then(() => { getGame(); setShowRepacksModal(false); setShowSelectFolderModal(false); }); }; const handleRandomizerClick = () => { if (!randomGameObjectID.current) return; const searchParams = new URLSearchParams({ fromRandomizer: "1", }); navigate( `/game/steam/${randomGameObjectID.current}?${searchParams.toString()}` ); }; const fromRandomizer = searchParams.get("fromRandomizer"); return ( {gameDetails && ( setShowRepacksModal(false)} /> )} {isLoading ? ( ) : (
setShowRepacksModal(true)} getGame={getGame} isGamePlaying={isGamePlaying} />

{t("requirements")}

)} {fromRandomizer && ( )}
); }