feat(byt-ratt): sok bland ALLA recept vid byte

Byt-ratt-skarmen far ett sokfalt. Med sokning filtreras maltidstyp bort
pa servern -> byt till vilken ratt som helst. Utan sokning visas breda
forslag for slotten (view=swap).
This commit is contained in:
Claude
2026-08-19 23:54:34 +00:00
parent fbf5c82ccc
commit ceaf0de0c2
+40 -9
View File
@@ -1,3 +1,4 @@
import { useState } from "react";
import { router, useLocalSearchParams } from "expo-router";
import { Alert } from "react-native";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -8,13 +9,16 @@ import {
Card,
EmptyState,
ErrorView,
Input,
LoadingView,
Row,
Screen,
Small,
Spacer,
Tag,
Title,
} from "@/components/ui";
import { spacing } from "@/lib/theme";
interface Rec {
recipeId: string;
@@ -32,13 +36,20 @@ export default function SwapMealScreen() {
const mealType = String(params.mealType || "dinner");
const queryClient = useQueryClient();
const [searchText, setSearchText] = useState("");
const [submitted, setSubmitted] = useState("");
const query = useQuery({
queryKey: ["swap-options", mealType],
// view=swap: bredda urvalet alla lämpliga rätter, inte bara det man har hemma.
queryFn: () =>
api<WhatToEatResponse>(
`/v1/recommendations/what-to-eat?limit=20&view=swap&mealType=${mealType}`,
),
queryKey: ["swap-options", mealType, submitted],
// Med sökning: byt till VILKEN rätt som helst (mealType filtreras då bort på
// servern). Utan sökning: breda förslag för slotten (view=swap, låg täckningsvikt).
queryFn: () => {
const base = "/v1/recommendations/what-to-eat?limit=30&view=swap";
const path = submitted
? `${base}&search=${encodeURIComponent(submitted)}`
: `${base}&mealType=${mealType}`;
return api<WhatToEatResponse>(path);
},
});
const swap = useMutation({
@@ -53,15 +64,35 @@ export default function SwapMealScreen() {
});
const recs = query.data?.recommendations ?? [];
const mealLabel = mealType === "lunch" ? "lunchen" : mealType === "breakfast" ? "frukosten" : "middagen";
const mealLabel =
mealType === "lunch" ? "lunchen" : mealType === "breakfast" ? "frukosten" : "middagen";
return (
<Screen>
<Title>Byt ut måltiden</Title>
<Small>Välj en annan rätt för {mealLabel}:</Small>
<Small>Välj en annan rätt för {mealLabel} eller sök efter vilken rätt som helst.</Small>
<Spacer size={spacing.sm} />
<Input
placeholder="Sök bland alla recept …"
value={searchText}
onChangeText={setSearchText}
onSubmitEditing={() => setSubmitted(searchText.trim())}
returnKeyType="search"
autoCorrect={false}
/>
{submitted ? (
<Small>
Visar träffar för {submitted}.{" "}
<Small>Rensa sökrutan och sök tomt för att se förslag igen.</Small>
</Small>
) : null}
<Spacer size={spacing.xs} />
{query.isLoading && <LoadingView />}
{query.isError && <ErrorView onRetry={() => void query.refetch()} />}
{query.data && recs.length === 0 && <EmptyState text={t("wte.empty")} />}
{query.data && recs.length === 0 && (
<EmptyState text={submitted ? "Inga recept matchar sökningen." : t("wte.empty")} />
)}
{recs.map((rec) => (
<Card key={rec.recipeId} onPress={() => swap.mutate(rec.recipeId)}>
<Row style={{ justifyContent: "space-between", alignItems: "center" }}>