refactor: reorganize imports and improve code formatting in PayrollFormModal component
This commit is contained in:
parent
fb1ad29741
commit
29ca4f8ec4
@ -1,9 +1,3 @@
|
|||||||
import { useForm } from '@inertiajs/react';
|
|
||||||
import { Loader, Plus, Trash2 } from 'lucide-react';
|
|
||||||
import { X, Save } from 'lucide-react';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { NumericFormat } from 'react-number-format';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -11,14 +5,24 @@ import {
|
|||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog"
|
} from '@/components/ui/dialog';
|
||||||
import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from '@/components/ui/empty';
|
import {
|
||||||
import { FieldGroup } from "@/components/ui/field"
|
Empty,
|
||||||
import { Input } from "@/components/ui/input"
|
EmptyDescription,
|
||||||
import { Label } from "@/components/ui/label"
|
EmptyHeader,
|
||||||
|
EmptyTitle,
|
||||||
|
} from '@/components/ui/empty';
|
||||||
|
import { FieldGroup } from '@/components/ui/field';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||||
import payrollRoutes from '@/routes/payroll';
|
import payrollRoutes from '@/routes/payroll';
|
||||||
import type { Payroll } from '@/types';
|
import type { Payroll } from '@/types';
|
||||||
|
import { useForm } from '@inertiajs/react';
|
||||||
|
import { Loader, Plus, Save, Trash2, X } from 'lucide-react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { NumericFormat } from 'react-number-format';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
interface PayrollFormModalProps {
|
interface PayrollFormModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -26,18 +30,28 @@ interface PayrollFormModalProps {
|
|||||||
payroll: Payroll | null;
|
payroll: Payroll | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalProps) {
|
export function PayrollFormModal({
|
||||||
const { data, setData, patch, processing, errors, reset, clearErrors } = useForm({
|
isOpen,
|
||||||
adjustments: [] as { type: 'bonus' | 'deduction', amount: number, description: string }[],
|
onClose,
|
||||||
|
payroll,
|
||||||
|
}: PayrollFormModalProps) {
|
||||||
|
const { data, setData, patch, processing, errors, reset, clearErrors } =
|
||||||
|
useForm({
|
||||||
|
adjustments: [] as {
|
||||||
|
type: 'bonus' | 'deduction';
|
||||||
|
amount: number;
|
||||||
|
description: string;
|
||||||
|
}[],
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (payroll) {
|
if (payroll) {
|
||||||
setData({
|
setData({
|
||||||
adjustments: payroll.adjustments?.map(adj => ({
|
adjustments:
|
||||||
|
payroll.adjustments?.map((adj) => ({
|
||||||
type: adj.type,
|
type: adj.type,
|
||||||
amount: adj.amount,
|
amount: adj.amount,
|
||||||
description: adj.description
|
description: adj.description,
|
||||||
})) || [],
|
})) || [],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -56,7 +70,7 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
const addAdjustment = () => {
|
const addAdjustment = () => {
|
||||||
setData('adjustments', [
|
setData('adjustments', [
|
||||||
...data.adjustments,
|
...data.adjustments,
|
||||||
{ type: 'bonus', amount: 0, description: '' }
|
{ type: 'bonus', amount: 0, description: '' },
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,14 +103,24 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
<Dialog open={isOpen} onOpenChange={(open) => !open && handleClose()}>
|
<Dialog open={isOpen} onOpenChange={(open) => !open && handleClose()}>
|
||||||
<DialogContent className="max-w-2xl">
|
<DialogContent className="max-w-2xl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Penyesuaian Penggajian - {payroll?.user?.name}</DialogTitle>
|
<DialogTitle>
|
||||||
|
Penyesuaian Penggajian - {payroll?.user?.name}
|
||||||
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<form onSubmit={onSubmit}>
|
<form onSubmit={onSubmit}>
|
||||||
<div className="max-h-[60vh] overflow-y-auto px-1 py-2">
|
<div className="max-h-[60vh] overflow-y-auto px-1 py-2">
|
||||||
<FieldGroup>
|
<FieldGroup>
|
||||||
<div className="flex items-center justify-between border-b pb-2 mb-4">
|
<div className="mb-4 flex items-center justify-between border-b pb-2">
|
||||||
<h3 className="text-sm font-medium">Bonus & Potongan</h3>
|
<h3 className="text-sm font-medium">
|
||||||
<Button type="button" variant="outline" size="sm" onClick={addAdjustment} className="gap-2">
|
Bonus & Potongan
|
||||||
|
</h3>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={addAdjustment}
|
||||||
|
className="gap-2"
|
||||||
|
>
|
||||||
<Plus className="size-4" />
|
<Plus className="size-4" />
|
||||||
Tambah
|
Tambah
|
||||||
</Button>
|
</Button>
|
||||||
@ -114,30 +138,61 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{data.adjustments.map((adj, index) => (
|
{data.adjustments.map((adj, index) => (
|
||||||
<div key={index} className="flex gap-3 items-start border-l-2 border-primary/20 pl-4 py-2 mb-4 group relative">
|
<div
|
||||||
<div className="flex flex-col gap-3 flex-1">
|
key={index}
|
||||||
|
className="group relative mb-4 flex items-start gap-3 border-l-2 border-primary/20 py-2 pl-4"
|
||||||
|
>
|
||||||
|
<div className="flex flex-1 flex-col gap-3">
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<Label className="text-[10px] uppercase mb-1">Jenis</Label>
|
<Label className="mb-1 text-[10px] uppercase">
|
||||||
|
Jenis
|
||||||
|
</Label>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={adj.type}
|
value={adj.type}
|
||||||
onValueChange={(val) => updateAdjustment(index, 'type', val)}
|
onValueChange={(val) =>
|
||||||
className="flex items-center gap-6 w-fit"
|
updateAdjustment(
|
||||||
|
index,
|
||||||
|
'type',
|
||||||
|
val,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="flex w-fit items-center gap-6"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RadioGroupItem value="bonus" id={`bonus-${index}`} />
|
<RadioGroupItem
|
||||||
<Label htmlFor={`bonus-${index}`}>Bonus</Label>
|
value="bonus"
|
||||||
|
id={`bonus-${index}`}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`bonus-${index}`}
|
||||||
|
>
|
||||||
|
Bonus
|
||||||
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RadioGroupItem value="deduction" id={`deduction-${index}`} />
|
<RadioGroupItem
|
||||||
<Label htmlFor={`deduction-${index}`}>Potongan</Label>
|
value="deduction"
|
||||||
|
id={`deduction-${index}`}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`deduction-${index}`}
|
||||||
|
>
|
||||||
|
Potongan
|
||||||
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label className="text-[10px] uppercase mb-1" htmlFor={`amount-${index}`} required>Jumlah</Label>
|
<Label
|
||||||
|
className="mb-1 text-[10px] uppercase"
|
||||||
|
htmlFor={`amount-${index}`}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
Jumlah
|
||||||
|
</Label>
|
||||||
<NumericFormat
|
<NumericFormat
|
||||||
id={`amount-${index}`}
|
id={`amount-${index}`}
|
||||||
customInput={Input}
|
customInput={Input}
|
||||||
@ -146,23 +201,38 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
prefix="Rp "
|
prefix="Rp "
|
||||||
value={adj.amount}
|
value={adj.amount}
|
||||||
onValueChange={(values) => {
|
onValueChange={(values) => {
|
||||||
updateAdjustment(index, 'amount', values.value)
|
updateAdjustment(
|
||||||
|
index,
|
||||||
|
'amount',
|
||||||
|
values.value,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
placeholder="Rp 0"
|
placeholder="Rp 0"
|
||||||
autoComplete='off'
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label className="text-[10px] uppercase mb-1" htmlFor={`description-${index}`} required>Keterangan</Label>
|
<Label
|
||||||
|
className="mb-1 text-[10px] uppercase"
|
||||||
|
htmlFor={`description-${index}`}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
Keterangan
|
||||||
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id={`description-${index}`}
|
id={`description-${index}`}
|
||||||
value={adj.description}
|
value={adj.description}
|
||||||
onChange={e =>
|
onChange={(e) =>
|
||||||
updateAdjustment(index, 'description', e.target.value)
|
updateAdjustment(
|
||||||
|
index,
|
||||||
|
'description',
|
||||||
|
e.target.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
placeholder="Contoh: Lembur"
|
placeholder="Contoh: Lembur"
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -170,7 +240,7 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="text-red-500 mt-6"
|
className="mt-6 text-red-500"
|
||||||
onClick={() => removeAdjustment(index)}
|
onClick={() => removeAdjustment(index)}
|
||||||
>
|
>
|
||||||
<Trash2 className="size-4" />
|
<Trash2 className="size-4" />
|
||||||
@ -181,12 +251,25 @@ export function PayrollFormModal({ isOpen, onClose, payroll }: PayrollFormModalP
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter className="mt-6">
|
<DialogFooter className="mt-6">
|
||||||
<Button type="button" variant="outline" className="gap-2" onClick={handleClose}>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
className="gap-2"
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
<X className="size-4" />
|
<X className="size-4" />
|
||||||
Batal
|
Batal
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" className="gap-2" disabled={processing}>
|
<Button
|
||||||
{processing ? <Loader className="size-4 animate-spin" /> : <Save className="size-4" />}
|
type="submit"
|
||||||
|
className="gap-2"
|
||||||
|
disabled={processing}
|
||||||
|
>
|
||||||
|
{processing ? (
|
||||||
|
<Loader className="size-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Save className="size-4" />
|
||||||
|
)}
|
||||||
{processing ? 'Menyimpan...' : 'Simpan'}
|
{processing ? 'Menyimpan...' : 'Simpan'}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user