import type { ColumnDef } from '@tanstack/react-table'; import { Eye, Lock, Unlock } from 'lucide-react'; import { RowActions } from '@/components/row-actions'; import { Badge } from '@/components/ui/badge'; import { MONTH_NAMES } from '@/lib/constants'; import { formatCurrency } from '@/lib/utils'; export type PayrollPeriod = { id: number; year: number; month: number; status: 'open' | 'closed'; closed_at: string | null; created_at: string; payrolls_count: number; paid_count: number; cancelled_count: number; payrolls_sum_total_amount: number | null; payrolls_sum_bonus_amount: number | null; payrolls_sum_deduction_amount: number | null; }; function formatPeriod(period: PayrollPeriod): string { return `${MONTH_NAMES[period.month]} ${period.year}`; } function getStatusBadge(status: string) { const statusConfig: Record = { open: { label: 'Terbuka', className: 'bg-green-100 text-green-800 hover:bg-green-100', }, closed: { label: 'Ditutup', className: 'bg-gray-100 text-gray-800 hover:bg-gray-100', }, }; const config = statusConfig[status] ?? statusConfig.open; return ( {config.label} ); } type CreateColumnsParams = { showUrl: (id: number) => string; handleClose: (period: PayrollPeriod) => void; handleReopen: (period: PayrollPeriod) => void; }; export function createPayrollPeriodColumns( params: CreateColumnsParams, ): ColumnDef[] { const { showUrl, handleClose, handleReopen } = params; return [ { accessorKey: 'year', header: () => Periode, cell: ({ row }) => ( {formatPeriod(row.original)} ), }, { accessorKey: 'payrolls_count', header: () => Jumlah Karyawan, cell: ({ row }) => ( {row.getValue('payrolls_count') as number} ), }, { accessorKey: 'payrolls_sum_total_amount', header: () => Total Gaji, cell: ({ row }) => ( {formatCurrency( (row.getValue('payrolls_sum_total_amount') as number) ?? 0, )} ), }, { accessorKey: 'payrolls_sum_bonus_amount', header: () => Bonus, cell: ({ row }) => { const value = (row.getValue('payrolls_sum_bonus_amount') as number) ?? 0; return ( 0 ? 'font-medium text-green-600' : 'text-muted-foreground' } > {value > 0 ? '+ ' : ''} {formatCurrency(value)} ); }, }, { accessorKey: 'payrolls_sum_deduction_amount', header: () => Potongan, cell: ({ row }) => { const value = (row.getValue('payrolls_sum_deduction_amount') as number) ?? 0; return ( 0 ? 'font-medium text-red-600' : 'text-muted-foreground' } > {value > 0 ? '- ' : ''} {formatCurrency(value)} ); }, }, { id: 'payment_status', header: () => Status Bayar, cell: ({ row }) => { const period = row.original; const paid = period.paid_count ?? 0; const cancelled = period.cancelled_count ?? 0; const total = period.payrolls_count ?? 0; const unpaid = total - paid - cancelled; return (
{paid > 0 && ( {paid} dibayar )} {unpaid > 0 && ( {unpaid} menunggu )} {cancelled > 0 && ( {cancelled} dibatalkan )}
); }, }, { accessorKey: 'status', header: () => Status, cell: ({ row }) => ( {getStatusBadge(row.getValue('status') as string)} ), }, { id: 'actions', header: () => Aksi, meta: { className: 'w-[100px] text-center', headerClassName: 'w-[100px] text-center', }, cell: ({ row }) => { const period = row.original; return ( , href: showUrl(period.id), }, { label: 'Tutup Periode', icon: ( ), show: period.status === 'open', onClick: () => handleClose(period), }, { label: 'Buka Periode', icon: ( ), show: period.status === 'closed', onClick: () => handleReopen(period), }, ]} /> ); }, }, ]; }