Files
ToBePlayed-Frontend/src/pages/GameSearchPage.jsx
T
lobo 60dcfe8992
Build, Test & Push Frontend / quality-check (push) Successful in 44s
Build, Test & Push Frontend / docker (push) Successful in 27s
feat(search): add game search page (#50)
Add /search to find games by name on IGDB.
A game in the library opens its game page. Other hits open a
detail view with an Add button. The query stays in the URL.
To fit the new nav icon on 360 px phones, the header padding is
smaller and the points chip hides while the Questions icon shows.
2026-10-20 10:42:06 +02:00

51 lines
2.2 KiB
React

import {useEffect, useState} from 'react';
import {useNavigate, useSearchParams} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import {Search} from 'lucide-react';
import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card';
import GameSearch from '../components/GameSearch.jsx';
import PageContainer from '../components/PageContainer.jsx';
import SearchHitCard from '../components/SearchHitCard.jsx';
/**
* Find games by name on IGDB. A game the user owns opens its page; any other hit opens a detail view with "Add".
* The query lives in the URL, so it stays when the user comes back from a game page.
*/
export default function GameSearchPage() {
const {t} = useTranslation();
const navigate = useNavigate();
const [params, setParams] = useSearchParams();
const [query, setQuery] = useState(params.get('q') ?? '');
const [picked, setPicked] = useState(null);
// The input keeps its own state: a router update per keystroke runs in a transition and drops keys of a burst.
useEffect(() => {
const timer = setTimeout(() => setParams(query ? {q: query} : {}, {replace: true}), 400);
return () => clearTimeout(timer);
}, [query, setParams]);
const onQueryChange = (q) => {
setPicked(null);
setQuery(q);
};
const onPick = (hit) => (hit.inLibrary ? navigate(`/library/${hit.appid}`) : setPicked(hit));
return (
<PageContainer className="space-y-4 px-4 py-6 md:px-8">
{picked ? (
<SearchHitCard hit={picked} onBack={() => setPicked(null)}/>
) : (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2"><Search className="size-4 text-primary"/>{t('GAME_SEARCH.TITLE')}</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<p className="text-sm text-muted-foreground">{t('GAME_SEARCH.HINT')}</p>
<GameSearch query={query} onQueryChange={onQueryChange} onPick={onPick} markInLibrary/>
</CardContent>
</Card>
)}
</PageContainer>
);
}