243 lines
13 KiB
TypeScript

import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { EmptyState } from '@/components/ui/empty-state';
import { Pagination } from '@/components/ui/pagination';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem } from '@/types';
import { Head, Link, usePage } from '@inertiajs/react';
import { PencilIcon, PlusIcon, Trash2Icon } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Toaster, toast } from 'sonner';
import { Input } from '@/components/ui/input'; // Tambahkan import Input
import {
AlertDialog, AlertDialogAction, AlertDialogCancel,
AlertDialogContent, AlertDialogDescription, AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger
} from '@/components/ui/alert-dialog';
interface Employee {
id: string;
employee_id: string;
name: string;
email: string;
gender: string;
nik: string;
birth_date: Date;
birth_place: string;
address: string;
phone_number: string;
join_date: string;
is_active: boolean;
}
interface PageProps {
employees: {
data: Employee[];
links: Array<{
url: string | null;
label: string;
active: boolean;
}>;
};
status?: string;
}
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashboard', href: '/dashboard' },
{ title: 'Employees', href: '/employees' },
];
export default function EmployeeIndex() {
const { employees, status } = usePage<PageProps>().props;
const [searchTerm, setSearchTerm] = useState('');
const [filteredEmployees, setFilteredEmployees] = useState<Employee[]>(employees.data);
useEffect(() => {
if (status) {
toast.success(status);
}
}, [status]);
useEffect(() => {
// Filter data berdasarkan search term
const results = employees.data.filter(employee =>
Object.values(employee).some(
value =>
value &&
value.toString().toLowerCase().includes(searchTerm.toLowerCase())
)
);
setFilteredEmployees(results);
}, [searchTerm, employees.data]);
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title="Employee Management" />
<Toaster position="top-right" richColors />
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold">Data Pegawai</h1>
</div>
<Button asChild>
<Link href={route('employees.create')}>
<PlusIcon className="mr-2 h-4 w-4" />
Tambah Employee
</Link>
</Button>
</div>
{/* Tambahkan input search */}
<div className="w-full md:w-1/3">
<Input
type="text"
placeholder="Cari pegawai..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<div>
<div>
{filteredEmployees.length === 0 ? (
<EmptyState
title="No Employees Found"
description={searchTerm ?
"No employees match your search" :
"Get started by creating a new employee"}
action={
<Button asChild>
<Link href={route('employees.create')}>
<PlusIcon className="mr-2 h-4 w-4" />
Add Employee
</Link>
</Button>
}
/>
) : (
<>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>ID Pegawai</TableHead>
<TableHead>Nama</TableHead>
<TableHead>NIK</TableHead>
<TableHead>Jenis Kelamin</TableHead>
<TableHead>Tempat, Tanggal Lahir</TableHead>
<TableHead>No. Telpon</TableHead>
<TableHead>Tanggal Bergabung</TableHead>
<TableHead>Status</TableHead>
<TableHead>Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredEmployees.map((employee) => (
<TableRow key={employee.id}>
<TableCell className="font-medium">
{employee.employee_id}
</TableCell>
<TableCell>
{employee.name}
<br/>
{employee.email}
</TableCell>
<TableCell>{employee.nik}</TableCell>
<TableCell className="capitalize">
{employee.gender}
</TableCell>
<TableCell>
{employee.birth_place ? `${employee.birth_place}, ${new Date(employee.birth_date).toLocaleDateString('id-ID', {
day: '2-digit',
month: 'long',
year: 'numeric'
})}` : new Date(employee.birth_date).toLocaleDateString('id-ID', {
day: '2-digit',
month: 'long',
year: 'numeric'
})}
</TableCell>
<TableCell>
{employee.phone_number}
</TableCell>
<TableCell>
{new Date(employee.join_date).toLocaleDateString()}
</TableCell>
<TableCell>
<Badge
variant={employee.is_active ? 'default' : 'destructive'}
>
{employee.is_active ? 'Active' : 'Inactive'}
</Badge>
</TableCell>
<TableCell className="flex justify-start gap-2">
<Button
variant="ghost"
size="icon"
asChild
className="hover:bg-neutral-100"
>
<Link href={route('employees.edit', employee.id)}>
<PencilIcon className="h-4 w-4" />
</Link>
</Button>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
variant="ghost"
size="icon"
className="text-red-600 hover:bg-red-50 hover:text-red-700"
>
<Trash2Icon className="h-4 w-4" />
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Apakah Anda yakin?</AlertDialogTitle>
<AlertDialogDescription>
Tindakan ini tidak dapat dibatalkan. Data pegawai akan dihapus secara permanen.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Batal</AlertDialogCancel>
<AlertDialogAction asChild>
<Link
href={route('employees.destroy', employee.id)}
method="delete"
as="button"
onSuccess={() => toast.success('Employee deleted successfully')}
preserveScroll
>
Hapus
</Link>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{/* Tetap tampilkan pagination untuk data asli */}
{employees.links.length > 3 && (
<div className="mt-4">
<Pagination links={employees.links} />
</div>
)}
</>
)}
</div>
</div>
</div>
</AppLayout>
);
}