From 1ec164cd7b9c62275b713ca2a5ff70b50a040a1c Mon Sep 17 00:00:00 2001 From: DanielS Date: Fri, 1 May 2026 02:29:00 +0200 Subject: [PATCH] feat: add optional categories - admins can mark categories as optional in the order wizard --- shop/components/admin/category-dialog.tsx | 26 +++++++++++++++++++ shop/components/admin/category-list.tsx | 11 +++++++- shop/components/order-wizard.tsx | 20 +++++++++----- shop/lib/types.ts | 1 + ...01002700_add_is_required_to_categories.sql | 4 +++ 5 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 shop/supabase/migrations/20260501002700_add_is_required_to_categories.sql diff --git a/shop/components/admin/category-dialog.tsx b/shop/components/admin/category-dialog.tsx index 74deda1..145c4c1 100644 --- a/shop/components/admin/category-dialog.tsx +++ b/shop/components/admin/category-dialog.tsx @@ -23,6 +23,7 @@ import { } from '@/components/ui/form' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' +import { Checkbox } from '@/components/ui/checkbox' import { createCategory, updateCategory } from '@/lib/actions/products' import { Category } from '@/lib/types' import { @@ -40,6 +41,7 @@ const categorySchema = z.object({ description: z.string().optional(), icon: z.string().default('Package'), sort_order: z.coerce.number().int().min(0).default(0), + is_required: z.boolean().default(true), }) type CategoryFormValues = z.infer @@ -60,6 +62,7 @@ export function CategoryDialog({ description: category?.description || '', icon: category?.icon || 'Package', sort_order: category?.sort_order ?? 0, + is_required: category?.is_required ?? true, }, }) @@ -178,6 +181,29 @@ export function CategoryDialog({ )} /> + ( + + + + +
+ + Pflichtauswahl im Bestellvorgang + +

+ Wenn aktiv, muss der Kunde aus dieser Kategorie einen Artikel wählen. + Wenn deaktiviert, ist die Kategorie optional. +

+
+
+ )} + /> diff --git a/shop/components/admin/category-list.tsx b/shop/components/admin/category-list.tsx index 5f27d9c..06ed28d 100644 --- a/shop/components/admin/category-list.tsx +++ b/shop/components/admin/category-list.tsx @@ -12,6 +12,7 @@ import { import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Edit2, Trash2, Cloud, Utensils, HardDrive, Package, ArrowUpDown } from 'lucide-react' import { Button } from '@/components/ui/button' +import { Badge } from '@/components/ui/badge' import { deleteCategory } from '@/lib/actions/products' import { useState } from 'react' import { CategoryDialog } from './category-dialog' @@ -55,6 +56,7 @@ export function CategoryList({ initialCategories }: { initialCategories: Categor Reihenfolge + Typ Aktionen @@ -73,6 +75,13 @@ export function CategoryList({ initialCategories }: { initialCategories: Categor {category.sort_order} + + {category.is_required ? ( + Pflicht + ) : ( + Optional + )} +
@@ -94,7 +103,7 @@ export function CategoryList({ initialCategories }: { initialCategories: Categor ))} {categories.length === 0 && ( - + Keine Kategorien gefunden. diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index 3146084..a2b84f5 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -88,9 +88,9 @@ export function OrderWizard({ return init }) - // All categories must have a product selected + // Only REQUIRED categories must have a product selected const allCategoriesFilled = useMemo( - () => categories.every(cat => !!selections[cat.id]?.productId), + () => categories.filter(cat => cat.is_required).every(cat => !!selections[cat.id]?.productId), [categories, selections] ) @@ -234,10 +234,14 @@ export function OrderWizard({ Ausgewählt - ) : ( + ) : cat.is_required ? ( Pflichtfeld + ) : ( + + Optional + )}
@@ -353,8 +357,12 @@ export function OrderWizard({ const prod = products.find(p => p.id === sel?.productId) if (!prod) return (
- - {cat.name}: nicht gewählt + {cat.is_required ? ( + + ) : ( + + )} + {cat.name}: {cat.is_required ? 'nicht gewählt' : 'nicht gewählt (optional)'}
) return ( @@ -392,7 +400,7 @@ export function OrderWizard({ {!allCategoriesFilled && (

- Bitte aus jeder Kategorie einen Artikel wählen. + Bitte aus jeder Pflichtkategorie einen Artikel wählen.

)} diff --git a/shop/lib/types.ts b/shop/lib/types.ts index 2617863..b5acaae 100644 --- a/shop/lib/types.ts +++ b/shop/lib/types.ts @@ -17,6 +17,7 @@ export type Category = { description?: string | null; icon?: string | null; sort_order: number; + is_required: boolean; created_at: string; }; diff --git a/shop/supabase/migrations/20260501002700_add_is_required_to_categories.sql b/shop/supabase/migrations/20260501002700_add_is_required_to_categories.sql new file mode 100644 index 0000000..d5b9aac --- /dev/null +++ b/shop/supabase/migrations/20260501002700_add_is_required_to_categories.sql @@ -0,0 +1,4 @@ +-- Add is_required column to categories +-- When true (default), a product must be selected from this category in the order wizard +-- When false, the category is optional and can be skipped +ALTER TABLE public.categories ADD COLUMN IF NOT EXISTS is_required BOOLEAN DEFAULT true NOT NULL;