Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/components/recipe/RecipeList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function RecipeList({ recipes }: RecipeListProps) {
return (
<ul className="mt-8 grid grid-cols-2 gap-6 sm:grid-cols-2 lg:grid-cols-4">
{recipes.map((recipe)=> (
<li key={recipe.recipeId} className="h-full">
<li key={recipe.id} className="h-full">
<RecipeCard recipe={recipe} />
</li>
))}
Expand Down
17 changes: 17 additions & 0 deletions client/src/graphql/recipes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { gql, type TypedDocumentNode } from '@apollo/client';
import type { Recipe } from '../types/recipe';

type GetRecipesData = { recipes: Recipe[] };
type GetRecipesVariables = { page?: number ; pageSize?: number };

export const GET_RECIPES: TypedDocumentNode<GetRecipesData, GetRecipesVariables> = gql`
query GetRecipes($page: Int, $pageSize: Int) {
recipes(page: $page, pageSize: $pageSize) {
id
imageUrl
title
prepTimeMinutes
servings
}
}
`
2 changes: 1 addition & 1 deletion client/src/routes/RecipeDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { RecipeDetail } from '../components/recipe/RecipeDetail';
// Placeholder for en oppskrift. Henter id fra URL-en. som /recipes/5 gir id = 5
export default function RecipeDetailPage() {
const { id } = useParams();
const recipe = recipes.find((r) => r.recipeId === id);
const recipe = recipes.find((r) => r.id === id);
if (!recipe) {
return <p>Fant ikke oppskriften.</p>
}
Expand Down
56 changes: 54 additions & 2 deletions client/src/routes/RecipeListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,71 @@
import { useSearchParams } from 'react-router';
import { RecipeList } from '../components/recipe/RecipeList';
import { recipes} from '../mocks/recipes';
import { useQuery } from '@apollo/client/react';
import { GET_RECIPES } from '../graphql/recipes';
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.
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 },
});

const [hasMore, setHasMore] = useState(true);

if (loading && !data) {
return <p role="status">Laster oppskrifter...</p>
}
if(error) {
return <p role="alert">Kunne ikke hente oppskriftene. Prøv igjen senere.</p>
}

const recipes = data?.recipes ?? [];

async function handleLoadMore() {
// Regner ut hvilke side som er neste.
const nextPage = Math.floor(recipes.length / PAGE_SIZE) + 1;

// Henter neste side
const result = await fetchMore({
variables: {page: nextPage},
// Legger de nye oppskriftene etter de gamle
updateQuery: (previous, { fetchMoreResult }) => ({
recipes: [...previous.recipes, ...fetchMoreResult.recipes],
}),
});

// Dersom det er færre enn 12 er det ikke flere oppskrifter igjen.
if ((result.data?.recipes.length ?? 0) < PAGE_SIZE) {
setHasMore(false);
}
}

return (
<>
<h1 className="font-heading text-4xl md:text-5xl">Oppskrifter</h1>

{query && <p className="mt-4">Alt med «{query}»</p>}
<RecipeList recipes={ recipes } />
<RecipeList recipes={recipes} />

{/*Knappen vises bare hvis det kan finnes flere oppskrifter og første side er full*/}
{hasMore && recipes.length >= PAGE_SIZE && (
<div className="mt-8 flex justify-center">
<button
type="button"
onClick={handleLoadMore}
disabled={loading}
className="rounded-full bg-primary text-background px-6 py-3 hover:opacity-90 disabled:opacity-50"
>
{loading ? 'Laster...' : 'Last flere'}
</button>
</div>
)}
</>
);
}