dress/resources/js/pages/admin/finance/payroll/index.tsx

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',
},
],
};