import { h, ref } from 'vue' import type { ColumnDef } from '@tanstack/vue-table' import { ArrowUpDown, Film, Package, ChevronDown } from 'lucide-vue-next' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Checkbox } from '@/components/ui/checkbox' import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover' import TaskStatusBadge from '@/components/asset/TaskStatusBadge.vue' import EditableTaskStatus from '@/components/task/EditableTaskStatus.vue' import { type Task } from '@/services/task' import { TaskStatus } from '@/services/asset' function formatDate(dateString: string): string { const date = new Date(dateString) return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', }) } interface ColumnCallbacks { onBulkStatusChange?: (status: TaskStatus) => void onStatusUpdated?: (taskId: number, newStatus: TaskStatus) => void getSelectedCount?: () => number } export const createColumns = (callbacks?: ColumnCallbacks): ColumnDef[] => { // Create ref outside column definitions so it persists across renders const isPopoverOpen = ref(false) return [ // Select column { id: 'select', header: ({ table }) => h(Checkbox, { modelValue: table.getIsAllPageRowsSelected(), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(value === true), ariaLabel: 'Select all', }), cell: ({ row }) => h(Checkbox, { modelValue: row.getIsSelected(), 'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(value === true), ariaLabel: 'Select row', onClick: (e: Event) => e.stopPropagation(), }), enableSorting: false, enableHiding: false, size: 40, }, { accessorKey: 'name', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Task Name', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { return h('div', { class: 'font-medium' }, row.getValue('name')) }, }, { accessorKey: 'project_name', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Project', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const projectName = row.getValue('project_name') as string | undefined return h('div', { class: 'text-sm' }, projectName || '-') }, }, { accessorKey: 'task_type', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Type', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const taskType = row.getValue('task_type') as string return h( Badge, { variant: 'outline', class: 'capitalize' }, () => taskType.replace(/_/g, ' ') ) }, }, { accessorKey: 'status', header: ({ column }) => { const selectedCount = callbacks?.getSelectedCount?.() || 0 if (selectedCount > 0) { return h('div', { class: 'flex items-center gap-2' }, [ h( Button, { variant: 'ghost', size: 'sm', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Status', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ), h('div', { onClick: (e: Event) => e.stopPropagation() }, [ h(Popover, { open: isPopoverOpen.value, 'onUpdate:open': (value: boolean) => { isPopoverOpen.value = value } }, { default: () => [ h(PopoverTrigger, {}, { default: () => h( Button, { variant: 'outline', size: 'sm', class: 'h-8 w-8 p-0', }, () => h(ChevronDown, { class: 'h-4 w-4' }) ), }), h(PopoverContent, { class: 'w-48 p-2', align: 'start' }, { default: () => { return h('div', { class: 'flex flex-col gap-1' }, [ h('div', { class: 'px-2 py-1.5 text-sm font-semibold' }, `Change Status`), ...Object.values(TaskStatus).map((status) => h( Button, { variant: 'ghost', size: 'sm', class: 'justify-start', onClick: () => { callbacks?.onBulkStatusChange?.(status) isPopoverOpen.value = false }, }, () => h(TaskStatusBadge, { status, class: 'w-full' }) ) ), ]) }, }), ], }), ]), ]) } return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Status', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const task = row.original return h(EditableTaskStatus, { taskId: task.id, status: row.getValue('status') as TaskStatus, projectId: task.project_id, onStatusUpdated: (taskId: number, newStatus: TaskStatus) => { callbacks?.onStatusUpdated?.(taskId, newStatus) }, }) }, }, { id: 'context', header: 'Context', cell: ({ row }) => { const task = row.original const isShot = !!task.shot_id const icon = isShot ? Film : Package const label = isShot ? 'Shot' : 'Asset' return h('div', { class: 'flex items-center gap-2' }, [ h(icon, { class: 'h-4 w-4 text-muted-foreground' }), h('span', { class: 'text-sm text-muted-foreground' }, label), ]) }, }, { id: 'shot_asset', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Shot/Asset', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, accessorFn: (row) => row.shot_name || row.asset_name || '', cell: ({ row }) => { const task = row.original const name = task.shot_name || task.asset_name || '-' return h('div', { class: 'font-medium' }, name) }, }, { accessorKey: 'episode_name', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Episode', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const episodeName = row.getValue('episode_name') as string | undefined return h('div', { class: 'text-sm' }, episodeName || '-') }, }, { accessorKey: 'assigned_user_name', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Assignee', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const assigneeName = row.getValue('assigned_user_name') as string | undefined return h('div', { class: 'text-sm' }, assigneeName || 'Unassigned') }, }, { accessorKey: 'deadline', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Deadline', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { const deadline = row.getValue('deadline') as string | undefined if (!deadline) return h('div', { class: 'text-sm text-muted-foreground' }, '-') const date = new Date(deadline) const now = new Date() const isOverdue = date < now const isUrgent = date.getTime() - now.getTime() < 3 * 24 * 60 * 60 * 1000 // 3 days return h( 'div', { class: [ 'text-sm', isOverdue ? 'text-destructive font-medium' : isUrgent ? 'text-orange-600 font-medium' : '', ], }, formatDate(deadline) ) }, }, { accessorKey: 'created_at', header: ({ column }) => { return h( Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Created', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })] ) }, cell: ({ row }) => { return h('div', { class: 'text-sm text-muted-foreground' }, formatDate(row.getValue('created_at'))) }, }, ] }