"use client"; import { updateCommissionRequestStatus } from "@/actions/commissions/requests/updateCommissionRequestStatus"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Kanban, KanbanBoard, KanbanColumn, KanbanItem, KanbanOverlay } from "@/components/ui/kanban"; import { BOARD_COLUMNS, type BoardColumnId, canonicalStatusForColumn, } from "@/lib/commissions/kanban"; import Link from "next/link"; import * as React from "react"; type BoardItem = { id: string; createdAt: string; status: string; customerName: string; customerEmail: string; message: string; typeName: string | null; optionName: string | null; extrasCount: number; filesCount: number; }; type ColumnsState = Record; import type { UniqueIdentifier } from "@dnd-kit/core"; type KanbanValue = Record; function isColumnsState(v: KanbanValue): v is ColumnsState { return ( Array.isArray(v.intake) && Array.isArray(v.inProgress) && Array.isArray(v.completed) ); } function asColumnsState(v: KanbanValue): ColumnsState { if (!isColumnsState(v)) { // Defensive: if something ever changes upstream, keep UI stable return { intake: [], inProgress: [], completed: [] }; } return v; } function findItemColumn(columns: ColumnsState, itemId: string): BoardColumnId | null { for (const col of Object.keys(columns) as BoardColumnId[]) { if (columns[col].some((x) => x.id === itemId)) return col; } return null; } function diffMovedItem(prev: ColumnsState, next: ColumnsState) { const prevLoc = new Map(); const nextLoc = new Map(); for (const c of Object.keys(prev) as BoardColumnId[]) { for (const i of prev[c]) { prevLoc.set(i.id, c); } } for (const c of Object.keys(next) as BoardColumnId[]) { for (const i of next[c]) { nextLoc.set(i.id, c); } } for (const [id, from] of prevLoc.entries()) { const to = nextLoc.get(id); if (to && to !== from) return { id, from, to }; } return null; } export default function CommissionsKanbanClient({ initialColumns, }: { initialColumns: ColumnsState; }) { const [columns, setColumns] = React.useState(initialColumns); const prevRef = React.useRef(columns); React.useEffect(() => { prevRef.current = columns; }, [columns]); async function persistMove(moved: { id: string; to: BoardColumnId }, snapshotBefore: ColumnsState) { const status = canonicalStatusForColumn(moved.to); try { await updateCommissionRequestStatus({ id: moved.id, status }); // optional: you could also update the item’s status in local state here // but revalidatePath + eventual refresh will keep it consistent anyway. setColumns((cur) => { const col = findItemColumn(cur, moved.id); if (!col) return cur; return { ...cur, [col]: cur[col].map((x) => (x.id === moved.id ? { ...x, status } : x)), }; }); } catch { // Revert optimistic state if update fails setColumns(snapshotBefore); } } function onValueChange(next: KanbanValue) { const nextColumns = asColumnsState(next); const prev = prevRef.current; setColumns(nextColumns); const moved = diffMovedItem(prev, nextColumns); if (!moved) return; void persistMove({ id: moved.id, to: moved.to }, prev); } return (

Commissions Board

Drag requests between columns to update their status.

item.id} > {(Object.keys(columns) as BoardColumnId[]).map((colId) => { const col = BOARD_COLUMNS[colId]; const items = columns[colId]; return (
{col.title} {items.length}
{items.map((item) => (
{item.customerName} — #{item.id.slice(0, 6)}
{item.typeName ?? "No type"}{item.optionName ? ` · ${item.optionName}` : ""}
{item.status}

{item.message}

Files: {item.filesCount} · Extras: {item.extrasCount}
))}
); })}
); }