diff --git a/ondeck/src/components/clients/client-detail.tsx b/ondeck/src/components/clients/client-detail.tsx index 94bbacb..833775d 100644 --- a/ondeck/src/components/clients/client-detail.tsx +++ b/ondeck/src/components/clients/client-detail.tsx @@ -14,7 +14,7 @@ import { SelectValue, } from '@/components/ui/select' import { Textarea } from '@/components/ui/textarea' -import { Building2, MapPin, Phone, Mail, FileText, CheckSquare, CalendarRange, Users, X, Plus, UserCheck, StickyNote, Pencil, Trash2, ChevronDown, ChevronUp } from 'lucide-react' +import { Building2, MapPin, Phone, Mail, FileText, CheckSquare, CalendarRange, Users, X, Plus, UserCheck, StickyNote, Pencil, Trash2, ChevronDown, ChevronUp, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react' import { Combobox } from '@/components/ui/combobox' import { formatDate, formatRenewalDate } from '@/lib/utils' import { PolicyGroupManager } from '@/components/clients/policy-group-manager' @@ -53,6 +53,9 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic const [parentOptions, setParentOptions] = useState<{id:string;name:string}[]>([]) const [parentLinking, setParentLinking] = useState(false) const [showArchivedTasks, setShowArchivedTasks] = useState(false) + const [taskSort, setTaskSort] = useState<'date' | 'priority'>('date') + const [taskSortDir, setTaskSortDir] = useState<'asc' | 'desc'>('asc') + const [showCompleted, setShowCompleted] = useState(false) const [notesExpanded, setNotesExpanded] = useState(!!(client.notes)) const [additionalServiceOpen, setAdditionalServiceOpen] = useState(false) const [sessionUserId, setSessionUserId] = useState('') @@ -362,7 +365,7 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic - Tasks ({tasks.length}) + Tasks ({tasks.filter((t: any) => t.status !== 'COMPLETED' && t.status !== 'NA' && t.status !== 'CANCELLED').length}) @@ -475,44 +478,136 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic -
+ {/* Sort / filter header */} +
+ {/* Sort buttons */} + {([['date', 'Date'], ['priority', 'Priority']] as const).map(([key, label]) => ( + + ))} + + + + {/* Show completed toggle */} + + + + -
- {tasks.length === 0 ? ( - - - No tasks found - - - ) : ( - tasks.map((task: any) => ( - - -
-
-

{task.title}

-

{task.description}

-
-
- {task.status} -

- Due: {formatDate(task.dueDate)} -

-
-
+ + {(() => { + const isTerminal = (s: string) => s === 'COMPLETED' || s === 'NA' || s === 'CANCELLED' + const priorityOrder: Record = { HIGH: 0, MEDIUM: 1, LOW: 2 } + const filtered = showCompleted ? tasks : tasks.filter((t: any) => !isTerminal(t.status)) + const sorted = [...filtered].sort((a: any, b: any) => { + let cmp = 0 + if (taskSort === 'date') { + cmp = new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime() + } else { + cmp = (priorityOrder[a.priority] ?? 9) - (priorityOrder[b.priority] ?? 9) + } + return taskSortDir === 'asc' ? cmp : -cmp + }) + return sorted.length === 0 ? ( + + + No tasks found - )) - )} + ) : ( + sorted.map((task: any) => { + const completed = isTerminal(task.status) + const overdue = new Date(task.dueDate) < new Date() && !completed + return ( + + +
+
+
+

+ {task.title} +

+ + {task.status.replace('_', ' ')} + + + {task.priority} + +
+ {task.description && ( +

{task.description}

+ )} + {task.assignments?.length > 0 && ( +

+ Assigned to: {task.assignments.map((a: any) => a.user.displayName || a.user.email).join(', ')} +

+ )} +
+
+

+ Due: {formatDate(task.dueDate)} +

+
+
+
+
+ ) + }) + ) + })()}