- app/(app)/products/[id]/docs/[folder]/[slug]/page.tsx: server-route
die doc laadt (scope-checked via productAccessFilter), frontmatter
parseert, en op basis van ?edit=1 viewer of editor toont. Fallback
voor unparseable frontmatter toont errors + raw content in <pre>.
- product-doc-viewer.tsx: server-component met frontmatter-kop
(title + status-badge + audience/applies_to/last_updated meta) en
body via <Markdown> (XSS-safe).
- product-doc-editor.tsx: client-wrapper rond MarkdownDocEditor met
parseProductDocMd validator + updateProductDocAction + cancelHref.
- delete-product-doc-button.tsx: AlertDialog confirm + delete-action
+ DemoTooltip + redirect-na-success. Disabled in demo.
- Edit-knop conditioneel verborgen bij disabled folder (T-1071 voegt
banner toe); delete blijft altijd zichtbaar voor cleanup.
- Button met `render={<Link/>}` ipv asChild (CLAUDE.md hardstop
base-ui pattern).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
'use client'
|
|
|
|
// Confirm-dialog + delete-action voor een Product Doc. DemoTooltip-wrapped
|
|
// (laag 3 van de drie-laagse demo-policy). Na succesvolle delete: redirect
|
|
// naar de folder-page.
|
|
|
|
import { useState, useTransition } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { Trash2 } from 'lucide-react'
|
|
import { toast } from 'sonner'
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
AlertDialogTrigger,
|
|
} from '@/components/ui/alert-dialog'
|
|
import { DemoTooltip } from '@/components/shared/demo-tooltip'
|
|
import { debugProps } from '@/lib/debug'
|
|
import { deleteProductDocAction } from '@/actions/product-docs'
|
|
|
|
interface Props {
|
|
docId: string
|
|
docTitle: string
|
|
/** URL waar we naar redirecten na succes. */
|
|
redirectHref: string
|
|
isDemo: boolean
|
|
}
|
|
|
|
export function DeleteProductDocButton({
|
|
docId,
|
|
docTitle,
|
|
redirectHref,
|
|
isDemo,
|
|
}: Props) {
|
|
const router = useRouter()
|
|
const [open, setOpen] = useState(false)
|
|
const [submitting, startSubmit] = useTransition()
|
|
|
|
function confirmDelete() {
|
|
startSubmit(async () => {
|
|
const r = await deleteProductDocAction(docId)
|
|
if ('error' in r) {
|
|
toast.error(r.error)
|
|
return
|
|
}
|
|
toast.success('Doc verwijderd')
|
|
setOpen(false)
|
|
router.push(redirectHref)
|
|
router.refresh()
|
|
})
|
|
}
|
|
|
|
return (
|
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
<DemoTooltip show={isDemo}>
|
|
<AlertDialogTrigger
|
|
render={
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
disabled={isDemo}
|
|
{...debugProps(
|
|
'delete-product-doc-button',
|
|
'DeleteProductDocButton',
|
|
'components/product-docs/delete-product-doc-button.tsx',
|
|
)}
|
|
>
|
|
<Trash2 className="size-3.5 mr-1" />
|
|
Verwijderen
|
|
</Button>
|
|
}
|
|
/>
|
|
</DemoTooltip>
|
|
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Doc verwijderen?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
“{docTitle}” wordt permanent verwijderd. Een audit-log-rij
|
|
blijft bewaard, maar de inhoud is daarna niet meer leesbaar.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel disabled={submitting}>Annuleer</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
onClick={confirmDelete}
|
|
disabled={submitting}
|
|
variant="destructive"
|
|
data-debug-id="delete-product-doc-button__confirm"
|
|
>
|
|
Ja, verwijder
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
)
|
|
}
|