From e37be6bc2d94b127c150ac255aa38f5dac7b1e3f Mon Sep 17 00:00:00 2001 From: marszayn Date: Mon, 3 Mar 2025 11:51:49 +0700 Subject: [PATCH] feat: Menambahkan controller, request, dan model Penaatan --- app/Http/Controllers/PenaatanController.php | 56 +++ app/Http/Requests/PenaatanRequest.php | 28 ++ app/Models/Penaatan.php | 22 + .../components/modals/add-penaatan-modal.tsx | 208 ++++++++ .../modals/add-perusahaan-modal.tsx | 4 +- .../pages/admin/penaatan/index_penaatan.tsx | 461 ++++++++++++++++++ 6 files changed, 777 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/PenaatanController.php create mode 100644 app/Http/Requests/PenaatanRequest.php create mode 100644 app/Models/Penaatan.php create mode 100644 resources/js/components/modals/add-penaatan-modal.tsx create mode 100644 resources/js/pages/admin/penaatan/index_penaatan.tsx diff --git a/app/Http/Controllers/PenaatanController.php b/app/Http/Controllers/PenaatanController.php new file mode 100644 index 0000000..b5fe068 --- /dev/null +++ b/app/Http/Controllers/PenaatanController.php @@ -0,0 +1,56 @@ +get(); + return Inertia::render('admin/penaatan/index_penaatan', ['penaatan' => $penaatan]); + } catch (\Exception $e) { + Log::error('Error fetching Status Penaatan: ' . $e->getMessage()); + return back()->with('error', 'Something went wrong.'); + } + } + + public function store(PenaatanRequest $request) + { + try { + Penaatan::create($request->validated()); + return redirect()->route('admin.penataan.index')->with('success', 'Penaatan created successfully.'); + } catch (\Exception $e) { + Log::error('Error creating Penaatan: ' . $e->getMessage()); + return back()->with('error', 'Failed to create Penaatan.'); + } + } + + public function update(PenaatanRequest $request, Penaatan $penaatan) + { + try { + $penaatan->update($request->validated()); + return redirect()->route('admin.penaatan.index')->with('success', 'Penaatan berhasil diperbarui.'); + } catch (\Exception $e) { + Log::error('Error updating Penaatan: ' . $e->getMessage()); + return back()->with('error', 'Something went wrong.'); + } + } + + public function destroy(Penaatan $penaatan) + { + try { + $penaatan->delete(); + return redirect()->route('admin.penaatan.index')->with('success', 'Penaatan berhasil dihapus.'); + } catch (\Exception $e) { + Log::error('Error deleting Penaatan: ' . $e->getMessage()); + return back()->with('error', 'Something went wrong.'); + } + } +} diff --git a/app/Http/Requests/PenaatanRequest.php b/app/Http/Requests/PenaatanRequest.php new file mode 100644 index 0000000..9fda70f --- /dev/null +++ b/app/Http/Requests/PenaatanRequest.php @@ -0,0 +1,28 @@ +|string> + */ + public function rules(): array + { + return [ + 'NamaPenaatan' => ['required', 'string', 'max:255'], + ]; + } +} diff --git a/app/Models/Penaatan.php b/app/Models/Penaatan.php new file mode 100644 index 0000000..0bbae3c --- /dev/null +++ b/app/Models/Penaatan.php @@ -0,0 +1,22 @@ +hasMany(Hukum::class, 'PenaatanId'); + } + +} diff --git a/resources/js/components/modals/add-penaatan-modal.tsx b/resources/js/components/modals/add-penaatan-modal.tsx new file mode 100644 index 0000000..b4d1106 --- /dev/null +++ b/resources/js/components/modals/add-penaatan-modal.tsx @@ -0,0 +1,208 @@ +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import Select from "react-select"; +import { useState, useEffect } from "react"; +import { useForm } from "@inertiajs/react"; +import { useToast } from "@/hooks/use-toast"; + +import { HukumType } from "@/types/perusahaan"; + +interface AddPenaatanModalProps { + open: boolean; + onClose: () => void; + onSuccess: () => void; + editingData: HukumType | null; + penaatan: { PenaatanId: number; NamaPenaatan: string }[]; +} + +export function AddPenaatanModal({ + open, + onClose, + onSuccess, + editingData, + penaatan, +}: AddPenaatanModalProps) { + const { toast } = useToast(); + const [loading, setLoading] = useState(false); + + const { data, setData, post, reset } = useForm<{ + PenaatanId: string; + PenaatanNumber: string; + PenaatanDate: string; + PenaatanFile: File | null; + currentPenaatanFile?: string; + }>({ + PenaatanId: "", + PenaatanNumber: "", + PenaatanDate: "", + PenaatanFile: null, + currentPenaatanFile: editingData?.PenaatanFile, + }); + + const [isPenaatanModalOpen, setIsPenaatanModalOpen] = useState(false); + const [selectedHukum, setSelectedHukum] = useState(null); + + // Handle Open Modal for Penaatan + const handleOpenPenaatanModal = (hukum: HukumType) => { + setSelectedHukum(hukum); + setIsPenaatanModalOpen(true); + }; + + useEffect(() => { + if (editingData) { + setData({ + PenaatanId: editingData.PenaatanId?.toString() || "", + PenaatanNumber: editingData.PenaatanNumber || "", + PenaatanDate: editingData.PenaatanDate || "", + PenaatanFile: null, + currentPenaatanFile: "", + }); + } else { + reset(); + } + }, [editingData, open]); + + const penaatanOptions = penaatan.map((p) => ({ + value: p.PenaatanId.toString(), + label: p.NamaPenaatan, + })); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + + const formData = new FormData(); + formData.append("PenaatanId", data.PenaatanId); + formData.append("PenaatanNumber", data.PenaatanNumber); + formData.append("PenaatanDate", data.PenaatanDate); + if (data.PenaatanFile) + formData.append("PenaatanFile", data.PenaatanFile); + + if (!editingData) return; + + post(`/admin/hukum/${editingData.HukumId}/penaatan`, { + data: formData, + forceFormData: true, + onSuccess: () => { + toast({ + title: "Berhasil", + description: "Data Penaatan berhasil diperbarui", + variant: "default", + }); + reset(); + setLoading(false); + onSuccess(); + onClose(); + }, + onError: () => { + toast({ + title: "Gagal", + description: "Terjadi kesalahan saat memperbarui data", + variant: "destructive", + }); + setLoading(false); + }, + }); + }; + + return ( + + + + Perbarui Data Penaatan + +
+
+ + + setData("PenaatanNumber", e.target.value) + } + /> + + + + setData("PenaatanDate", e.target.value) + } + /> + + +
+ + setData( + "PenaatanFile", + e.target.files + ? e.target.files[0] + : null + ) + } + /> + {editingData?.PenaatanFile && ( +
+ + File saat ini:{" "} + {editingData.PenaatanFile} + + +
+ )} +
+
+ + + + + +
+
+
+ ); +} diff --git a/resources/js/components/modals/add-perusahaan-modal.tsx b/resources/js/components/modals/add-perusahaan-modal.tsx index 566ddab..f49e42f 100644 --- a/resources/js/components/modals/add-perusahaan-modal.tsx +++ b/resources/js/components/modals/add-perusahaan-modal.tsx @@ -179,7 +179,7 @@ AddPerusahaanModalProps) { const perusahaanOptions = perusahaan.map((per) => ({ value: per.PerusahaanId, - label: per.PerusahaanId, + label: per.NamaPerusahaan, })); const kecamatanOptions = kecamatan @@ -439,7 +439,7 @@ AddPerusahaanModalProps) { onChange={(option) => setData({ ...data, - PerusahaanId: + NamaPerusahaan: option?.value?.toString() || "", }) diff --git a/resources/js/pages/admin/penaatan/index_penaatan.tsx b/resources/js/pages/admin/penaatan/index_penaatan.tsx new file mode 100644 index 0000000..8b416e6 --- /dev/null +++ b/resources/js/pages/admin/penaatan/index_penaatan.tsx @@ -0,0 +1,461 @@ +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 Penaatan { + PenaatanId: number | null; + NamaPenaatan: string; +} + +const ITEMS_PER_PAGE = 5; + +export default function PenaatanIndex({ + penaatan, +}: PageProps<{ penaatan: Penaatan[] }>) { + const { + data, + setData, + post, + put, + delete: destroy, + reset, + } = useForm({ + PenaatanId: null, + NamaPenaatan: "", + }); + + const { toast } = useToast(); + + const [editing, setEditing] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); + const [deleteConfirm, setDeleteConfirm] = useState(null); + const [search, setSearch] = useState(""); + + const [filteredPenaatan, setFilteredPenaatan] = useState(penaatan); + const [currentPage, setCurrentPage] = useState(1); + + useEffect(() => { + let filtered = penaatan; + + if (search) { + filtered = filtered.filter((penaatan) => + penaatan.NamaPenaatan.toLowerCase().includes( + search.toLowerCase() + ) + ); + } + + setFilteredPenaatan(filtered); + setCurrentPage(1); + }, [penaatan, search]); + + const totalPages = Math.ceil(filteredPenaatan.length / ITEMS_PER_PAGE); + const startIndex = (currentPage - 1) * ITEMS_PER_PAGE; + const endIndex = startIndex + ITEMS_PER_PAGE; + const currentItems = filteredPenaatan.slice(startIndex, endIndex); + + const handleSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); + }; + + const handlePageChange = (page: number) => { + setCurrentPage(page); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (editing) { + put(`/admin/penaatan/${data.PenaatanId}`, { + onSuccess: () => { + toast({ + title: "Berhasil", + description: "Penaatan berhasil diperbarui", + variant: "default", + }); + setIsModalOpen(false); + reset(); + setEditing(false); + }, + onError: () => { + toast({ + title: "Gagal", + description: + "Terjadi kesalahan saat memperbarui Penaatan", + variant: "destructive", + }); + }, + }); + } else { + post("/admin/penaatan", { + onSuccess: () => { + toast({ + title: "Berhasil", + description: "Penaatan berhasil dibuat", + variant: "default", + }); + setIsModalOpen(false); + reset(); + }, + onError: () => { + toast({ + title: "Gagal", + description: "Terjadi kesalahan saat membuat Penaatan", + variant: "destructive", + }); + }, + }); + } + }; + + const handleEdit = (penaatan: Penaatan) => { + setData({ ...penaatan }); + setEditing(true); + setIsModalOpen(true); + }; + + const handleDelete = () => { + if (deleteConfirm) { + destroy(`/admin/penaatan/${deleteConfirm.PenaatanId}`, { + onSuccess: () => { + toast({ + title: "Berhasil", + description: "Penaatan berhasil dihapus", + variant: "default", + }); + setDeleteConfirm(null); + }, + onError: () => { + toast({ + title: "Gagal", + description: + "Terjadi kesalahan saat menghapus Penaatan", + variant: "destructive", + }); + setDeleteConfirm(null); + }, + }); + } + }; + return ( + + +
+ + +
+
+
+ + +
+ + + + + + + + + {editing + ? "Ubah Penaatan" + : "Buat Penaatan"} + + +
+
+ + + setData( + "NamaPenaatan", + e.target.value + ) + } + className="w-full" + /> + {/*
+ + +
*/} +
+ + + +
+
+
+
+
+
+ +
+ + + + {/* + ID + */} + + No + + + Name + + + Actions + + + + + {currentItems.map((penaatan, index) => ( + + {/* {category.id} */} + + {startIndex + index + 1} + + + {penaatan.NamaPenaatan} + + + + + + + ))} + {currentItems.length === 0 && ( + + + Tidak ada data + + + )} + +
+
+ {/*
+
+ 1 : Pengumuman
2 : Undangan +
+
+ 3 : Peraturan
4 : Popup Home +
+
*/} +
+
+ Showing {startIndex + 1} to{" "} + {Math.min(endIndex, filteredPenaatan.length)} of{" "} + {filteredPenaatan.length} entries +
+
+ + {Array.from( + { length: totalPages }, + (_, i) => i + 1 + ).map((page) => ( + + ))} + +
+
+
+
+
+ + {deleteConfirm && ( + setDeleteConfirm(null)}> + + + + Konfirmasi Penghapusan + + +
+

+ Apakah Anda yakin ingin menghapus " + + {deleteConfirm.NamaPenaatan} + + "? +
+ + Tindakan ini tidak dapat dibatalkan. + +

+
+ + + + +
+
+ )} + +
+ ); +}