"use client";
import type { ClientView } from "@/lib/client-view";
import { ApproveButton } from "@/components/client/ApproveButton";
import { isClosedTaskStatus, TASK_STATUS_VISUALS } from "@/components/client/TaskStatusIndicator";
import { TASK_STATUS_LABELS, TASK_STATUSES, type TaskStatus } from "@/lib/task-status";
type Task = ClientView["phases"][number]["tasks"][number] & {
phaseTitle: string;
};
const COLUMNS: { id: TaskStatus; label: string }[] = TASK_STATUSES.map((id) => ({
id,
label: TASK_STATUS_LABELS[id],
}));
function TaskCard({ task, token }: { task: Task; token: string }) {
return (
{task.phaseTitle}
{task.title}
{task.description && (
{task.description}
)}
{task.deliverables.length > 0 && (
{task.deliverables.map((d) => (
-
{d.title}
{(d.status === "pending" || d.status === "submitted" || d.approved_at !== null) && (
)}
))}
)}
);
}
export function ClientKanban({ phases, token }: { phases: ClientView["phases"]; token: string }) {
const allTasks: Task[] = phases.flatMap((phase) =>
phase.tasks.map((task) => ({ ...task, phaseTitle: phase.title }))
);
// Derived from the statuses, not a hand-written object: as three fixed keys it
// dropped any task outside them from every column AND every counter, so the
// client silently saw fewer tasks than the project had.
const tasksByStatus = COLUMNS.reduce(
(acc, col) => {
acc[col.id] = allTasks.filter((t) => t.status === col.id);
return acc;
},
{} as Record
);
// "Cancellate" è l'unica colonna che si nasconde da vuota: nella maggior parte
// dei progetti non ce n'è nessuna, e una quinta colonna vuota ruberebbe spazio
// alle quattro che raccontano il lavoro. Si nasconde solo se è vuota, quindi
// nessun task sparisce mai dalla board — era proprio quello il bug di prima.
const visibleColumns = COLUMNS.filter(
(col) => col.id !== "cancelled" || tasksByStatus.cancelled.length > 0
);
return (
4 ? "xl:grid-cols-5" : "xl:grid-cols-4"
}`}
>
{visibleColumns.map((col) => {
// Stessa tinta dell'icona in Timeline: passando da una vista all'altra
// "in corso" e "in revisione" restano riconoscibili senza rileggere.
const v = TASK_STATUS_VISUALS[col.id];
return (
{col.label}
{tasksByStatus[col.id].length}
{tasksByStatus[col.id].map((task) => (
))}
{tasksByStatus[col.id].length === 0 && (
Nessun task
)}
);
})}
);
}