Scrum4Me/components/ideas/idea-pbi-link-card.tsx
Madhura68 b25c3c5482 fix(m12): drop bogus /backlog#pbi-{code} route on PBI-link
Three places linked to \`/products/[id]/backlog#pbi-{pbi_code}\` after
materializing or in the planned-state link-card. That route doesn't
exist (product backlog lives at \`/products/[id]\` directly), and the
hash was double-prefixed (\`#pbi-PBI-32\`) since pbi_code already starts
with PBI-. Result: 404 for the user.

Fix: route to \`/products/[id]\` without anchor. The new PBI is the most
recent so visible near the top. Per-PBI anchor scrolling is a follow-up
once we add \`id="pbi-{id}"\` attributes to pbi-list rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:06:24 +02:00

85 lines
2.6 KiB
TypeScript

'use client'
// IdeaPbiLinkCard — toont de gekoppelde PBI bij PLANNED. Bij "stale link"
// (status===PLANNED maar pbi_id===null, want PBI elders verwijderd via
// de SetNull FK) tonen we de Re-link-banner.
import { useTransition } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { ExternalLink, Link2Off } from 'lucide-react'
import { toast } from 'sonner'
import { Button } from '@/components/ui/button'
import { relinkIdeaPlanAction } from '@/actions/ideas'
import type { IdeaDto } from '@/lib/idea-dto'
interface Props {
idea: IdeaDto
isDemo: boolean
}
export function IdeaPbiLinkCard({ idea, isDemo }: Props) {
const router = useRouter()
const [pending, startTransition] = useTransition()
if (idea.status !== 'planned') return null
if (idea.pbi && idea.product_id) {
return (
<div className="rounded-md border border-status-done/30 bg-status-done/10 p-4 flex items-center gap-3">
<div className="flex-1">
<p className="text-xs uppercase tracking-wide text-status-done font-medium">
Gepland
</p>
<p className="text-sm">
Gematerialiseerd als{' '}
<Link
href={`/products/${idea.product_id}`}
className="font-medium text-status-done hover:underline inline-flex items-center gap-1"
>
{idea.pbi.code} {idea.pbi.title}
<ExternalLink className="size-3" />
</Link>
</p>
</div>
</div>
)
}
// Stale link — pbi_id === null maar status nog PLANNED.
function handleRelink() {
if (isDemo) return
startTransition(async () => {
const r = await relinkIdeaPlanAction(idea.id)
if ('error' in r) {
toast.error(r.error)
return
}
toast.success('Idee terug naar PLAN_READY — open de Plan-tab.')
router.refresh()
})
}
return (
<div className="rounded-md border border-status-blocked/30 bg-status-blocked/10 p-4 space-y-2">
<div className="flex items-center gap-2">
<Link2Off className="size-4 text-status-blocked" />
<p className="text-sm font-medium text-status-blocked">
De gekoppelde PBI bestaat niet meer
</p>
</div>
<p className="text-sm text-muted-foreground">
Klik om dit idee terug naar PLAN_READY te zetten en opnieuw te materialiseren.
</p>
<Button
size="sm"
variant="outline"
onClick={handleRelink}
disabled={isDemo || pending}
>
Plan opnieuw beschikbaar maken
</Button>
</div>
)
}