'use client' import { useState } from 'react' import { toast } from 'sonner' import { Plus, Search, Pencil, Trash2, Clock, Calendar, Building2, Tag, } from 'lucide-react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Label } from '@/components/ui/label' type DepartmentType = 'PERSONAL_LINES' | 'COMMERCIAL_LINES' | 'CLAIMS' | 'BENEFITS' | 'OTHER' type TaskTiming = 'PRE_RENEWAL' | 'POST_RENEWAL' type TaskPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' type TaskLevel = 'POLICY' | 'RENEWAL_GROUP' | 'BOTH' | 'CLIENT' interface Designation { id: string name: string color: string } interface TaskTemplate { id: string name: string description: string | null department: DepartmentType timing: TaskTiming daysOffset: number defaultPriority: TaskPriority taskGroup: string | null isActive: boolean displayOrder: number | null level: TaskLevel designationId: string | null policyTypeFilter: string | null designation: Designation | null _count: { tasks: number } } interface TaskTemplateManagerProps { initialTemplates: TaskTemplate[] designations: Designation[] } const DEPARTMENTS: { value: DepartmentType; label: string }[] = [ { value: 'PERSONAL_LINES', label: 'Personal Lines' }, { value: 'COMMERCIAL_LINES', label: 'Commercial Lines' }, { value: 'CLAIMS', label: 'Claims' }, { value: 'BENEFITS', label: 'Benefits' }, { value: 'OTHER', label: 'Other' }, ] const TIMINGS: { value: TaskTiming; label: string }[] = [ { value: 'PRE_RENEWAL', label: 'Pre-Renewal' }, { value: 'POST_RENEWAL', label: 'Post-Renewal' }, ] const PRIORITIES: { value: TaskPriority; label: string; color: string }[] = [ { value: 'LOW', label: 'Low', color: 'bg-slate-100 text-slate-700' }, { value: 'MEDIUM', label: 'Medium', color: 'bg-blue-100 text-blue-700' }, { value: 'HIGH', label: 'High', color: 'bg-orange-100 text-orange-700' }, { value: 'URGENT', label: 'Urgent', color: 'bg-red-100 text-red-700' }, ] const LEVELS: { value: TaskLevel; label: string }[] = [ { value: 'CLIENT', label: 'Client' }, { value: 'BOTH', label: 'Policy/Group' }, { value: 'RENEWAL_GROUP', label: 'Group only' }, { value: 'POLICY', label: 'Policy only' }, ] const POLICY_TYPES = [ 'Workers Compensation', 'Package', 'General Liability', 'Business Auto', 'Umbrella(C)', 'Commercial Property', 'Inland Marine (C)', 'Cyber Liability', 'BOP', 'Crime', 'Pollution Liability', 'Errors & Ommissions Professional Liability', 'Employment Practices Liability', 'Directors & Officers', 'Motor Truck Cargo', 'ERISA', ] const emptyTemplate = { name: '', description: '', department: 'CLAIMS' as DepartmentType, timing: 'PRE_RENEWAL' as TaskTiming, daysOffset: -90, defaultPriority: 'MEDIUM' as TaskPriority, taskGroup: '', isActive: true, displayOrder: null as number | null, level: 'BOTH' as TaskLevel, designationId: null as string | null, policyTypeFilter: null as string | null, } export function TaskTemplateManager({ initialTemplates, designations, }: TaskTemplateManagerProps) { const [templates, setTemplates] = useState(initialTemplates) const [searchQuery, setSearchQuery] = useState('') const [departmentFilter, setDepartmentFilter] = useState('all') const [timingFilter, setTimingFilter] = useState('all') const [designationFilter, setDesignationFilter] = useState('all') const [isDialogOpen, setIsDialogOpen] = useState(false) const [editingTemplate, setEditingTemplate] = useState(null) const [formData, setFormData] = useState(emptyTemplate) const [isSubmitting, setIsSubmitting] = useState(false) const [deleteConfirmId, setDeleteConfirmId] = useState(null) const filteredTemplates = templates.filter((template) => { const matchesSearch = template.name.toLowerCase().includes(searchQuery.toLowerCase()) || template.description?.toLowerCase().includes(searchQuery.toLowerCase()) const matchesDepartment = departmentFilter === 'all' || template.department === departmentFilter const matchesTiming = timingFilter === 'all' || template.timing === timingFilter const matchesDesignation = designationFilter === 'all' || (designationFilter === 'none' && !template.designationId) || template.designationId === designationFilter return matchesSearch && matchesDepartment && matchesTiming && matchesDesignation }) const handleOpenCreate = () => { setEditingTemplate(null) setFormData(emptyTemplate) setIsDialogOpen(true) } const handleOpenEdit = (template: TaskTemplate) => { setEditingTemplate(template) setFormData({ name: template.name, description: template.description || '', department: template.department, timing: template.timing, daysOffset: template.daysOffset, defaultPriority: template.defaultPriority, taskGroup: template.taskGroup || '', isActive: template.isActive, displayOrder: template.displayOrder, level: template.level, designationId: template.designationId, policyTypeFilter: template.policyTypeFilter, }) setIsDialogOpen(true) } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setIsSubmitting(true) try { const url = editingTemplate ? `/api/templates/${editingTemplate.id}` : '/api/templates' const method = editingTemplate ? 'PATCH' : 'POST' const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...formData, description: formData.description || null, displayOrder: formData.displayOrder || null, designationId: formData.designationId || null, policyTypeFilter: formData.policyTypeFilter || null, }), }) if (!response.ok) { throw new Error('Failed to save template') } const savedTemplate = await response.json() if (editingTemplate) { setTemplates((prev) => prev.map((t) => t.id === savedTemplate.id ? { ...savedTemplate, _count: t._count, designation: designations.find(d => d.id === savedTemplate.designationId) || null } : t ) ) toast.success('Template updated successfully') } else { setTemplates((prev) => [ ...prev, { ...savedTemplate, _count: { tasks: 0 }, designation: designations.find(d => d.id === savedTemplate.designationId) || null }, ]) toast.success('Template created successfully') } setIsDialogOpen(false) } catch (error) { toast.error('Failed to save template') } finally { setIsSubmitting(false) } } const handleDelete = async (id: string) => { try { const response = await fetch(`/api/templates/${id}`, { method: 'DELETE', }) if (!response.ok) { throw new Error('Failed to delete template') } setTemplates((prev) => prev.filter((t) => t.id !== id)) toast.success('Template deleted successfully') } catch (error) { toast.error('Failed to delete template') } finally { setDeleteConfirmId(null) } } const formatDaysOffset = (timing: TaskTiming, daysOffset: number) => { const absDays = Math.abs(daysOffset) if (timing === 'PRE_RENEWAL') { return `${absDays} days before renewal` } return `${absDays} days after renewal` } const getPriorityBadge = (priority: TaskPriority) => { const config = PRIORITIES.find((p) => p.value === priority) return ( {config?.label} ) } return (
{/* Filters and Actions */}
setSearchQuery(e.target.value)} className="pl-9" />
{editingTemplate ? 'Edit Template' : 'Create Template'} {editingTemplate ? 'Update the task template details.' : 'Create a new task template for renewal workflows.'}
setFormData((prev) => ({ ...prev, name: e.target.value })) } placeholder="e.g., Claim Review" required />
setFormData((prev) => ({ ...prev, description: e.target.value, })) } placeholder="Optional description" />
setFormData((prev) => ({ ...prev, taskGroup: e.target.value })) } placeholder="e.g. Renewal, Claims, Audit (optional)" />
setFormData((prev) => ({ ...prev, daysOffset: parseInt(e.target.value) || 0, })) } />

