ui: /ideas list page + IdeaList table + row-actions skeleton (M12 T-507)
app/(app)/ideas/page.tsx (server-component): - user_id-only fetch (no productAccessFilter — Idee is privé) - products fetched with productAccessFilter for filter-dropdown + create-form components/ideas/idea-list.tsx (client-component): - Search by title, product-dropdown filter, status multi-chip filter - Inline create form with title/description/product (optional) - Native shadcn Table + status badge via getIdeaStatusBadge (T-509) - Row click navigates to /ideas/[id] - Sonner toasts for success/error; router.refresh() after mutations - DemoTooltip + disabled on Nieuw + Archive - Empty-state + filtered-empty messaging components/ideas/idea-row-actions.tsx (placeholder for T-508): - "Open" navigation + "Archive" button only — Grill / Make Plan / Materialiseer come in T-508 with full disabled-rules Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
006d803a16
commit
2eb0f33068
3 changed files with 403 additions and 0 deletions
48
app/(app)/ideas/page.tsx
Normal file
48
app/(app)/ideas/page.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { cookies } from 'next/headers'
|
||||
import { getIronSession } from 'iron-session'
|
||||
|
||||
import { SessionData, sessionOptions } from '@/lib/session'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { productAccessFilter } from '@/lib/product-access'
|
||||
import { ideaToDto } from '@/lib/idea-dto'
|
||||
import { IdeaList } from '@/components/ideas/idea-list'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function IdeasPage() {
|
||||
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
|
||||
|
||||
// M12: idee is strikt user_id-only (geen productAccessFilter — Q8).
|
||||
const ideas = await prisma.idea.findMany({
|
||||
where: { user_id: session.userId, archived: false },
|
||||
orderBy: { created_at: 'desc' },
|
||||
include: { product: { select: { id: true, name: true, repo_url: true } } },
|
||||
take: 200,
|
||||
})
|
||||
|
||||
// Productenlijst voor de filter-dropdown + voor "Nieuw idee"-form.
|
||||
// Producten zijn product-scoped (kan team-shared zijn) — productAccessFilter
|
||||
// is hier dus wél juist.
|
||||
const products = await prisma.product.findMany({
|
||||
where: { ...productAccessFilter(session.userId), archived: false },
|
||||
orderBy: { name: 'asc' },
|
||||
select: { id: true, name: true, repo_url: true },
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-5xl mx-auto w-full">
|
||||
<header className="mb-6 flex items-baseline justify-between">
|
||||
<h1 className="text-xl font-medium text-foreground">Ideeën</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Lichtgewicht voorstellen die je via Grill Me en Make Plan tot een PBI laat groeien.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<IdeaList
|
||||
ideas={ideas.map((i) => ideaToDto(i))}
|
||||
products={products}
|
||||
isDemo={session.isDemo ?? false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue