From 28e5e9db51d744126c3577439e56b2c5bd5ab0a2 Mon Sep 17 00:00:00 2001 From: Mari Zhevagin Date: Thu, 15 Oct 2026 00:16:52 +0200 Subject: [PATCH 1/2] =?UTF-8?q?s=C3=B8k=20filtrere=20oppskrifter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/graphql/recipes.ts | 6 +++--- client/src/routes/RecipeListPage.tsx | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/client/src/graphql/recipes.ts b/client/src/graphql/recipes.ts index 9394999..c932fc2 100644 --- a/client/src/graphql/recipes.ts +++ b/client/src/graphql/recipes.ts @@ -2,14 +2,14 @@ import { gql, type TypedDocumentNode } from '@apollo/client'; import type { Recipe } from '../types/recipe'; type GetRecipesData = { recipes: Recipe[] }; -type GetRecipesVariables = { page?: number ; pageSize?: number }; +type GetRecipesVariables = { search?: string; page?: number ; pageSize?: number }; type GetRecipeData = { recipe: Recipe | null }; type GetRecipeVariables = { id: string }; export const GET_RECIPES: TypedDocumentNode = gql` - query GetRecipes($page: Int, $pageSize: Int) { - recipes(page: $page, pageSize: $pageSize) { + query GetRecipes($search: String, $page: Int, $pageSize: Int) { + recipes(search: $search, page: $page, pageSize: $pageSize) { id imageUrl title diff --git a/client/src/routes/RecipeListPage.tsx b/client/src/routes/RecipeListPage.tsx index 85325eb..d8ebc23 100644 --- a/client/src/routes/RecipeListPage.tsx +++ b/client/src/routes/RecipeListPage.tsx @@ -7,17 +7,24 @@ import { useState } from 'react'; const PAGE_SIZE = 12; // Listen over alle oppskrifter eller søksresultatet -// Selve søkefeltet ligger i headeren. Resultatene kobles til senere. +// Selve søkefeltet ligger i headeren export default function RecipeListPage() { const [searchParams] = useSearchParams(); const query = searchParams.get('q') ?? ''; const { data, loading, error, fetchMore } = useQuery(GET_RECIPES, { - variables: { page: 1, pageSize: PAGE_SIZE }, + variables: { search: query || undefined, page: 1, pageSize: PAGE_SIZE }, }); const [hasMore, setHasMore] = useState(true); + // nullstiller når man søker på noe nytt + const [prevQuery, setPrevQuery] = useState(query); + if (query !== prevQuery) { + setPrevQuery(query); + setHasMore(true); + } + if (loading && !data) { return

Laster oppskrifter...

} @@ -50,7 +57,12 @@ export default function RecipeListPage() { <>

Oppskrifter

- {query &&

Alt med «{query}»

} + {query && recipes.length > 0 &&

Alt med '{query}'

} + + {/* melding hvis søket ikke finner noe */} + {query && recipes.length === 0 && ( +

Fant ingen oppskrifter med '{query}'.

+ )} {/*Knappen vises bare hvis det kan finnes flere oppskrifter og første side er full*/} From 1d4cd1ae966d1899c88dfa9a34f23dc78c3b24e7 Mon Sep 17 00:00:00 2001 From: Mari Zhevagin Date: Thu, 15 Oct 2026 00:46:40 +0200 Subject: [PATCH 2/2] debounce og prettier --- client/src/components/layout/MobileHeader.tsx | 7 +- client/src/components/layout/SearchBar.tsx | 33 +++++++- client/src/components/layout/StickyHeader.tsx | 2 +- client/src/components/layout/TopHeader.tsx | 7 +- client/src/graphql/recipes.ts | 78 ++++++++++--------- client/src/routes/RecipeListPage.tsx | 14 ++-- 6 files changed, 85 insertions(+), 56 deletions(-) diff --git a/client/src/components/layout/MobileHeader.tsx b/client/src/components/layout/MobileHeader.tsx index 19ce238..2ce60e3 100644 --- a/client/src/components/layout/MobileHeader.tsx +++ b/client/src/components/layout/MobileHeader.tsx @@ -29,12 +29,7 @@ export function MobileHeader({ query }: MobileHeaderProps) { } }} > - + ) : ( <> diff --git a/client/src/components/layout/SearchBar.tsx b/client/src/components/layout/SearchBar.tsx index f292ba0..88bd659 100644 --- a/client/src/components/layout/SearchBar.tsx +++ b/client/src/components/layout/SearchBar.tsx @@ -1,5 +1,5 @@ -import { useState, type SubmitEvent } from 'react'; -import { useNavigate } from 'react-router'; +import { useState, useEffect, type SubmitEvent } from 'react'; +import { useNavigate, useLocation } from 'react-router'; type SearchBarProps = { initialQuery: string; @@ -17,6 +17,34 @@ export default function SearchBar({ }: SearchBarProps) { const [input, setInput] = useState(initialQuery); const navigate = useNavigate(); + const location = useLocation(); + + //oppdaterer søket når URL forandes med feks. tilbakeknapp + const [prevQuery, setPrevQuery] = useState(initialQuery); + if (initialQuery !== prevQuery) { + setPrevQuery(initialQuery); + setInput(initialQuery); + } + + // søker av seg selv litt etter man slutter å skrive + useEffect(() => { + const trimmed = input.trim(); + // søker ikke på nytt hvis søkteksten matcher urlen + if (trimmed === initialQuery) return; + + const timer = setTimeout(() => { + // tomt felt viser alle oppskrifter + const url = trimmed + ? `/recipes?q=${encodeURIComponent(trimmed)}` + : '/recipes'; + // erstatter historikken så tilbakeknappen ikke går gjennom hver bokstav + navigate(url, { replace: location.pathname === '/recipes' }); + // forandre her hvis vi skal forandre hvor fort autosøk skjer + }, 400); + + // avbryter hvis man skriver mer før tiden er ute + return () => clearTimeout(timer); + }, [input, initialQuery, navigate, location.pathname]); function handleSubmit(event: SubmitEvent) { // Hindrer at skjemaet laster siden på nytt @@ -69,6 +97,7 @@ export default function SearchBar({ onChange={(event) => setInput(event.target.value)} placeholder="Søk etter oppskrift" autoFocus={autoFocus} + autoComplete="off" className="min-w-0 flex-1 bg-transparent py-2 pr-4 pl-1 text-sm placeholder:text-text/70 focus:outline-none" /> diff --git a/client/src/components/layout/StickyHeader.tsx b/client/src/components/layout/StickyHeader.tsx index eda7b4e..8d7ad35 100644 --- a/client/src/components/layout/StickyHeader.tsx +++ b/client/src/components/layout/StickyHeader.tsx @@ -40,7 +40,7 @@ export function StickyHeader({ visible, query }: StickyHeaderProps) {
- +
diff --git a/client/src/components/layout/TopHeader.tsx b/client/src/components/layout/TopHeader.tsx index 4a738ef..c97e5b6 100644 --- a/client/src/components/layout/TopHeader.tsx +++ b/client/src/components/layout/TopHeader.tsx @@ -51,12 +51,7 @@ export function TopHeader({ query, scrolled }: TopHeaderProps) { } }} > - + ) : (