feat(category): add resets_others option
All checks were successful
Staging Build / build (push) Successful in 2m46s

This commit is contained in:
DanielS
2026-07-09 17:27:16 +02:00
parent 567d1f226b
commit 6b35917a06
5 changed files with 124 additions and 42 deletions

View File

@@ -91,7 +91,8 @@ export function WysiwygAdminClient({
free_items_limit: 0, free_items_limit: 0,
preselect: false, preselect: false,
show_in_kauf: mode === 'purchase', show_in_kauf: mode === 'purchase',
show_in_abo: mode === 'subscription' show_in_abo: mode === 'subscription',
resets_others: false
}) })
setCategories([...categories, newCat]) setCategories([...categories, newCat])
} catch (e) { } catch (e) {
@@ -182,7 +183,7 @@ export function WysiwygAdminClient({
/> />
{/* Kategorie Attribute (Toggles) */} {/* Kategorie Attribute (Toggles) */}
<div className="flex items-center gap-6 mt-3 text-xs text-slate-400"> <div className="flex flex-wrap items-center gap-6 mt-3 text-xs text-slate-400">
<label className="flex items-center gap-2 cursor-pointer select-none"> <label className="flex items-center gap-2 cursor-pointer select-none">
<input <input
type="checkbox" type="checkbox"
@@ -196,11 +197,49 @@ export function WysiwygAdminClient({
<input <input
type="checkbox" type="checkbox"
checked={cat.allow_multiselect} checked={cat.allow_multiselect}
onChange={(e) => handleCategoryToggle(cat.id, { allow_multiselect: e.target.checked })} onChange={(e) => {
const checked = e.target.checked
handleCategoryToggle(cat.id, {
allow_multiselect: checked,
...(checked ? { preselect: false } : {})
})
}}
className="rounded border-white/10 bg-white/5 text-primary focus:ring-0 focus:ring-offset-0" className="rounded border-white/10 bg-white/5 text-primary focus:ring-0 focus:ring-offset-0"
/> />
<span>Mehrfachauswahl</span> <span>Mehrfachauswahl</span>
</label> </label>
{!cat.allow_multiselect && (
<label className="flex items-center gap-2 cursor-pointer select-none">
<input
type="checkbox"
checked={cat.preselect}
onChange={(e) => handleCategoryToggle(cat.id, { preselect: e.target.checked })}
className="rounded border-white/10 bg-white/5 text-primary focus:ring-0 focus:ring-offset-0"
/>
<span>Vorauswahl</span>
</label>
)}
<label className="flex items-center gap-2 cursor-pointer select-none">
<input
type="checkbox"
checked={cat.resets_others}
onChange={(e) => handleCategoryToggle(cat.id, { resets_others: e.target.checked })}
className="rounded border-white/10 bg-white/5 text-primary focus:ring-0 focus:ring-offset-0"
/>
<span>Rest zurücksetzen</span>
</label>
{cat.allow_multiselect && (
<div className="flex items-center gap-2">
<span>Freie Artikel Limit:</span>
<input
type="number"
min={0}
value={cat.free_items_limit}
onChange={(e) => handleCategoryToggle(cat.id, { free_items_limit: parseInt(e.target.value) || 0 })}
className="w-12 rounded border-white/10 bg-white/5 text-white focus:ring-0 focus:ring-offset-0 px-1 py-0.5 text-center"
/>
</div>
)}
</div> </div>
</div> </div>
<button <button

View File

@@ -48,6 +48,7 @@ const categorySchema = z.object({
preselect: z.boolean().default(true), preselect: z.boolean().default(true),
show_in_kauf: z.boolean().default(true), show_in_kauf: z.boolean().default(true),
show_in_abo: z.boolean().default(true), show_in_abo: z.boolean().default(true),
resets_others: z.boolean().default(false),
}) })
type CategoryFormValues = z.infer<typeof categorySchema> type CategoryFormValues = z.infer<typeof categorySchema>
@@ -75,6 +76,7 @@ export function CategoryDialog({
preselect: category?.preselect ?? true, preselect: category?.preselect ?? true,
show_in_kauf: category?.show_in_kauf ?? true, show_in_kauf: category?.show_in_kauf ?? true,
show_in_abo: category?.show_in_abo ?? true, show_in_abo: category?.show_in_abo ?? true,
resets_others: category?.resets_others ?? false,
}, },
}) })
@@ -269,6 +271,29 @@ export function CategoryDialog({
/> />
)} )}
<FormField
control={form.control}
name="resets_others"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-lg border border-slate-200 dark:border-white/10 bg-slate-50 dark:bg-white/5 p-4">
<FormControl>
<Checkbox
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<div className="space-y-1 leading-none">
<FormLabel className="text-slate-900 dark:text-white font-semibold cursor-pointer">
Anderen Kategorien bei Auswahl zurücksetzen
</FormLabel>
<p className="text-xs text-slate-500 dark:text-slate-400">
Wenn aktiv, setzt die Auswahl eines Artikels dieser Kategorie alle anderen Kategorien zurück.
</p>
</div>
</FormItem>
)}
/>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<FormField <FormField
control={form.control} control={form.control}

View File

@@ -379,11 +379,25 @@ export function OrderWizard({
nextProductId = productId nextProductId = productId
} }
const isSelectedNow = cat?.allow_multiselect
? nextProductIds.includes(productId)
: nextProductId === productId
const shouldReset = isSelectedNow && cat?.resets_others
const next = { const next = {
...prev, ...prev,
[catId]: { productId: nextProductId, productIds: nextProductIds, moduleIds: [] }, [catId]: { productId: nextProductId, productIds: nextProductIds, moduleIds: [] },
} }
if (shouldReset) {
// Reset all other categories
categories.forEach(c => {
if (c.id !== catId) {
next[c.id] = { productId: null, productIds: [], moduleIds: [] }
}
})
} else {
// Automatically deselect now conflicting products in other categories // Automatically deselect now conflicting products in other categories
const selectedIds: string[] = [] const selectedIds: string[] = []
Object.values(next).forEach(s => { Object.values(next).forEach(s => {
@@ -432,6 +446,7 @@ export function OrderWizard({
} }
} }
}) })
}
return next return next
}) })

View File

@@ -31,6 +31,7 @@ export type Category = {
preselect: boolean preselect: boolean
show_in_kauf?: boolean show_in_kauf?: boolean
show_in_abo?: boolean show_in_abo?: boolean
resets_others: boolean
created_at: string created_at: string
} }

View File

@@ -0,0 +1,2 @@
-- Add resets_others column to categories table
ALTER TABLE public.categories ADD COLUMN IF NOT EXISTS resets_others BOOLEAN DEFAULT false NOT NULL;