feat(plan): atgardspanel som bottenpanel (Modal) i stallet for Alert

Klick pa en maltid oppnar en egen panel: 'Jag lagade detta' (ratt dag),
'Byt ratt', 'Ta bort'. Ingen 'Avbryt' - tryck utanfor for att stanga.
Kanns mer enterprise an systemets Alert-ruta.
This commit is contained in:
Claude
2026-08-19 23:54:34 +00:00
parent ceaf0de0c2
commit ec33634b3d
+70 -25
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react";
import { Alert, Pressable, Text, View } from "react-native";
import { Alert, Modal, Pressable, Text, View } from "react-native";
import { router } from "expo-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "@/lib/api";
@@ -11,6 +11,7 @@ import {
Card,
EmptyState,
ErrorView,
Heading,
LoadingView,
Row,
Screen,
@@ -67,6 +68,7 @@ export default function PlanScreen() {
const locale = getLanguageTag();
const queryClient = useQueryClient();
const [selectedKey, setSelectedKey] = useState<string>(() => toKey(new Date()));
const [actionEntry, setActionEntry] = useState<WeekPlanEntry | null>(null);
const [generating, setGenerating] = useState(false);
const todayKey = toKey(new Date());
@@ -175,31 +177,10 @@ export default function PlanScreen() {
onError: onMutationError,
});
// Öppnar en egen bottenpanel (Modal) i stället för Alert ingen "Avbryt",
// tryck utanför för att stänga (känns mer enterprise).
const openActions = (entry: WeekPlanEntry) => {
if (!planId) return;
Alert.alert(entry.titleSv, undefined, [
// "Jag lagade detta" bara på rätt dag inte för framtida måltider.
...(entry.date === todayKey
? [
{
text: t("recipe.iCookedThis"),
onPress: () => patchEntry.mutate({ planId, entryId: entry.id, status: "cooked" }),
},
]
: []),
{
text: "Byt rätt",
onPress: () =>
router.push(`/swap-meal/${entry.id}?planId=${planId}&mealType=${entry.mealType}`),
},
// Ersätter "Hoppa över": ta bort måltiden man inte lagat.
{
text: t("common.remove"),
style: "destructive" as const,
onPress: () => removeEntry.mutate({ planId, entryId: entry.id }),
},
{ text: t("common.cancel"), style: "cancel" as const },
]);
if (planId) setActionEntry(entry);
};
const monthLabel = cap(
@@ -386,6 +367,70 @@ export default function PlanScreen() {
/>
</>
) : null}
{/* Åtgärdspanel för en måltid tryck utanför för att stänga, ingen Avbryt. */}
<Modal
visible={actionEntry !== null}
transparent
animationType="fade"
onRequestClose={() => setActionEntry(null)}
>
<Pressable
onPress={() => setActionEntry(null)}
style={{ flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,0.4)" }}
>
<Pressable
onPress={() => {}}
style={{
backgroundColor: colors.surface,
borderTopLeftRadius: radius.lg,
borderTopRightRadius: radius.lg,
padding: spacing.lg,
paddingBottom: spacing.xl,
}}
>
{actionEntry ? (
<>
<Heading>{actionEntry.titleSv}</Heading>
{actionEntry.date === todayKey ? (
<>
<Button
label={t("recipe.iCookedThis")}
onPress={() => {
patchEntry.mutate({
planId: planId!,
entryId: actionEntry.id,
status: "cooked",
});
setActionEntry(null);
}}
/>
<Spacer size={spacing.xs} />
</>
) : null}
<Button
label="Byt rätt"
variant="secondary"
onPress={() => {
const e = actionEntry;
setActionEntry(null);
router.push(`/swap-meal/${e.id}?planId=${planId}&mealType=${e.mealType}`);
}}
/>
<Spacer size={spacing.xs} />
<Button
label={t("common.remove")}
variant="danger"
onPress={() => {
removeEntry.mutate({ planId: planId!, entryId: actionEntry.id });
setActionEntry(null);
}}
/>
</>
) : null}
</Pressable>
</Pressable>
</Modal>
</Screen>
);
}