66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { useState } from "react";
|
||
import { router } from "expo-router";
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import { api } from "@/lib/api";
|
||
import { Card, EmptyState, ErrorView, Heading, Input, LoadingView, Screen, Small } from "@/components/ui";
|
||
import { spacing } from "@/lib/theme";
|
||
|
||
/** Dina sparade recept (favoriter) – sökbar lista. Backend: GET /v1/recipes/favorites/mine. */
|
||
|
||
interface SavedRecipe {
|
||
id: string;
|
||
titleSv: string;
|
||
totalTimeMinutes: number | null;
|
||
nutritionPerPortion: { kcal?: number } | null;
|
||
}
|
||
interface FavoritesResponse {
|
||
recipes: SavedRecipe[];
|
||
}
|
||
|
||
export default function SavedRecipesScreen() {
|
||
const [query, setQuery] = useState("");
|
||
const favs = useQuery<FavoritesResponse>({
|
||
queryKey: ["favorites-mine"],
|
||
queryFn: () => api<FavoritesResponse>("/v1/recipes/favorites/mine"),
|
||
});
|
||
|
||
if (favs.isLoading) return <LoadingView />;
|
||
if (favs.isError) return <ErrorView onRetry={() => void favs.refetch()} />;
|
||
|
||
const all = favs.data?.recipes ?? [];
|
||
const q = query.trim().toLowerCase();
|
||
const filtered = q ? all.filter((r) => r.titleSv.toLowerCase().includes(q)) : all;
|
||
|
||
return (
|
||
<Screen style={{ gap: spacing.md }}>
|
||
<Input
|
||
placeholder="Sök bland dina sparade recept"
|
||
autoCapitalize="none"
|
||
value={query}
|
||
onChangeText={setQuery}
|
||
/>
|
||
{all.length === 0 ? (
|
||
<EmptyState text="Du har inga sparade recept än. Tryck på ☆ Spara på ett recept så hamnar det här." />
|
||
) : filtered.length === 0 ? (
|
||
<EmptyState text="Inga sparade recept matchar din sökning." />
|
||
) : (
|
||
filtered.map((r) => (
|
||
<Card key={r.id} onPress={() => router.push(`/recipe/${r.id}`)} style={{ gap: spacing.xs }}>
|
||
<Heading>{r.titleSv}</Heading>
|
||
<Small>
|
||
{[
|
||
r.totalTimeMinutes != null ? `${r.totalTimeMinutes} min` : null,
|
||
r.nutritionPerPortion?.kcal != null
|
||
? `${Math.round(r.nutritionPerPortion.kcal)} kcal`
|
||
: null,
|
||
]
|
||
.filter(Boolean)
|
||
.join(" · ")}
|
||
</Small>
|
||
</Card>
|
||
))
|
||
)}
|
||
</Screen>
|
||
);
|
||
}
|