425 lines
19 KiB
TypeScript
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>
|
|
);
|
|
}
|