diff --git a/apps/mobile/src/app/(tabs)/plan.tsx b/apps/mobile/src/app/(tabs)/plan.tsx index d9fa895..dfccdba 100644 --- a/apps/mobile/src/app/(tabs)/plan.tsx +++ b/apps/mobile/src/app/(tabs)/plan.tsx @@ -178,6 +178,11 @@ export default function PlanScreen() { text: t("common.skip"), onPress: () => patchEntry.mutate({ planId, entryId: entry.id, status: "skipped" }), }, + { + text: "Byt rätt", + onPress: () => + router.push(`/swap-meal/${entry.id}?planId=${planId}&mealType=${entry.mealType}`), + }, { text: t("common.cancel"), style: "cancel" }, ]); }; diff --git a/apps/mobile/src/app/_layout.tsx b/apps/mobile/src/app/_layout.tsx index 56595f7..6d55e70 100644 --- a/apps/mobile/src/app/_layout.tsx +++ b/apps/mobile/src/app/_layout.tsx @@ -77,6 +77,7 @@ export default function RootLayout() { options={{ title: "", presentation: "fullScreenModal" }} /> + diff --git a/apps/mobile/src/app/swap-meal/[entryId].tsx b/apps/mobile/src/app/swap-meal/[entryId].tsx new file mode 100644 index 0000000..14deb82 --- /dev/null +++ b/apps/mobile/src/app/swap-meal/[entryId].tsx @@ -0,0 +1,75 @@ +import { router, useLocalSearchParams } from "expo-router"; +import { Alert } from "react-native"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { api } from "@/lib/api"; +import { t } from "@/lib/i18n"; +import { + Body, + Card, + EmptyState, + ErrorView, + LoadingView, + Row, + Screen, + Small, + Tag, + Title, +} from "@/components/ui"; + +interface Rec { + recipeId: string; + titleSv: string; + coveragePercent: number; +} +interface WhatToEatResponse { + recommendations: Rec[]; +} + +export default function SwapMealScreen() { + const params = useLocalSearchParams<{ entryId: string; planId: string; mealType: string }>(); + const entryId = String(params.entryId); + const planId = String(params.planId); + const mealType = String(params.mealType || "dinner"); + const queryClient = useQueryClient(); + + const query = useQuery({ + queryKey: ["swap-options", mealType], + queryFn: () => + api(`/v1/recommendations/what-to-eat?limit=10&mealType=${mealType}`), + }); + + const swap = useMutation({ + mutationFn: (recipeId: string) => + api(`/v1/week-plans/${planId}/entries/${entryId}`, { method: "PATCH", body: { recipeId } }), + onSuccess: () => { + void queryClient.invalidateQueries({ queryKey: ["week-plan"] }); + router.back(); + }, + onError: (err) => + Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error")), + }); + + const recs = query.data?.recommendations ?? []; + const mealLabel = mealType === "lunch" ? "lunchen" : mealType === "breakfast" ? "frukosten" : "middagen"; + + return ( + + Byt ut måltiden + Välj en annan rätt för {mealLabel}: + {query.isLoading && } + {query.isError && void query.refetch()} />} + {query.data && recs.length === 0 && } + {recs.map((rec) => ( + swap.mutate(rec.recipeId)}> + + {rec.titleSv} + = 80 ? "success" : "neutral"} + /> + + + ))} + + ); +}