import { Head, Link, router, usePage } from '@inertiajs/react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import AppLayout from '@/layouts/app-layout'; import { PlusCircle, FileText, Search, CheckCircle2, Clock, Pencil, Download } from 'lucide-react'; import { useState } from 'react'; import * as XLSX from 'xlsx'; interface Payroll { id: number; employee_name: string; employee_nip: string; period: string; net_salary: number; status: 'pending' | 'paid'; } interface PageProps { payrolls: Payroll[]; filters: { search?: string; period?: string; status?: string }; [key: string]: unknown; } 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('-'); return new Date(Number(year), Number(month) - 1, 1) .toLocaleDateString('id-ID', { month: 'long', year: 'numeric' }); } function StatusBadge({ status }: { status: 'pending' | 'paid' }) { return status === 'paid' ? ( Telah Dikirim ) : ( Menunggu ); } export default function Index({ payrolls, filters }: PageProps) { const [search, setSearch] = useState(filters.search ?? ''); const [period, setPeriod] = useState(filters.period ?? ''); const [status, setStatus] = useState(filters.status ?? ''); const [processingId, setProcessingId] = useState(null); const applyFilter = () => { router.get('/admin/payrolls', { search, period, status }, { preserveScroll: true }); }; const resetFilter = () => { setSearch(''); setPeriod(''); setStatus(''); router.get('/admin/payrolls', {}, { preserveScroll: true }); }; const toggleStatus = (payroll: Payroll) => { const newStatus = payroll.status === 'paid' ? 'pending' : 'paid'; setProcessingId(payroll.id); router.patch( `/admin/payrolls/${payroll.id}/status`, { status: newStatus }, { preserveScroll: true, onFinish: () => setProcessingId(null) }, ); }; const exportExcel = () => { const rows = payrolls.map((p, i) => ({ No: i + 1, Karyawan: p.employee_name, NIP: p.employee_nip, Periode: formatPeriod(p.period), 'Gaji Bersih': p.net_salary, Status: p.status === 'paid' ? 'Telah Dikirim' : 'Menunggu', })); const ws = XLSX.utils.json_to_sheet(rows); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Payroll'); XLSX.writeFile(wb, `payroll_${new Date().toISOString().slice(0, 10)}.xlsx`); }; return (

Manajemen Payroll

Daftar seluruh payroll yang telah di-generate.

{/* Filter */}
setSearch(e.target.value)} onKeyDown={e => e.key === 'Enter' && applyFilter()} />
setPeriod(e.target.value)} />
{/* Tabel */} Daftar Slip Gaji {payrolls.length === 0 ? (

Belum ada data payroll.

) : ( # Karyawan Periode Gaji Bersih Status Aksi {payrolls.map((payroll, index) => ( {index + 1}
{payroll.employee_name}
NIP: {payroll.employee_nip}
{formatPeriod(payroll.period)} {formatRupiah(payroll.net_salary)}
))}
)}
); }