- app/(app)/products/[id]/docs/[folder]/page.tsx: server-route die folder-segment valideert tegen ProductDocFolder-enum (404 anders), docs sorteert op slug ASC, en de tabel + breadcrumb + "Nieuwe doc"-link rendert. New-doc-link wordt in T-1070 functioneel via dialog. - components/product-docs/product-docs-folder-list.tsx: server-tabel (slug · title · status-badge · updated_at met nl-NL DateTimeFormat). - components/product-docs/product-doc-status-badge.tsx: MD3-tokens (bg-status-done/20, bg-status-blocked/20, bg-muted) per status. Unknown statussen fallbacken naar 'muted'. - "Nieuwe doc"-knop conditioneel verborgen bij disabled folder; banner zelf komt in T-1071. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
// Folder-listing tabel. Server-component (geen interactiviteit in v1 —
|
|
// sorteren komt later via TanStack-table indien nodig). Toont
|
|
// slug · title · status-badge · updated_at.
|
|
|
|
import Link from 'next/link'
|
|
import { FileText } from 'lucide-react'
|
|
|
|
import { debugProps } from '@/lib/debug'
|
|
import { ProductDocStatusBadge } from './product-doc-status-badge'
|
|
|
|
export interface ProductDocListRow {
|
|
id: string
|
|
slug: string
|
|
title: string
|
|
status: string
|
|
updated_at: Date
|
|
}
|
|
|
|
interface Props {
|
|
productId: string
|
|
folderApi: string
|
|
docs: ProductDocListRow[]
|
|
}
|
|
|
|
const dateFmt = new Intl.DateTimeFormat('nl-NL', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
})
|
|
|
|
export function ProductDocsFolderList({ productId, folderApi, docs }: Props) {
|
|
if (docs.length === 0) {
|
|
return (
|
|
<div
|
|
className="text-sm text-muted-foreground p-6 text-center"
|
|
{...debugProps(
|
|
'product-docs-folder-list--empty',
|
|
'ProductDocsFolderList',
|
|
'components/product-docs/product-docs-folder-list.tsx',
|
|
)}
|
|
>
|
|
Nog geen docs in deze folder.
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const docsUrl = `/products/${productId}/docs/${folderApi}`
|
|
return (
|
|
<div
|
|
className="rounded-lg border border-border bg-surface-container-low overflow-hidden"
|
|
{...debugProps(
|
|
'product-docs-folder-list',
|
|
'ProductDocsFolderList',
|
|
'components/product-docs/product-docs-folder-list.tsx',
|
|
)}
|
|
>
|
|
<table className="w-full text-sm">
|
|
<thead className="border-b border-border bg-surface-container">
|
|
<tr className="text-xs text-muted-foreground">
|
|
<th className="text-left px-3 py-2 font-medium">Slug</th>
|
|
<th className="text-left px-3 py-2 font-medium">Titel</th>
|
|
<th className="text-left px-3 py-2 font-medium">Status</th>
|
|
<th className="text-right px-3 py-2 font-medium">Bijgewerkt</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{docs.map((doc) => (
|
|
<tr
|
|
key={doc.id}
|
|
className="border-t border-border first:border-t-0 hover:bg-surface-container/60"
|
|
>
|
|
<td className="px-3 py-2 font-mono text-xs">
|
|
<Link
|
|
href={`${docsUrl}/${doc.slug}`}
|
|
className="text-primary hover:underline inline-flex items-center gap-1.5"
|
|
>
|
|
<FileText className="size-3 shrink-0" />
|
|
{doc.slug}
|
|
</Link>
|
|
</td>
|
|
<td className="px-3 py-2 truncate max-w-[420px]">{doc.title}</td>
|
|
<td className="px-3 py-2">
|
|
<ProductDocStatusBadge status={doc.status} />
|
|
</td>
|
|
<td className="px-3 py-2 text-right text-xs text-muted-foreground tabular-nums">
|
|
{dateFmt.format(doc.updated_at)}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)
|
|
}
|