import { Head, useForm, Link } from '@inertiajs/react'; import React, { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Separator } from '@/components/ui/separator'; import AppLayout from '@/layouts/app-layout'; import { PlusCircle, Trash2 } from 'lucide-react'; // ─── Types ─────────────────────────────────────────────────────────────────── interface Position { id: number; name: string; basic_salary: number; } interface Department { name: string; } interface Employee { id: number; name: string; nip: string; position: Position; department: Department; } interface DetailItem { name: string; type: 'bonus' | 'deduction'; amount: number; } interface PageProps { employees: Employee[]; } // ─── Helpers ───────────────────────────────────────────────────────────────── function formatRupiah(value: number): string { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, }).format(value); } // ─── Component ─────────────────────────────────────────────────────────────── export default function Create({ employees }: PageProps) { const { data, setData, post, processing, errors } = useForm<{ employee_id: string; period: string; basic_salary: number; details: DetailItem[]; }>({ employee_id: '', period: '', basic_salary: 0, details: [], }); const [selectedEmployee, setSelectedEmployee] = useState(null); // Kalkulasi net salary secara real-time di sisi frontend const netSalary = data.details.reduce((acc, item) => { return item.type === 'bonus' ? acc + (item.amount || 0) : acc - (item.amount || 0); }, data.basic_salary); // Auto-fill basic_salary saat employee dipilih const handleEmployeeChange = (value: string) => { const emp = employees.find((e) => String(e.id) === value) ?? null; setSelectedEmployee(emp); setData((prev) => ({ ...prev, employee_id: value, basic_salary: emp?.position?.basic_salary ?? 0, })); }; // Tambah baris komponen (bonus/potongan) const addDetail = () => { setData('details', [ ...data.details, { name: '', type: 'bonus', amount: 0 }, ]); }; // Update baris komponen pada index tertentu const updateDetail = (index: number, field: keyof DetailItem, value: string | number) => { const updated = [...data.details]; // @ts-expect-error – dynamic field assignment updated[index][field] = field === 'amount' ? Number(value) : value; setData('details', updated); }; // Hapus baris komponen const removeDetail = (index: number) => { setData('details', data.details.filter((_, i) => i !== index)); }; const submit = (e: React.FormEvent) => { e.preventDefault(); post('/admin/payrolls'); }; return (
{/* Back button */} Form Generate Payroll

Pilih karyawan dan periode, lalu tambahkan komponen bonus/potongan jika diperlukan.

{/* ── SEKSI 1: Informasi Utama ── */}

1 Informasi Utama

{/* Pilih Karyawan */}
{errors.employee_id && (

{errors.employee_id}

)}
{/* Periode */}
setData('period', e.target.value)} /> {errors.period && (

{errors.period}

)}
{/* Info Karyawan Terpilih */} {selectedEmployee && (
Departemen:{' '} {selectedEmployee.department.name}
Jabatan:{' '} {selectedEmployee.position.name}
)}
{/* ── SEKSI 2: Gaji Pokok (Auto-fill) ── */}

2 Gaji Pokok

setData('basic_salary', Number(e.target.value)) } className="font-medium" /> {errors.basic_salary && (

{errors.basic_salary}

)}
{/* ── SEKSI 3: Komponen Bonus / Potongan ── */}

3 Komponen Gaji

{data.details.length === 0 ? (

Belum ada komponen tambahan. Klik "Tambah Komponen" untuk menambahkan bonus atau potongan.

) : (
{/* Header kolom */}
Nama Komponen Tipe Nominal (Rp)
{data.details.map((item, index) => (
{/* Nama Komponen */} updateDetail(index, 'name', e.target.value) } /> {/* Tipe */} {/* Nominal */} updateDetail(index, 'amount', e.target.value) } /> {/* Hapus */}
))}
)}
{/* ── RINGKASAN GAJI BERSIH ── */}

Total Gaji Bersih (Estimasi)

Gaji Pokok + Bonus − Potongan

{formatRupiah(Math.max(0, netSalary))}

{/* ── TOMBOL AKSI ── */}
); }