From 728363fa71e15f2fa8efc9915e63a393bd63412a Mon Sep 17 00:00:00 2001 From: DanielS Date: Fri, 3 Jul 2026 00:52:22 +0200 Subject: [PATCH] feat: hide excluded products and auto-deselect conflicts in wizard --- shop/components/order-wizard.tsx | 62 ++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index 21d3042..45ba805 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -296,10 +296,40 @@ export function OrderWizard({ // Helper: update product selection for a category (resets modules) function selectProduct(catId: string, productId: string) { - setSelections(prev => ({ - ...prev, - [catId]: { productId, moduleIds: [] }, - })) + setSelections(prev => { + const next = { + ...prev, + [catId]: { productId, moduleIds: [] }, + } + + // Automatically deselect now conflicting products in other categories + const selectedIds = Object.entries(next) + .map(([, s]) => s.productId) + .filter((id): id is string => !!id) + + categories.forEach(c => { + if (c.id === catId) return + const sel = next[c.id] + if (!sel?.productId) return + + const otherSelectedProductIds = selectedIds.filter(id => id !== sel.productId) + const prod = products.find(p => p.id === sel.productId) + + const isExcluded = prod && ( + otherSelectedProductIds.some(otherId => { + const otherProd = products.find(p => p.id === otherId) + return otherProd?.exclusions?.includes(prod.id) + }) || + prod.exclusions?.some(exId => otherSelectedProductIds.includes(exId)) + ) + + if (isExcluded) { + next[c.id] = { productId: null, moduleIds: [] } + } + }) + + return next + }) } // Helper: toggle module for a category's selected product @@ -709,12 +739,32 @@ export function OrderWizard({ {categories.map((cat, idx) => { - // Filter products based on display flags show_in_kauf / show_in_abo + const otherSelectedProductIds = Object.entries(selections) + .filter(([cId]) => cId !== cat.id) + .map(([, s]) => s.productId) + .filter((id): id is string => !!id) + + // Filter products based on display flags and mutual exclusions const catProducts = products.filter(p => { if (p.category_id !== cat.id) return false - return selectedBillingInterval === 'one_time' + + const matchesInterval = selectedBillingInterval === 'one_time' ? p.show_in_kauf !== false : p.show_in_abo !== false + if (!matchesInterval) return false + + // Check if p is excluded by any other selected product + const isExcludedByOthers = otherSelectedProductIds.some(otherId => { + const otherProd = products.find(prod => prod.id === otherId) + return otherProd?.exclusions?.includes(p.id) + }) + if (isExcludedByOthers) return false + + // Check if p excludes any other selected product + const excludesOthers = p.exclusions?.some(exId => otherSelectedProductIds.includes(exId)) + if (excludesOthers) return false + + return true }) const sel = selections[cat.id] const selectedProduct = catProducts.find(p => p.id === sel?.productId) ?? null