import React, {useEffect, useState} from "react"; import {DownloadProviderEndpoint, GameEndpoint} from "Frontend/generated/endpoints"; import {useNavigate, useParams} from "react-router"; import {GameCover} from "Frontend/components/general/covers/GameCover"; import ComboButton, {ComboButtonOption} from "Frontend/components/general/input/ComboButton"; import ImageCarousel from "Frontend/components/general/covers/ImageCarousel"; import {Accordion, AccordionItem, addToast, Button, Chip, Link, Tooltip, useDisclosure} from "@heroui/react"; import {gameRatingInStars, humanFileSize, isAdmin, toTitleCase} from "Frontend/util/utils"; import {DownloadEndpoint} from "Frontend/endpoints/endpoints"; import {gameState} from "Frontend/state/GameState"; import {useSnapshot} from "valtio/react"; import {CheckCircle, Info, MagnifyingGlass, Pencil, Star, Trash, TriangleDashed} from "@phosphor-icons/react"; import {useAuth} from "Frontend/util/auth"; import MatchGameModal from "Frontend/components/general/modals/MatchGameModal"; import EditGameMetadataModal from "Frontend/components/general/modals/EditGameMetadataModal"; import GameUpdateDto from "Frontend/generated/org/gameyfin/app/games/dto/GameUpdateDto"; import Markdown from "react-markdown"; import remarkBreaks from "remark-breaks"; import {GameAdminDto} from "Frontend/dtos/GameDtos"; export default function GameView() { const {gameId} = useParams(); const navigate = useNavigate(); const auth = useAuth(); const editGameModal = useDisclosure(); const matchGameModal = useDisclosure(); const state = useSnapshot(gameState); const game = gameId ? state.state[parseInt(gameId)] as GameAdminDto : undefined; const [downloadOptions, setDownloadOptions] = useState>(); useEffect(() => { DownloadProviderEndpoint.getProviders().then((providers) => { const options: Record = providers.reduce((acc, provider) => { acc[provider.key] = { label: provider.name, description: provider.shortDescription ?? provider.description, action: () => { if (gameId) DownloadEndpoint.downloadGame(parseInt(gameId), provider.key); }, }; return acc; }, {} as Record); setDownloadOptions(options); }); }, [gameId]); useEffect(() => { if (state.isLoaded && (!gameId || !state.state[parseInt(gameId)])) { navigate("/", {replace: true}); } document.title = game ? game.title : "Gameyfin"; }, [gameId, state]); async function toggleMatchConfirmed() { if (!game) return; await GameEndpoint.updateGame( { id: game.id, metadata: {matchConfirmed: !game.metadata.matchConfirmed} } as GameUpdateDto ) } async function deleteGame() { if (!game) return; await GameEndpoint.deleteGame(game.id); addToast({ title: "Game deleted", description: `${game.title} removed from Gameyfin!`, color: "success" }); } return game && (
{game.headerId ? ( Game header ) : game.imageIds && game.imageIds.length > 0 ? ( Game screenshot ) : (
)}

{game.title}

{gameRatingInStars(game)}

{game.release !== undefined ? new Date(game.release).getFullYear() :

no data

}

{isAdmin(auth) &&
} {downloadOptions && }
{game.comment && }> {props.children} } }} >{game.comment} }

Summary

{game.summary ?
:

No summary available

}

Details

Developed by {game.developers && game.developers.length > 0 ? [...game.developers].sort().map((dev, index) => <> {dev} {index !== game.developers!!.length - 1 &&

/

} ) : }
Published by {game.publishers && game.publishers.length > 0 ? [...game.publishers].sort().join(" / ") : }
Genres {game.genres && game.genres.length > 0 ? [...game.genres].sort().map(genre => {toTitleCase(genre)} ) : }
Themes {game.themes && game.themes.length > 0 ? [...game.themes].sort().map(theme => {toTitleCase(theme)} ) : }
Features {game.features && game.features.length > 0 ? [...game.features].sort().map(feature => {toTitleCase(feature)} ) : }

Media

`/images/screenshot/${id}`)} videosUrls={game.videoUrls} className="-mx-24" />
); }