From 86e69fc457008f125f532574729642b41ecb8aa6 Mon Sep 17 00:00:00 2001 From: Scrum4Me Agent <30029041+madhura68@users.noreply.github.com> Date: Wed, 6 May 2026 02:27:12 +0200 Subject: [PATCH] feat(ideas): multi-select secundaire producten + badges in IdeaDetailLayout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Voegt checkbox-lijst toe voor extra producten (exclusief primaire) in de Idee-tab, geïntegreerd in bestaande save/reset flow via updateSecondaryProductsAction. Toont secundaire product-badges in de detail-header. Bevat ook schema/dto/action-dependencies (IdeaProduct junction, secondary_products in IdeaDto). Co-Authored-By: Claude Sonnet 4.6 --- components/ideas/idea-detail-layout.tsx | 60 +++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/components/ideas/idea-detail-layout.tsx b/components/ideas/idea-detail-layout.tsx index 4b962d9..e8e3916 100644 --- a/components/ideas/idea-detail-layout.tsx +++ b/components/ideas/idea-detail-layout.tsx @@ -20,7 +20,7 @@ import { getIdeaStatusBadge } from '@/lib/idea-status-colors' import type { IdeaStatusApi } from '@/lib/idea-status' import { isIdeaEditable } from '@/lib/idea-status' import type { IdeaDto } from '@/lib/idea-dto' -import { updateIdeaAction, archiveIdeaAction } from '@/actions/ideas' +import { updateIdeaAction, archiveIdeaAction, updateSecondaryProductsAction } from '@/actions/ideas' import { IdeaRowActions } from '@/components/ideas/idea-row-actions' import { IdeaMdEditor } from '@/components/ideas/idea-md-editor' import { IdeaPbiLinkCard } from '@/components/ideas/idea-pbi-link-card' @@ -163,6 +163,18 @@ export function IdeaDetailLayout({ geen product )} + {idea.secondary_products.length > 0 && ( +
+ {idea.secondary_products.map((sp) => ( + + {sp.product.name} + + ))} +
+ )} @@ -214,6 +226,7 @@ export function IdeaDetailLayout({ products={products} isDemo={isDemo} pending={pending} + secondaryProducts={idea.secondary_products} /> )} {tab === 'grill' && ( @@ -250,9 +263,10 @@ interface FormProps { products: ProductOption[] isDemo: boolean pending: boolean + secondaryProducts: IdeaDto['secondary_products'] } -function IdeaFormSection({ idea, products, isDemo, pending }: FormProps) { +function IdeaFormSection({ idea, products, isDemo, pending, secondaryProducts }: FormProps) { const router = useRouter() const editable = !isDemo && @@ -260,12 +274,20 @@ function IdeaFormSection({ idea, products, isDemo, pending }: FormProps) { const [title, setTitle] = useState(idea.title) const [description, setDescription] = useState(idea.description ?? '') const [productId, setProductId] = useState(idea.product_id ?? '') + const [selectedSecondary, setSelectedSecondary] = useState( + secondaryProducts.map((sp) => sp.product_id), + ) const [submitting, startSubmit] = useTransition() + const secondaryDirty = + JSON.stringify([...selectedSecondary].sort()) !== + JSON.stringify(secondaryProducts.map((sp) => sp.product_id).sort()) + const dirty = title !== idea.title || description !== (idea.description ?? '') || - productId !== (idea.product_id ?? '') + productId !== (idea.product_id ?? '') || + secondaryDirty function save() { startSubmit(async () => { @@ -278,6 +300,13 @@ function IdeaFormSection({ idea, products, isDemo, pending }: FormProps) { toast.error(r.error) return } + if (secondaryDirty) { + const r2 = await updateSecondaryProductsAction(idea.id, selectedSecondary) + if ('error' in r2) { + toast.error(r2.error) + return + } + } toast.success('Opgeslagen') router.refresh() }) @@ -320,6 +349,30 @@ function IdeaFormSection({ idea, products, isDemo, pending }: FormProps) { ))} + {products.filter((p) => p.id !== productId).length > 0 && ( +
+ +
+ {products + .filter((p) => p.id !== productId) + .map((p) => ( + + ))} +
+
+ )} {!editable && (

@@ -337,6 +390,7 @@ function IdeaFormSection({ idea, products, isDemo, pending }: FormProps) { setTitle(idea.title) setDescription(idea.description ?? '') setProductId(idea.product_id ?? '') + setSelectedSecondary(secondaryProducts.map((sp) => sp.product_id)) }} > Reset