243 lines
13 KiB
TypeScript
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>
|
|
);
|
|
}
|