import * as React from "react"; import { Plus, Trash2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Separator } from "@/components/ui/separator"; /** * AddColumnModal — WealthX DS (L4 Dialog) * * Create or edit a Pipeline stage (column). Supports: * - Column title (optionally locked for system stages) * - Time-based alert thresholds (warning days, priority days) * - Task template list (up to 20 tasks) * * Data source: `listColumns()` → `Stage` in `loan-crm.ts` */ const MAX_TASKS = 20; // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export interface ColumnTask { /** Temp numeric ID for new tasks; persisted string ID for existing ones. */ id: string | number; name: string; } export interface AddColumnEditData { id?: string; name: string; orderIndex?: number; warningDays?: number | null; priorityDays?: number | null; tasks?: ColumnTask[]; /** When true the title field is read-only (system/fixed stages). */ isTitleLocked?: boolean; } export interface AddColumnModalProps { open: boolean; onOpenChange: (open: boolean) => void; onSave: (data: AddColumnEditData) => void; /** Pre-populate for edit mode. Omit (or pass null) for create mode. */ editData?: AddColumnEditData | null; loading?: boolean; className?: string; } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- export function AddColumnModal({ open, onOpenChange, onSave, editData, loading = false, className, }: AddColumnModalProps) { const isEdit = !!editData?.id; const nextId = React.useRef(0); const [name, setName] = React.useState(editData?.name ?? ""); const [warningDays, setWarningDays] = React.useState( editData?.warningDays != null ? String(editData.warningDays) : "" ); const [priorityDays, setPriorityDays] = React.useState( editData?.priorityDays != null ? String(editData.priorityDays) : "" ); const [tasks, setTasks] = React.useState(editData?.tasks ?? []); // Sync state when dialog opens or editData changes React.useEffect(() => { if (open) { setName(editData?.name ?? ""); setWarningDays( editData?.warningDays != null ? String(editData.warningDays) : "" ); setPriorityDays( editData?.priorityDays != null ? String(editData.priorityDays) : "" ); setTasks(editData?.tasks ?? []); } }, [open, editData]); // Validation const wDays = warningDays !== "" ? parseInt(warningDays, 10) : null; const pDays = priorityDays !== "" ? parseInt(priorityDays, 10) : null; const daysError = wDays !== null && pDays !== null && wDays >= pDays ? "Warning days must be less than priority days." : null; const taskNames = tasks.map((t) => t.name.trim().toLowerCase()); const hasDuplicateTasks = new Set(taskNames).size !== taskNames.filter(Boolean).length; const isValid = name.trim().length > 0 && !daysError && !hasDuplicateTasks && tasks.every((t) => t.name.trim().length > 0); function addTask() { if (tasks.length >= MAX_TASKS) return; setTasks((prev) => [...prev, { id: nextId.current++, name: "" }]); } function removeTask(id: string | number) { setTasks((prev) => prev.filter((t) => t.id !== id)); } function updateTask( id: string | number, patch: Partial> ) { setTasks((prev) => prev.map((t) => (t.id === id ? { ...t, ...patch } : t))); } function handleSave() { onSave({ id: editData?.id, name: name.trim(), orderIndex: editData?.orderIndex, warningDays: wDays, priorityDays: pDays, tasks, isTitleLocked: editData?.isTitleLocked, }); } return ( {isEdit ? "Edit Column" : "Add New Column"}
{/* Column title */}
setName(e.target.value)} placeholder="e.g. Pre-approval" disabled={editData?.isTitleLocked || loading} /> {editData?.isTitleLocked && (

This column title is locked and cannot be changed.

)}
{/* Time-based alerts */}
Time-based alerts
setWarningDays(e.target.value)} placeholder="e.g. 7" disabled={loading} />
setPriorityDays(e.target.value)} placeholder="e.g. 14" disabled={loading} />
{daysError && (

{daysError}

)}
{/* Task templates */}
Task templates
{tasks.length === 0 && (

No tasks yet. Tasks will be created for each new opportunity added to this column.

)}
{tasks.map((task) => (
updateTask(task.id, { name: e.target.value }) } placeholder="Task name" className="flex-1" disabled={loading} />
))}
{hasDuplicateTasks && (

Task names must be unique.

)}
); }