import type { ColumnDef, FilterFn } from '@tanstack/vue-table' import { ArrowUpDown, Pencil, Trash2 } from '@lucide/vue' import { h } from 'vue' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Switch } from '@/components/ui/switch' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip' export interface Plan { id: string name: string description: string | null price: number limits: Record | null is_active: boolean | number } const nameFilter: FilterFn = (row, _columnId, filterValue) => { const search = (filterValue as string).toLowerCase() const name = (row.original.name as string).toLowerCase() return name.includes(search) } const booleanFilter: FilterFn = (row, columnId, filterValue) => { if (!filterValue || filterValue === '') return true const raw = row.original[columnId as keyof Plan] const cellValue = raw === true || raw === 1 || raw === '1' const filterBool = filterValue === 'true' return cellValue === filterBool } export function getColumns(callbacks: { onEdit: (plan: Plan) => void onDelete: (plan: Plan) => void onToggleStatus: (plan: Plan, value: boolean) => void }): ColumnDef[] { return [ { id: 'name_search', accessorFn: row => row.name, header: ({ column }) => { return h(Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Nama', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })]) }, cell: ({ row }) => h('div', { class: 'font-medium' }, row.original.name), filterFn: nameFilter, enableHiding: false, }, { accessorKey: 'price', header: ({ column }) => { return h(Button, { variant: 'ghost', onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), }, () => ['Harga', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })]) }, cell: ({ row }) => { const val = row.original.price const formatted = val.toLocaleString('id-ID') return h('div', { class: 'flex items-center gap-1 text-sm' }, [ h('span', { class: 'text-muted-foreground' }, 'Rp'), h('span', { class: 'font-medium' }, formatted), ]) }, }, { accessorKey: 'description', header: 'Deskripsi', cell: ({ row }) => { const desc = row.getValue('description') as string | null return h('div', { class: 'text-muted-foreground truncate max-w-[300px]' }, desc ?? '-') }, }, { accessorKey: 'is_active', header: 'Status', filterFn: booleanFilter, cell: ({ row }) => { const raw = row.getValue('is_active') const isActive = raw === true || raw === 1 || raw === '1' const plan = row.original return h('div', { class: 'flex items-center gap-2' }, [ h(Switch, { modelValue: isActive, 'onUpdate:modelValue': (val: boolean) => callbacks.onToggleStatus(plan, val), }), h(Badge, { variant: 'outline', class: isActive ? 'border-emerald-500 text-emerald-600 bg-emerald-50' : 'border-red-500 text-red-600 bg-red-50', }, () => isActive ? 'Aktif' : 'Nonaktif'), ]) }, }, { id: 'actions', header: ' ', size: 0, minSize: 0, enableHiding: false, cell: ({ row }) => { const plan = row.original return h(TooltipProvider, null, () => h('div', { class: 'flex items-center gap-1' }, [ h(Tooltip, null, () => [ h(TooltipTrigger, { asChild: true }, () => h(Button, { variant: 'ghost', size: 'icon', class: 'h-8 w-8 text-yellow-500', onClick: () => callbacks.onEdit(plan), }, () => h(Pencil, { class: 'h-4 w-4' }) ) ), h(TooltipContent, null, () => 'Edit'), ]), h(Tooltip, null, () => [ h(TooltipTrigger, { asChild: true }, () => h(Button, { variant: 'ghost', size: 'icon', class: 'h-8 w-8 text-destructive', onClick: () => callbacks.onDelete(plan), }, () => h(Trash2, { class: 'h-4 w-4' }) ) ), h(TooltipContent, null, () => 'Hapus'), ]), ]) ) }, }, ] }