import { Head, Link, router } from '@inertiajs/react'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import AppLayout from '@/layouts/app-layout'; import { Printer, Building2, CalendarDays, Hash, Pencil, CheckCircle2, Clock } from 'lucide-react'; interface DetailItem { name: string; type: 'bonus' | 'deduction'; amount: number; } interface PayrollData { id: number; period: string; basic_salary: number; details: DetailItem[]; net_salary: number; status: 'pending' | 'paid'; created_at: string; employee: { name: string; nip: string; position: string; department: string; }; } interface PageProps { payroll: PayrollData; } function formatRupiah(value: number): string { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, }).format(value); } function formatPeriod(period: string): string { const [year, month] = period.split('-'); const date = new Date(Number(year), Number(month) - 1, 1); return date.toLocaleDateString('id-ID', { month: 'long', year: 'numeric' }); } function InfoCell({ label, value }: { label: string; value: string }) { return (

{label}

{value}

); } function LineItem({ label, value, type = 'neutral', }: { label: string; value: string; type?: 'neutral' | 'bonus' | 'deduction'; }) { const valueClass = type === 'bonus' ? 'text-emerald-600 font-medium' : type === 'deduction' ? 'text-red-500 font-medium' : 'font-medium'; const prefix = type === 'bonus' ? '+ ' : type === 'deduction' ? '− ' : ''; return (
{label} {prefix}{value}
); } function StatusBadge({ status }: { status: 'pending' | 'paid' }) { return status === 'paid' ? ( Telah Dikirim ) : ( Menunggu ); } export default function Show({ payroll }: PageProps) { const bonuses = payroll.details.filter((d) => d.type === 'bonus'); const deductions = payroll.details.filter((d) => d.type === 'deduction'); const totalBonus = bonuses.reduce((s, d) => s + d.amount, 0); const totalDeduction = deductions.reduce((s, d) => s + d.amount, 0); const [toggling, setToggling] = useState(false); const toggleStatus = () => { const newStatus = payroll.status === 'paid' ? 'pending' : 'paid'; setToggling(true); router.patch( `/admin/payrolls/${payroll.id}/status`, { status: newStatus }, { onFinish: () => setToggling(false) }, ); }; return (
{/* Toolbar — tersembunyi saat print */}
{payroll.status !== 'paid' && ( <> )}
{/* ── Slip Card ── */} {/* ── HEADER ── */}
{/* Nama Perusahaan */}

PT. HRIS Nusantara

Slip Gaji Karyawan

{/* Meta slip */}
{String(payroll.id).padStart(5, '0')}
{payroll.created_at}
{/* ── INFO KARYAWAN ── */}

Informasi Karyawan

{/* ── PERIODE ── */}

Periode Penggajian

{formatPeriod(payroll.period)}

{/* ── RINCIAN GAJI ── */}
{/* Gaji Pokok */}

Komponen Gaji

{/* Bonus */} {bonuses.length > 0 && ( <>

Tambahan

{bonuses.map((item, i) => ( ))}
Subtotal tambahan + {formatRupiah(totalBonus)}
)} {/* Potongan */} {deductions.length > 0 && ( <>

Potongan

{deductions.map((item, i) => ( ))}
Subtotal potongan − {formatRupiah(totalDeduction)}
)}
{/* ── TOTAL GAJI BERSIH ── */}

Total Gaji Bersih

Gaji Pokok {bonuses.length > 0 && ' + Tambahan'} {deductions.length > 0 && ' − Potongan'}

{formatRupiah(payroll.net_salary)}

{/* ── FOOTER ── */}

Dokumen ini diterbitkan secara otomatis oleh sistem HRIS dan sah tanpa tanda tangan basah.

); }