134 lines
5.5 KiB
TypeScript
134 lines
5.5 KiB
TypeScript
import { ColumnDef } from '@tanstack/react-table';
|
|
import { Payroll } from '@/types';
|
|
import { DataTableColumnHeader } from '@/components/data-table-column-header';
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Switch } from '@/components/ui/switch';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { PencilRuler, Trash2 } from 'lucide-react';
|
|
|
|
interface ColumnProps {
|
|
onEdit: (payroll: Payroll) => void;
|
|
onDelete: (payroll: Payroll) => void;
|
|
onTogglePaid: (id: number) => void;
|
|
}
|
|
|
|
export const getColumns = ({ onEdit, onDelete, onTogglePaid }: ColumnProps): ColumnDef<Payroll>[] => [
|
|
{
|
|
accessorKey: "user.name",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Pegawai" />
|
|
),
|
|
cell: ({ row }) => row.original.user?.name || '-',
|
|
meta: { title: "Pegawai" },
|
|
},
|
|
{
|
|
accessorKey: "period_month",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Periode" />
|
|
),
|
|
cell: ({ row }) => row.original.period_month_formatted,
|
|
meta: { title: "Periode" },
|
|
},
|
|
{
|
|
accessorKey: "total_salary",
|
|
header: ({ column }) => (
|
|
<DataTableColumnHeader column={column} title="Rincian Gaji" />
|
|
),
|
|
cell: ({ row }) => {
|
|
const payroll = row.original;
|
|
return (
|
|
<div className="flex flex-col gap-1 py-1 min-w-[200px]">
|
|
<div className="flex justify-between text-[10px] text-muted-foreground uppercase tracking-tighter">
|
|
<span>Gaji Pokok</span>
|
|
<span className="font-medium text-foreground">{payroll.base_salary_formatted}</span>
|
|
</div>
|
|
|
|
{payroll.adjustments && payroll.adjustments.length > 0 && (
|
|
<div className="space-y-0.5">
|
|
{payroll.adjustments.map((adj, idx) => (
|
|
<div key={idx} className="flex justify-between text-[9px] text-muted-foreground italic">
|
|
<span className="line-clamp-1 max-w-[120px]">{adj.description}</span>
|
|
<span className={adj.type === 'bonus' ? 'text-green-600' : 'text-red-500'}>
|
|
{adj.type === 'bonus' ? '+' : '-'}{adj.amount_formatted}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-between text-xs font-bold pt-1 border-t border-dashed mt-1">
|
|
<span className="uppercase text-[10px]">Gaji Bersih</span>
|
|
<span className="text-primary">{payroll.total_salary_formatted}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
meta: { title: "Total Gaji" },
|
|
},
|
|
{
|
|
accessorKey: "is_paid",
|
|
header: "Status",
|
|
cell: ({ row }) => {
|
|
const payroll = row.original;
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<Switch
|
|
checked={payroll.is_paid}
|
|
onCheckedChange={() => onTogglePaid(payroll.id)}
|
|
/>
|
|
<Badge
|
|
variant={payroll.is_paid ? 'default' : 'outline'}
|
|
className={payroll.is_paid ? 'bg-green-500/10 text-green-600 border-green-200 dark:bg-green-500/20 dark:text-green-400 dark:border-green-900' : ''}
|
|
>
|
|
{payroll.is_paid ? 'Dibayar' : 'Pending'}
|
|
</Badge>
|
|
</div>
|
|
);
|
|
},
|
|
meta: { title: "Status" },
|
|
},
|
|
{
|
|
id: "actions",
|
|
header: "Aksi",
|
|
cell: ({ row }) => {
|
|
const payroll = row.original;
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className='text-yellow-600'
|
|
onClick={() => onEdit(payroll)}
|
|
>
|
|
<PencilRuler className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Ubah / Sesuaikan</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className='text-red-600'
|
|
onClick={() => onDelete(payroll)}
|
|
>
|
|
<Trash2 className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Hapus</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</div>
|
|
);
|
|
},
|
|
meta: { title: "Aksi" },
|
|
},
|
|
];
|