184 lines
6.5 KiB
TypeScript
184 lines
6.5 KiB
TypeScript
import { DataTable } from '@/components/data-table';
|
|
import { Head } from '@inertiajs/react';
|
|
import { Sparkles, Trash2 } from 'lucide-react';
|
|
|
|
import { DeleteConfirmation } from '@/components/modal/delete-confirmation';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import type { Payroll } from '@/types';
|
|
|
|
import { PayrollCard } from '@/components/cards/payroll-card';
|
|
import { usePermission } from '@/hooks/use-permission';
|
|
import { usePayrollIndex } from './hooks/use-payroll-index';
|
|
import { getColumns } from './partials/columns';
|
|
import { PayrollFormModal } from './partials/payroll-form-modal';
|
|
|
|
export default function PayrollIndex({
|
|
payrolls,
|
|
currentMonthPayrolls,
|
|
}: {
|
|
payrolls: Payroll[];
|
|
currentMonthPayrolls: Payroll[];
|
|
}) {
|
|
const { hasPermission } = usePermission();
|
|
const {
|
|
isFormOpen,
|
|
selectedPayroll,
|
|
isDeleteDialogOpen,
|
|
isBulkDeleteDialogOpen,
|
|
payrollToDelete,
|
|
rowsToDelete,
|
|
rowSelection,
|
|
isGenerating,
|
|
setRowSelection,
|
|
setRowsToDelete,
|
|
setIsDeleteDialogOpen,
|
|
setIsBulkDeleteDialogOpen,
|
|
onGenerate,
|
|
onEdit,
|
|
onDelete,
|
|
confirmDelete,
|
|
confirmBulkDelete,
|
|
onTogglePaid,
|
|
closeForm,
|
|
} = usePayrollIndex();
|
|
|
|
const columns = getColumns({ onEdit, onDelete, onTogglePaid }).filter(
|
|
(col) =>
|
|
col.id !== 'actions' ||
|
|
hasPermission('Edit:PayrollAdjustment') ||
|
|
hasPermission('Delete:Payroll'),
|
|
);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6 p-6">
|
|
<Head title="Penggajian" />
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight">
|
|
Penggajian
|
|
</h1>
|
|
</div>
|
|
{hasPermission('Generate:Payroll') && (
|
|
<Button
|
|
onClick={onGenerate}
|
|
disabled={isGenerating}
|
|
className="gap-2"
|
|
>
|
|
{isGenerating ? (
|
|
<Sparkles className="size-4 animate-spin" />
|
|
) : (
|
|
<Sparkles className="size-4" />
|
|
)}
|
|
Generate
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
{currentMonthPayrolls.length > 0 && (
|
|
<div className="flex flex-col gap-3">
|
|
<div className="grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
|
|
{currentMonthPayrolls.map((payroll) => (
|
|
<PayrollCard
|
|
key={payroll.id}
|
|
payroll={payroll}
|
|
onClick={() => {
|
|
if (
|
|
hasPermission('Edit:PayrollAdjustment')
|
|
) {
|
|
onEdit(payroll);
|
|
}
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<PayrollFormModal
|
|
isOpen={isFormOpen}
|
|
onClose={closeForm}
|
|
payroll={selectedPayroll}
|
|
/>
|
|
|
|
<Card className="overflow-hidden border-none bg-card/50 p-5 shadow-lg backdrop-blur-sm">
|
|
<CardContent className="p-0">
|
|
<DataTable
|
|
columns={columns}
|
|
data={payrolls}
|
|
showSelection={hasPermission('DeleteAny:Payroll')}
|
|
rowSelection={rowSelection}
|
|
onRowSelectionChange={setRowSelection}
|
|
filters={[
|
|
{
|
|
columnId: 'is_paid',
|
|
title: 'Status',
|
|
options: [
|
|
{ label: 'Dibayar', value: 'true' },
|
|
{ label: 'Pending', value: 'false' },
|
|
],
|
|
},
|
|
]}
|
|
bulkActions={
|
|
hasPermission('DeleteAny:Payroll')
|
|
? [
|
|
{
|
|
label: 'Hapus Terpilih',
|
|
onClick: (rows) => {
|
|
setRowsToDelete(rows);
|
|
setIsBulkDeleteDialogOpen(true);
|
|
},
|
|
icon: Trash2,
|
|
variant: 'destructive',
|
|
},
|
|
]
|
|
: []
|
|
}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Single Delete Confirmation */}
|
|
<DeleteConfirmation
|
|
isOpen={isDeleteDialogOpen}
|
|
onOpenChange={setIsDeleteDialogOpen}
|
|
title="Hapus penggajian?"
|
|
description={
|
|
<>
|
|
Tindakan ini tidak dapat dibatalkan. Penggajian{' '}
|
|
<strong>
|
|
{payrollToDelete?.period_month_formatted}
|
|
</strong>{' '}
|
|
akan dihapus secara permanen dan stok akan dikembalikan.
|
|
</>
|
|
}
|
|
onDelete={confirmDelete}
|
|
/>
|
|
|
|
{/* Bulk Delete Confirmation */}
|
|
<DeleteConfirmation
|
|
isOpen={isBulkDeleteDialogOpen}
|
|
onOpenChange={setIsBulkDeleteDialogOpen}
|
|
title={`Hapus ${rowsToDelete.length} penggajian?`}
|
|
description={
|
|
<>
|
|
Tindakan ini tidak dapat dibatalkan.{' '}
|
|
<strong>{rowsToDelete.length}</strong> item yang
|
|
terpilih akan dihapus secara permanen.
|
|
</>
|
|
}
|
|
onDelete={confirmBulkDelete}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
PayrollIndex.layout = {
|
|
breadcrumbs: [
|
|
{
|
|
title: 'Keuangan',
|
|
},
|
|
],
|
|
};
|