diff --git a/apps/api/src/routes/shopping.ts b/apps/api/src/routes/shopping.ts
index 2c5a20b..f909576 100644
--- a/apps/api/src/routes/shopping.ts
+++ b/apps/api/src/routes/shopping.ts
@@ -258,10 +258,29 @@ export async function shoppingRoutes(app: FastifyInstance) {
}
}
+ // Ta bort de köpta (markerade) varorna – de ligger nu i lagret. OMARKERADE
+ // varor blir kvar i listan (man kan handla i flera butiker och radera själv).
await app.db
- .update(schema.shoppingLists)
- .set({ status: "completed", updatedAt: new Date() })
- .where(eq(schema.shoppingLists.id, id));
+ .delete(schema.shoppingListItems)
+ .where(
+ and(
+ eq(schema.shoppingListItems.shoppingListId, id),
+ eq(schema.shoppingListItems.checked, true),
+ ),
+ );
+
+ // Markera hela listan som klar först när den är tömd; annars aktiv för fortsatt handling.
+ const remainingItems = await app.db
+ .select({ id: schema.shoppingListItems.id })
+ .from(schema.shoppingListItems)
+ .where(eq(schema.shoppingListItems.shoppingListId, id));
+ const remaining = remainingItems.length;
+ if (remaining === 0) {
+ await app.db
+ .update(schema.shoppingLists)
+ .set({ status: "completed", updatedAt: new Date() })
+ .where(eq(schema.shoppingLists.id, id));
+ }
await emitEvent(app.db, {
type: "SHOPPING_COMPLETED",
@@ -270,7 +289,7 @@ export async function shoppingRoutes(app: FastifyInstance) {
householdId: list.householdId,
correlationId: req.correlationId,
});
- return { ok: true, itemsAddedToInventory: added };
+ return { ok: true, itemsAddedToInventory: added, remaining };
});
}
diff --git a/apps/mobile/src/app/recipe/[id].tsx b/apps/mobile/src/app/recipe/[id].tsx
index cbcacaa..654be7b 100644
--- a/apps/mobile/src/app/recipe/[id].tsx
+++ b/apps/mobile/src/app/recipe/[id].tsx
@@ -203,7 +203,6 @@ export default function RecipeScreen() {
})}
/>
)}
- {recipe.verificationStatus === "editorial" && }
{recipe.description ?? recipe.descriptionSv}
{recipe.creatorDisplayName && Skapat av {recipe.creatorDisplayName}}
diff --git a/apps/mobile/src/app/recipes.tsx b/apps/mobile/src/app/recipes.tsx
index d608c0c..cda583c 100644
--- a/apps/mobile/src/app/recipes.tsx
+++ b/apps/mobile/src/app/recipes.tsx
@@ -15,7 +15,6 @@ import {
Screen,
Small,
Spacer,
- Tag,
} from "@/components/ui";
import { spacing } from "@/lib/theme";
@@ -164,10 +163,7 @@ export default function BrowseRecipesScreen() {
onPress={() => router.push(`/recipe/${r.id}`)}
style={{ gap: spacing.xs }}
>
-
- {r.title ?? r.titleSv}
- {r.verificationStatus === "editorial" && }
-
+ {r.title ?? r.titleSv}
{[
r.totalTimeMinutes != null ? `${r.totalTimeMinutes} min` : null,
diff --git a/apps/mobile/src/app/shopping.tsx b/apps/mobile/src/app/shopping.tsx
index 9601f85..94e335c 100644
--- a/apps/mobile/src/app/shopping.tsx
+++ b/apps/mobile/src/app/shopping.tsx
@@ -111,6 +111,20 @@ export default function ShoppingScreen() {
Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error")),
});
+ const remove = useMutation({
+ mutationFn: (itemId: string) =>
+ api(`/v1/shopping-lists/${listId}/items/${itemId}`, { method: "DELETE" }),
+ onSuccess: invalidate,
+ onError: (err) =>
+ Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error")),
+ });
+
+ const confirmRemove = (item: ShoppingItem) =>
+ Alert.alert(item.displayName, "Ta bort varan från listan?", [
+ { text: t("common.cancel"), style: "cancel" },
+ { text: "Ta bort", style: "destructive", onPress: () => remove.mutate(item.id) },
+ ]);
+
const complete = useMutation({
mutationFn: () =>
api(`/v1/shopping-lists/${listId}/complete`, {
@@ -160,8 +174,11 @@ export default function ShoppingScreen() {
{sectionLabel(section)}
{items.map((item) => (
- toggle.mutate(item)}>
-
+
+ toggle.mutate(item)}>
{item.checked ? "☑" : "☐"}
@@ -176,15 +193,23 @@ export default function ShoppingScreen() {
{item.displayName} · {formatQuantity(item.quantity, item.unit)}
- {item.estimatedPriceMinor != null && (
-
- {t("shopping.estimated", {
- amount: formatMinor(item.estimatedPriceMinor, list.data.currency),
- })}
-
- )}
-
-
+
+ {item.estimatedPriceMinor != null && (
+
+ {t("shopping.estimated", {
+ amount: formatMinor(item.estimatedPriceMinor, list.data.currency),
+ })}
+
+ )}
+ {/* Radera en vara man ångrat (utan att köpa den). */}
+ confirmRemove(item)}
+ hitSlop={8}
+ style={{ paddingHorizontal: spacing.sm }}
+ >
+ ✕
+
+
))}
))}