Negative for pre-renewal, positive for post-renewal

Only generate this task for policies of this type. Leave blank for all types.

setFormData((prev) => ({ ...prev, displayOrder: e.target.value ? parseInt(e.target.value) : null, })) } placeholder="Optional" />
setFormData((prev) => ({ ...prev, isActive: e.target.checked, })) } className="h-4 w-4 rounded border-gray-300" />
{/* Templates Table */} Templates ({filteredTemplates.length}) {filteredTemplates.length === 0 ? (
No templates found. Create one to get started.
) : ( Name Department Timing Level Policy Type Designation Priority Status Tasks Actions {filteredTemplates.map((template) => (
{template.name}
{template.description && (
{template.description}
)}
{DEPARTMENTS.find((d) => d.value === template.department) ?.label || template.department}
{formatDaysOffset(template.timing, template.daysOffset)}
{LEVELS.find((l) => l.value === template.level)?.label || template.level} {template.policyTypeFilter ? ( {template.policyTypeFilter} ) : ( Any )} {template.designation ? ( {template.designation.name} ) : ( All )} {getPriorityBadge(template.defaultPriority)} {template.isActive ? 'Active' : 'Inactive'} {template._count.tasks}
{deleteConfirmId === template.id ? (
) : ( )}
))}
)}
) }