{ e.currentTarget.style.display='none'; }} />
+ |
{employee.user?.name}
diff --git a/resources/js/pages/admin/payrolls/create.tsx b/resources/js/pages/admin/payrolls/create.tsx
index 2f1c370..9c43fbf 100644
--- a/resources/js/pages/admin/payrolls/create.tsx
+++ b/resources/js/pages/admin/payrolls/create.tsx
@@ -15,7 +15,7 @@ import { Separator } from '@/components/ui/separator';
import AppLayout from '@/layouts/app-layout';
import { PlusCircle, Trash2 } from 'lucide-react';
-// βββ Types βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+
interface Position {
id: number;
@@ -45,7 +45,7 @@ interface PageProps {
employees: Employee[];
}
-// βββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+
function formatRupiah(value: number): string {
return new Intl.NumberFormat('id-ID', {
@@ -55,7 +55,7 @@ function formatRupiah(value: number): string {
}).format(value);
}
-// βββ Component βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+
export default function Create({ employees }: PageProps) {
const { data, setData, post, processing, errors } = useForm<{
@@ -72,14 +72,14 @@ export default function Create({ employees }: PageProps) {
const [selectedEmployee, setSelectedEmployee] = useState
- {/* Nama Komponen */}
-
- updateDetail(index, 'name', e.target.value)
- }
- />
-
- {/* Tipe */}
-
diff --git a/resources/js/pages/admin/payrolls/edit.tsx b/resources/js/pages/admin/payrolls/edit.tsx
new file mode 100644
index 0000000..bf91025
--- /dev/null
+++ b/resources/js/pages/admin/payrolls/edit.tsx
@@ -0,0 +1,273 @@
+import { Head, useForm, Link } from '@inertiajs/react';
+import React 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';
+
+
+
+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';
+ employee: {
+ id: number;
+ 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('-');
+ return new Date(Number(year), Number(month) - 1, 1)
+ .toLocaleDateString('id-ID', { month: 'long', year: 'numeric' });
+}
+
+
+
+export default function Edit({ payroll }: PageProps) {
+ const { data, setData, put, processing, errors } = useForm<{
+ basic_salary: number;
+ details: DetailItem[];
+ }>({
+ basic_salary: payroll.basic_salary,
+ details: payroll.details,
+ });
+
+ // Hitung net salary
+ const netSalary = data.details.reduce((acc, item) => {
+ return item.type === 'bonus'
+ ? acc + (item.amount || 0)
+ : acc - (item.amount || 0);
+ }, data.basic_salary);
+
+ const addDetail = () => {
+ setData('details', [...data.details, { name: '', type: 'bonus', amount: 0 }]);
+ };
+
+ 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);
+ };
+
+ const removeDetail = (index: number) => {
+ setData('details', data.details.filter((_, i) => i !== index));
+ };
+
+ const submit = (e: React.FormEvent) => {
+ e.preventDefault();
+ put(`/admin/payrolls/${payroll.id}`);
+ };
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/resources/js/pages/admin/payrolls/index.tsx b/resources/js/pages/admin/payrolls/index.tsx
index 5882678..8ec4e99 100644
--- a/resources/js/pages/admin/payrolls/index.tsx
+++ b/resources/js/pages/admin/payrolls/index.tsx
@@ -1,7 +1,15 @@
-import { Head, Link } from '@inertiajs/react';
+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,
@@ -11,7 +19,11 @@ import {
TableRow,
} from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
-import { PlusCircle, FileText } from 'lucide-react';
+import { PlusCircle, FileText, Search, CheckCircle2, Clock, Pencil, Download } from 'lucide-react';
+import { useState } from 'react';
+import * as XLSX from 'xlsx';
+
+
interface Payroll {
id: number;
@@ -24,8 +36,12 @@ interface Payroll {
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',
@@ -42,41 +58,137 @@ function formatPeriod(period: string): string {
function StatusBadge({ status }: { status: 'pending' | 'paid' }) {
return status === 'paid' ? (
- + Revisi komponen gaji untuk periode ini. Karyawan dan periode tidak dapat diubah. + +
+
+
+
+
+
+ Karyawan +{payroll.employee.name} +
+
+ NIP +{payroll.employee.nip} +
+
+ Jabatan +{payroll.employee.position ?? '-'} +
+
+ Periode +{formatPeriod(payroll.period)} +
-
-
-
- Manajemen Payroll-Daftar seluruh payroll yang telah di-generate. -
+
+
+ {/* Filter */}
+
+
+ Manajemen Payroll+Daftar seluruh payroll yang telah di-generate. +
+
+
+
+
+
+
+
+
+
+
+
+ setPeriod(e.target.value)}
+ />
+
+
+
+
+
+
+ - Belum ada data payroll. - +Belum ada data payroll. @@ -96,28 +208,39 @@ export default function Index({ payrolls }: PageProps) {{payroll.employee_name}
-
- NIP: {payroll.employee_nip}
-
+ NIP: {payroll.employee_nip}
+
+
+
{/* Toolbar β tersembunyi saat print */}
-
+
-
+
{/* ββ Slip Card ββ */}
diff --git a/resources/js/pages/admin/positions/create.tsx b/resources/js/pages/admin/positions/create.tsx
index 72cb184..c552483 100644
--- a/resources/js/pages/admin/positions/create.tsx
+++ b/resources/js/pages/admin/positions/create.tsx
@@ -78,7 +78,7 @@ export default function Create() {
+ {payroll.status !== 'paid' && (
+ <>
+
+
+ >
+ )}
+
+
|