Public Access
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.
51 lines
2.2 KiB
React
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>
|
|
);
|
|
}
|