411 lines
17 KiB
TypeScript
411 lines
17 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { useForm } from "@inertiajs/react";
|
|
import { PageProps } from "@/types";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import {
|
|
Table,
|
|
TableHeader,
|
|
TableRow,
|
|
TableHead,
|
|
TableBody,
|
|
TableCell,
|
|
} from "@/components/ui/table";
|
|
// import { toast } from "react-toastify";
|
|
import { useToast } from "@/hooks/use-toast";
|
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
import {
|
|
Dialog,
|
|
DialogTrigger,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogFooter,
|
|
} from "@/components/ui/dialog";
|
|
import {
|
|
Search,
|
|
Plus,
|
|
Pencil,
|
|
Trash2,
|
|
ChevronLeft,
|
|
ChevronRight,
|
|
} from "lucide-react";
|
|
import AuthenticatedLayout from "@/layouts/authenticated-layout";
|
|
import { Head } from "@inertiajs/react";
|
|
import { Toaster } from "@/components/ui/toaster";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
|
|
interface Verifikator {
|
|
VerifikatorId: number | null;
|
|
NamaUnitKerja: string;
|
|
NamaKepala: string;
|
|
NIP: string;
|
|
}
|
|
|
|
const ITEMS_PER_PAGE = 5;
|
|
|
|
export default function VerifikatorIndex({
|
|
verifikator,
|
|
}: PageProps<{ verifikator: Verifikator[] }>) {
|
|
const {
|
|
data,
|
|
setData,
|
|
post,
|
|
put,
|
|
delete: destroy,
|
|
reset,
|
|
} = useForm<Verifikator>({
|
|
VerifikatorId: null,
|
|
NamaUnitKerja: "",
|
|
NamaKepala: "",
|
|
NIP: "",
|
|
});
|
|
|
|
const { toast } = useToast();
|
|
|
|
const [editing, setEditing] = useState(false);
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
const [deleteConfirm, setDeleteConfirm] = useState<Verifikator | null>(
|
|
null
|
|
);
|
|
const [search, setSearch] = useState("");
|
|
|
|
const [filteredVerifikator, setFilteredVerifikator] = useState(verifikator);
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
useEffect(() => {
|
|
let filtered = verifikator;
|
|
|
|
if (search) {
|
|
filtered = filtered.filter(
|
|
(v) =>
|
|
v.NamaUnitKerja.toLowerCase().includes(
|
|
search.toLowerCase()
|
|
) ||
|
|
v.NamaKepala.toLowerCase().includes(search.toLowerCase()) ||
|
|
v.NIP.toLowerCase().includes(search.toLowerCase())
|
|
);
|
|
}
|
|
|
|
setFilteredVerifikator(filtered);
|
|
setCurrentPage(1);
|
|
}, [verifikator, search]);
|
|
|
|
const totalPages = Math.ceil(filteredVerifikator.length / ITEMS_PER_PAGE);
|
|
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
|
|
const endIndex = startIndex + ITEMS_PER_PAGE;
|
|
const currentItems = filteredVerifikator.slice(startIndex, endIndex);
|
|
|
|
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
setSearch(e.target.value);
|
|
};
|
|
|
|
const handlePageChange = (page: number) => {
|
|
setCurrentPage(page);
|
|
};
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (editing) {
|
|
put(`/admin/verifikator/${data.VerifikatorId}`, {
|
|
onSuccess: () => {
|
|
toast({
|
|
title: "Berhasil",
|
|
description: "Data verifikator berhasil diperbarui",
|
|
variant: "default",
|
|
});
|
|
setIsModalOpen(false);
|
|
reset();
|
|
setEditing(false);
|
|
},
|
|
onError: () => {
|
|
toast({
|
|
title: "Gagal",
|
|
description: "Terjadi kesalahan saat memperbarui data",
|
|
variant: "destructive",
|
|
});
|
|
},
|
|
});
|
|
} else {
|
|
post("/admin/verifikator", {
|
|
onSuccess: () => {
|
|
toast({
|
|
title: "Berhasil",
|
|
description: "Data verifikator berhasil ditambahkan",
|
|
variant: "default",
|
|
});
|
|
setIsModalOpen(false);
|
|
reset();
|
|
},
|
|
onError: () => {
|
|
toast({
|
|
title: "Gagal",
|
|
description: "Terjadi kesalahan saat menambah data",
|
|
variant: "destructive",
|
|
});
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleEdit = (verifikator: Verifikator) => {
|
|
setData({ ...verifikator });
|
|
setEditing(true);
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
const handleDelete = () => {
|
|
if (deleteConfirm) {
|
|
destroy(`/admin/verifikator/${deleteConfirm.VerifikatorId}`, {
|
|
onSuccess: () => {
|
|
toast({
|
|
title: "Berhasil",
|
|
description: "Data verifikator berhasil dihapus",
|
|
variant: "default",
|
|
});
|
|
setDeleteConfirm(null);
|
|
},
|
|
onError: () => {
|
|
toast({
|
|
title: "Gagal",
|
|
description: "Terjadi kesalahan saat menghapus data",
|
|
variant: "destructive",
|
|
});
|
|
setDeleteConfirm(null);
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AuthenticatedLayout header={"Data Dinas Lingkungan Hidup"}>
|
|
<Head title="Data Dinas Lingkungan Hidup" />
|
|
<div className="container mx-auto p-4">
|
|
<Card className="shadow-lg">
|
|
<CardHeader>
|
|
<div className="flex flex-col space-y-4">
|
|
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
|
<div className="relative w-full md:w-96">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 h-4 w-4" />
|
|
<Input
|
|
type="text"
|
|
placeholder="Cari DLH..."
|
|
value={search}
|
|
onChange={handleSearch}
|
|
className="pl-10 pr-4 w-full"
|
|
/>
|
|
</div>
|
|
<Dialog
|
|
open={isModalOpen}
|
|
onOpenChange={setIsModalOpen}
|
|
>
|
|
<DialogTrigger asChild>
|
|
<Button
|
|
onClick={() => {
|
|
setEditing(false);
|
|
setIsModalOpen(true);
|
|
}}
|
|
>
|
|
<Plus className="h-4 w-4 mr-2" />
|
|
Tambah Dinas
|
|
</Button>
|
|
</DialogTrigger>
|
|
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
{editing
|
|
? "Edit Verifikator"
|
|
: "Tambah Verifikator"}
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
<form
|
|
onSubmit={handleSubmit}
|
|
className="space-y-4"
|
|
>
|
|
<div className="space-y-2">
|
|
<label>Nama Unit Kerja</label>
|
|
<Input
|
|
value={data.NamaUnitKerja}
|
|
onChange={(e) =>
|
|
setData(
|
|
"NamaUnitKerja",
|
|
e.target.value
|
|
)
|
|
}
|
|
placeholder="Masukkan nama unit kerja"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label>Nama Kepala</label>
|
|
<Input
|
|
value={data.NamaKepala}
|
|
onChange={(e) =>
|
|
setData(
|
|
"NamaKepala",
|
|
e.target.value
|
|
)
|
|
}
|
|
placeholder="Masukkan nama kepala"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label>NIP</label>
|
|
<Input
|
|
value={data.NIP}
|
|
onChange={(e) =>
|
|
setData(
|
|
"NIP",
|
|
e.target.value
|
|
)
|
|
}
|
|
placeholder="Masukkan NIP"
|
|
/>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button type="submit">
|
|
{editing
|
|
? "Simpan"
|
|
: "Tambah"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>No</TableHead>
|
|
<TableHead>Unit Kerja</TableHead>
|
|
<TableHead>Nama Kepala</TableHead>
|
|
<TableHead>NIP</TableHead>
|
|
<TableHead>Aksi</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{currentItems.map((item, index) => (
|
|
<TableRow key={item.VerifikatorId}>
|
|
<TableCell>
|
|
{startIndex + index + 1}
|
|
</TableCell>
|
|
<TableCell>
|
|
{item.NamaUnitKerja}
|
|
</TableCell>
|
|
<TableCell>{item.NamaKepala}</TableCell>
|
|
<TableCell>{item.NIP}</TableCell>
|
|
<TableCell className="flex gap-2">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => handleEdit(item)}
|
|
>
|
|
<Pencil className="h-4 w-4 mr-2" />
|
|
Edit
|
|
</Button>
|
|
<Button
|
|
variant="destructive"
|
|
onClick={() =>
|
|
setDeleteConfirm(item)
|
|
}
|
|
>
|
|
<Trash2 className="h-4 w-4 mr-2" />
|
|
Hapus
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
<div className="flex items-center justify-between mt-4">
|
|
<div className="text-sm text-gray-500">
|
|
Showing {startIndex + 1} to{" "}
|
|
{Math.min(endIndex, filteredVerifikator.length)}{" "}
|
|
of {filteredVerifikator.length} entries
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() =>
|
|
handlePageChange(currentPage - 1)
|
|
}
|
|
disabled={currentPage === 1}
|
|
>
|
|
<ChevronLeft className="h-4 w-4" />
|
|
</Button>
|
|
{Array.from(
|
|
{ length: totalPages },
|
|
(_, i) => i + 1
|
|
).map((page) => (
|
|
<Button
|
|
key={page}
|
|
variant={
|
|
currentPage === page
|
|
? "default"
|
|
: "outline"
|
|
}
|
|
size="sm"
|
|
onClick={() => handlePageChange(page)}
|
|
>
|
|
{page}
|
|
</Button>
|
|
))}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() =>
|
|
handlePageChange(currentPage + 1)
|
|
}
|
|
disabled={currentPage === totalPages}
|
|
>
|
|
<ChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{deleteConfirm && (
|
|
<Dialog open={true} onOpenChange={() => setDeleteConfirm(null)}>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Konfirmasi Hapus</DialogTitle>
|
|
</DialogHeader>
|
|
<p>
|
|
Apakah anda yakin ingin menghapus verifikator "
|
|
{deleteConfirm.NamaUnitKerja}"?
|
|
</p>
|
|
<DialogFooter>
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => setDeleteConfirm(null)}
|
|
>
|
|
Batal
|
|
</Button>
|
|
<Button
|
|
variant="destructive"
|
|
onClick={handleDelete}
|
|
>
|
|
Hapus
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)}
|
|
<Toaster />
|
|
</AuthenticatedLayout>
|
|
);
|
|
}
|