WORKFLOW-APP/components/LinkedDirectorsList.tsx

136 lines
4.8 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import LinkEntityModal from "@/components/LinkEntityModal";
import { text } from "@/lib/format";
import type { YsterbaardDirector } from "@/lib/types";
interface JunctionEntry {
id: string;
director_id: string;
director: YsterbaardDirector;
}
interface Props {
companyId: string;
companyName: string;
initial: JunctionEntry[];
}
export default function LinkedDirectorsList({ companyId, companyName, initial }: Props) {
const router = useRouter();
const [showLinkModal, setShowLinkModal] = useState(false);
const [unlinking, setUnlinking] = useState<string | null>(null);
const [linked, setLinked] = useState<JunctionEntry[]>(initial);
const [error, setError] = useState<string | null>(null);
const alreadyLinkedIds = linked.map((j) => j.director_id);
async function handleUnlink(junctionId: string, directorName: string) {
if (!confirm(`Remove link to "${directorName}"? The director will remain in PocketBase.`)) return;
setUnlinking(junctionId);
setError(null);
try {
const res = await fetch("/api/pb/records/link", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
action: "unlink",
company: companyId,
director: linked.find((j) => j.id === junctionId)?.director_id,
}),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error ?? "Unlink failed");
}
setLinked((prev) => prev.filter((j) => j.id !== junctionId));
window.location.reload();
} catch (e: unknown) {
setError(e instanceof Error ? e.message : "Unlink failed");
} finally {
setUnlinking(null);
}
}
return (
<>
<div className="flex flex-col gap-3 min-w-0">
<div className="flex items-baseline justify-between gap-3 flex-wrap">
<h2 className="text-xl font-semibold text-fg">Linked directors</h2>
<div className="flex items-center gap-3">
<p className="text-sm text-muted">
{linked.length} director{linked.length === 1 ? "" : "s"}
</p>
<button
onClick={() => setShowLinkModal(true)}
className="px-3 py-1.5 rounded-md bg-accent text-accent-on text-xs font-bold hover:bg-accent-hover transition-colors"
>
+ Link director
</button>
</div>
</div>
{error && (
<div className="px-4 py-2.5 rounded-lg bg-red-500/10 border border-red-500/30 text-red-400 text-sm">
{error}
</div>
)}
{linked.length === 0 ? (
<div className="bg-surface border border-border rounded-lg p-10 text-center text-muted">
No directors linked to this company.
</div>
) : (
<div className="flex flex-col gap-3">
{linked.map((j) => {
const d = j.director;
const name = `${text(d.first_names)} ${text(d.surname)}`.trim();
return (
<div
key={j.id}
className="bg-surface border border-border rounded-lg p-6 md:p-8 flex flex-col gap-3 hover:bg-surface-warm transition-colors"
>
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
<div className="min-w-0">
<p className="text-2xl font-bold text-fg leading-tight">{name || "—"}</p>
<p className="text-base text-muted font-mono mt-1">
ID {text(d.id_no)}
</p>
</div>
<button
onClick={() => handleUnlink(j.id, name)}
disabled={unlinking !== null}
title="Unlink director"
className="text-xs px-2.5 py-1 rounded border border-red-500/30 bg-red-500/10 text-red-400 hover:bg-red-500/20 transition-colors disabled:opacity-40 shrink-0"
>
{unlinking === j.id ? "…" : "Unlink"}
</button>
</div>
<Link
href={`/directors/${d.id}`}
className="text-xs font-semibold text-accent hover:underline self-start"
>
View director profile →
</Link>
</div>
);
})}
</div>
)}
</div>
<LinkEntityModal
mode="link-company"
parentId={companyId}
parentName={companyName}
alreadyLinkedIds={alreadyLinkedIds}
open={showLinkModal}
onClose={() => setShowLinkModal(false)}
onLinked={() => router.refresh()}
/>
</>
);
}