Files
ToBePlayed-Frontend/src/components/PlatformsCard.jsx
T
lobo f1a6bc0443 feat(library): show playtime per platform on game detail
Hero and library card show the set total. Fall back to the
row's own minutes when the API sends no total.
2026-10-09 13:55:57 +02:00

62 lines
3.0 KiB
React

import {Link} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import {Trophy} from 'lucide-react';
import {Card} from '@/components/ui/card';
import {cn} from '@/lib/utils';
import PlatformIcons from './PlatformIcons.jsx';
import {formatPlaytime} from '../utils/games.js';
import {formatDate} from '../utils/format.js';
import {platformLabel} from '../utils/platforms.js';
/**
* One row per platform of the game: playtime, last played and the progress of that platform. A row of another edition
* links to that edition, whose page lists its achievements.
*/
export default function PlatformsCard({game}) {
const {t, i18n} = useTranslation();
const lines = game.platforms;
if (!lines?.length) return null;
return (
<Card className="gap-3 p-4">
<h2 className="text-sm font-medium">{t('PLATFORMS.TITLE')}</h2>
<ul className="divide-y text-sm">
{lines.map((line, index) => {
const label = platformLabel(line) ?? t(`LIBRARY.SOURCE.${line.source}`);
return (
<li key={`${line.appid}:${line.source}:${index}`}
className="flex flex-wrap items-center gap-x-4 gap-y-1 py-2 first:pt-0 last:pb-0">
<span className="flex min-w-24 items-center gap-2 font-medium">
<PlatformIcons platforms={[line]}/>
{line.appid === game.appid
? <span>{label}</span>
: <Link to={`/library/${line.appid}`} className="hover:text-primary hover:underline">{label}</Link>}
</span>
<span className="tabular-nums">{formatPlaytime(line.playtimeMinutes)}</span>
<span className="text-muted-foreground">
{t('PLATFORMS.LAST_PLAYED')}{' '}
{line.lastPlayedAt
? formatDate(line.lastPlayedAt, i18n.language, {dateStyle: 'medium'})
: t('PLATFORMS.NEVER')}
</span>
{line.achievementsTotal != null && (
<span className="inline-flex items-center gap-1 tabular-nums">
<Trophy className={cn('size-3', line.perfect && 'text-amber-500')}/>
{line.achievementsUnlocked ?? '?'} / {line.achievementsTotal}
</span>
)}
</li>
);
})}
</ul>
{lines.length > 1 && (
<p className="flex items-center justify-between border-t pt-2 text-sm font-medium">
<span>{t('PLATFORMS.TOTAL')}</span>
<span className="tabular-nums">{formatPlaytime(game.totalPlaytimeMinutes)}</span>
</p>
)}
</Card>
);
}