skl/resources/js/pages/admin/hukum/index_hukum.tsx

425 lines
19 KiB
TypeScript

import React, { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Table,
TableHeader,
TableRow,
TableHead,
TableBody,
TableCell,
} from "@/components/ui/table";
import { useToast } from "@/hooks/use-toast";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import {
Search,
Plus,
Pencil,
Trash2,
ChevronLeft,
ChevronRight,
AlertTriangle,
Edit,
FileText,
} from "lucide-react";
import AuthenticatedLayout from "@/layouts/authenticated-layout";
import { Head, router } from "@inertiajs/react";
import { Toaster } from "@/components/ui/toaster";
import { HukumType } from "@/types/perusahaan";
import { AddHukumModal } from "@/components/modals/add-sanksi-hukum";
import { AddPenaatanModal } from "@/components/modals/add-penaatan-modal";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
interface HukumIndexProps {
hukumData: HukumType[];
perusahaan: { PerusahaanId: number; NamaPerusahaan: string }[];
jenisSanksi: { JenisSanksiId: number; NamaJenisSanksi: string }[];
penaatan: { PenaatanId: number; NamaPenaatan: string }[];
}
const ITEMS_PER_PAGE = 5;
export default function HukumIndex({
hukumData = [],
perusahaan = [],
jenisSanksi = [],
penaatan = [],
}: HukumIndexProps) {
const { toast } = useToast();
const [search, setSearch] = useState("");
const [filteredHukum, setFilteredHukum] = useState<HukumType[]>(
hukumData || []
);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [deletingData, setDeletingData] = useState<HukumType | null>(null);
const [isDeleting, setIsDeleting] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isPenaatanModalOpen, setIsPenaatanModalOpen] = useState(false);
const [editingData, setEditingData] = useState<HukumType | null>(null);
const [selectedHukum, setSelectedHukum] = useState<HukumType | null>(null);
// Pagination setup
const totalPages = Math.ceil((filteredHukum?.length || 0) / ITEMS_PER_PAGE);
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
const endIndex = startIndex + ITEMS_PER_PAGE;
const currentItems = filteredHukum.slice(startIndex, endIndex);
// Handle Search
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
const keyword = e.target.value.toLowerCase();
setSearch(keyword);
setFilteredHukum(
hukumData.filter((hukum) =>
hukum.SanksiNumber.toLowerCase().includes(keyword)
)
);
setCurrentPage(1);
};
// Handle Open Modal (Add/Edit)
const handleOpenModal = (data?: HukumType) => {
setEditingData(data || null);
setIsModalOpen(true);
};
// Handle Delete Modal
const handleDeleteModal = (data: HukumType) => {
setDeletingData(data);
setIsDeleteModalOpen(true);
};
// Handle Open Modal for Penaatan
const handleOpenPenaatanModal = (hukum: HukumType) => {
setSelectedHukum(hukum);
setIsPenaatanModalOpen(true);
};
const handleDeleteConfirm = () => {
if (!deletingData) return;
setIsDeleting(true);
router.delete(`/admin/hukum/${deletingData.HukumId}`, {
preserveScroll: true,
onSuccess: () => {
// Update the local state by filtering out the deleted item
setFilteredHukum((prev) =>
prev.filter((item) => item.HukumId !== deletingData.HukumId)
);
toast({
title: "Berhasil",
description: "Data berhasil dihapus",
variant: "default",
});
// Adjust page if necessary (if we're on the last page and it's now empty)
const newTotalItems = filteredHukum.length - 1;
const newTotalPages = Math.ceil(newTotalItems / ITEMS_PER_PAGE);
if (currentPage > newTotalPages && newTotalPages > 0) {
setCurrentPage(newTotalPages);
}
setIsDeleteModalOpen(false);
setDeletingData(null);
setIsDeleting(false);
},
onError: (errors) => {
console.error("Error deleting record:", errors);
toast({
title: "Gagal",
description: "Terjadi kesalahan saat menghapus data",
variant: "destructive",
});
setIsDeleting(false);
},
onFinish: () => {
// This will run regardless of success or error
setIsDeleting(false);
},
});
};
// Handle Success Callback
const handleSuccess = () => {
toast({
title: "Berhasil",
description: editingData
? "Data berhasil diperbarui"
: "Data berhasil ditambahkan",
variant: "default",
});
setIsModalOpen(false);
setEditingData(null);
};
console.log("hukumData", hukumData);
return (
<AuthenticatedLayout header="Riwayat Pengenaan dan Penaatan Sanksi Administratif">
<Head title="Penegakan Hukum" />
<div className="container mx-auto p-4">
<Card className="shadow-lg">
<CardHeader className="flex md:flex-row flex-col justify-between items-center">
<Input
type="text"
placeholder="Cari Sanksi Administratif..."
value={search}
onChange={handleSearch}
className="w-96 border-gray-300 focus:border-blue-500 focus:ring-blue-200 rounded-lg"
/>
<Button
onClick={() => handleOpenModal()}
className="bg-blue-600 hover:bg-blue-700 text-white"
>
<Plus className="h-4 w-4 mr-2" />
Buat Sanksi Administratif
</Button>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>No</TableHead>
<TableHead>Nama Perusahaan</TableHead>
<TableHead>Jenis Sanksi</TableHead>
<TableHead>Nomor SK Sanksi</TableHead>
<TableHead>Tanggal Sanksi</TableHead>
<TableHead className="border-r">
SK Sanksi
</TableHead>
<TableHead>Status Penaatan</TableHead>
<TableHead>Nomor SK Penaatan</TableHead>
<TableHead>Tanggal SK Penaatan</TableHead>
<TableHead>SK Penaatan</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{currentItems?.length > 0 ? (
currentItems.map((hukum, index) => (
<TableRow key={hukum.HukumId}>
<TableCell>
{startIndex + index + 1}
</TableCell>
<TableCell className="flex flex-col gap-2">
<Button
variant="link"
className="px-2 py-1 bg-green-100 h-auto font-normal text-left flex items-center gap-1"
onClick={() =>
handleOpenModal(hukum)
}
>
<Edit className="h-3 w-3 text-green-500" />
{hukum.perusahaan
?.NamaPerusahaan || "-"}
</Button>
<Button
variant="link"
className="px-2 py-1 bg-red-100 h-auto font-normal text-left flex items-center gap-1"
onClick={() =>
handleDeleteModal(hukum)
}
>
<Trash2 className="h-3 w-3 text-red-500" />
Hapus
</Button>
</TableCell>
<TableCell>
{hukum.jenis_sanksi
?.NamaJenisSanksi || "-"}
</TableCell>
<TableCell>
{hukum.SanksiNumber || "-"}
</TableCell>
<TableCell>
{hukum.SanksiDate
? new Date(
hukum.SanksiDate
).toLocaleDateString(
"id-ID",
{
day: "2-digit",
month: "long",
year: "numeric",
}
)
: "-"}
</TableCell>
<TableCell className="border-r">
{hukum.SanksiFile ? (
<a
href={`/storage/${hukum.SanksiFile}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center"
>
<FileText className="w-4 h-4 text-green-600 hover:text-green-800" />
</a>
) : (
"-"
)}
</TableCell>
<TableCell>
<Button
variant="link"
className="px-2 py-1 bg-blue-100 h-auto font-normal text-left flex items-center gap-1"
onClick={() =>
handleOpenPenaatanModal(
hukum
)
}
>
<Edit className="h-3 w-3 text-blue-500" />
{hukum.penaatan
?.NamaPenaatan || "-"}
</Button>
</TableCell>
<TableCell>
{hukum.PenaatanNumber || "-"}
</TableCell>
<TableCell>
{hukum.PenaatanDate
? new Date(
hukum.PenaatanDate
).toLocaleDateString(
"id-ID",
{
day: "2-digit",
month: "long",
year: "numeric",
}
)
: "-"}
</TableCell>
<TableCell>
{hukum.PenaatanFile ? (
<a
href={`/storage/${hukum.PenaatanFile}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center"
>
<FileText className="w-4 h-4 text-green-600 hover:text-green-800" />
</a>
) : (
"-"
)}
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={10}
className="text-center py-4 text-gray-500"
>
Tidak ada data
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</CardContent>
</Card>
{/* Pagination */}
<div className="mt-4 flex justify-end gap-2">
<Button
variant="outline"
onClick={() => setCurrentPage(currentPage - 1)}
disabled={currentPage === 1}
>
<ChevronLeft className="h-4 w-4" />
</Button>
<Button
variant="outline"
onClick={() => setCurrentPage(currentPage + 1)}
disabled={currentPage === totalPages}
>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
</div>
{/* Modal for Adding/Editing Hukum */}
<AddHukumModal
open={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSuccess={handleSuccess}
hukumtype={hukumData}
perusahaan={perusahaan}
penaatan={penaatan}
jenisSanksi={jenisSanksi}
editingData={editingData}
/>
{/* Modal for Updating Penaatan */}
<AddPenaatanModal
open={isPenaatanModalOpen}
onClose={() => setIsPenaatanModalOpen(false)}
onSuccess={() => {
toast({
title: "Berhasil",
description: "Penaatan diperbarui",
variant: "default",
});
setIsPenaatanModalOpen(false);
}}
editingData={selectedHukum}
penaatan={penaatan}
/>
{/* Delete Confirmation Dialog */}
<AlertDialog
open={isDeleteModalOpen}
onOpenChange={setIsDeleteModalOpen}
>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Konfirmasi Hapus</AlertDialogTitle>
<AlertDialogDescription>
Apakah anda yakin ingin menghapus data sanksi untuk
perusahaan{" "}
<strong>
{deletingData?.perusahaan?.NamaPerusahaan}
</strong>
?
<br />
Tindakan ini tidak dapat dibatalkan.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={isDeleting}>
Batal
</AlertDialogCancel>
<AlertDialogAction
onClick={(e) => {
e.preventDefault();
handleDeleteConfirm();
}}
disabled={isDeleting}
className="bg-red-600 hover:bg-red-700 text-white"
>
{isDeleting ? "Menghapus..." : "Hapus"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<Toaster />
</AuthenticatedLayout>
);
}