diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7a02480..84c76be 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,8 @@ import { useState } from 'react'; import { GameList } from './components/GameList/GameList'; import { mockGames } from './mocks/games'; +import { SearchBar } from './components/SearchBar/SearchBar'; +import { useDebounce } from './hooks/useDebounce'; /** * Midlertidig forside: viser spillene med mockdata til GraphQL er klart. @@ -10,6 +12,16 @@ function App() { const [favorites, setFavorites] = useState>(new Set()); const [view, setView] = useState<'list' | 'grid'>('list'); + // Det brukeren skriver nå, og det vi faktisk søker på etter 300 ms pause + const [input, setInput] = useState(''); + const query = useDebounce(input.trim(), 300); + + // MIDLERTIDIG: filtrerer mockdata på klienten for å kunne teste søket. + // Når GraphQL er klart, sendes `query` til backend og filtreres i databasen. + const games = mockGames.filter((g) => + g.name.toLowerCase().includes(query.toLowerCase()), + ); + const toggleFavorite = (id: string) => { setFavorites((prev) => { const next = new Set(prev); @@ -22,6 +34,7 @@ function App() { return (

Spill

+

Søkeresultater

{/* Bytter mellom visning 1 (liste) og visning 2 (rutenett) */} @@ -35,7 +48,7 @@ function App() { void; +} + +// Søkefeltet øverst på siden. Komponenten eier ikke state selv: +// forelderen styrer verdien og bestemmer når det faktisk søkes (debounce). +export function SearchBar({ value, onChange }: SearchBarProps) { + return ( + // role="search" gjør at skjermlesere kan hoppe rett til søket. + // preventDefault hindrer at Enter laster siden på nytt. +
e.preventDefault()}> + {/* Skjult visuelt, men lest opp av skjermlesere. Placeholder alene er ikke nok. */} + + onChange(e.target.value)} + autoComplete="off" + /> +
+ ); +} \ No newline at end of file diff --git a/frontend/src/hooks/useDebounce.ts b/frontend/src/hooks/useDebounce.ts new file mode 100644 index 0000000..de40783 --- /dev/null +++ b/frontend/src/hooks/useDebounce.ts @@ -0,0 +1,12 @@ +import { useEffect, useState } from 'react'; + +export function useDebounce(value: T, delay = 300): T { + const [debounced, setDebounced] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebounced(value), delay); + return () => clearTimeout(timer); + }, [value, delay]); + + return debounced; +} \ No newline at end of file