feat: Menambahkan controller, request, dan model Penaatan
parent
db45e28350
commit
e37be6bc2d
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\PenaatanRequest;
|
||||
use App\Models\Penaatan;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class PenaatanController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
$penaatan = Penaatan::latest()->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.');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class PenaatanRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'NamaPenaatan' => ['required', 'string', 'max:255'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Penaatan extends Model
|
||||
{
|
||||
|
||||
protected $table = 'Penaatan';
|
||||
|
||||
protected $primaryKey = 'PenaatanId';
|
||||
|
||||
protected $fillable = ['NamaPenaatan'];
|
||||
|
||||
public function hukum()
|
||||
{
|
||||
return $this->hasMany(Hukum::class, 'PenaatanId');
|
||||
}
|
||||
|
||||
}
|
|
@ -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<HukumType | null>(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 (
|
||||
<Dialog open={open} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Perbarui Data Penaatan</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<Label>Status Penaatan</Label>
|
||||
<Select
|
||||
id="PenaatanId"
|
||||
options={penaatanOptions}
|
||||
placeholder="Pilih Status Penaatan"
|
||||
value={penaatanOptions.find(
|
||||
(p) => p.value === data.PenaatanId
|
||||
)}
|
||||
onChange={(option) =>
|
||||
setData("PenaatanId", option?.value || "")
|
||||
}
|
||||
/>
|
||||
|
||||
<Label>Nomor SK Penaatan</Label>
|
||||
<Input
|
||||
value={data.PenaatanNumber}
|
||||
onChange={(e) =>
|
||||
setData("PenaatanNumber", e.target.value)
|
||||
}
|
||||
/>
|
||||
|
||||
<Label>Tanggal SK Penaatan</Label>
|
||||
<Input
|
||||
type="date"
|
||||
value={data.PenaatanDate}
|
||||
onChange={(e) =>
|
||||
setData("PenaatanDate", e.target.value)
|
||||
}
|
||||
/>
|
||||
|
||||
<Label>Dokumen SK Penaatan</Label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Input
|
||||
type="file"
|
||||
onChange={(e) =>
|
||||
setData(
|
||||
"PenaatanFile",
|
||||
e.target.files
|
||||
? e.target.files[0]
|
||||
: null
|
||||
)
|
||||
}
|
||||
/>
|
||||
{editingData?.PenaatanFile && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<span>
|
||||
File saat ini:{" "}
|
||||
{editingData.PenaatanFile}
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
window.open(
|
||||
`/storage/${editingData.PenaatanFile}`,
|
||||
"_blank"
|
||||
)
|
||||
}
|
||||
>
|
||||
Lihat File
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={onClose}
|
||||
disabled={loading}
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit" disabled={loading}>
|
||||
{loading ? "Menyimpan..." : "Simpan"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
|
@ -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() ||
|
||||
"",
|
||||
})
|
||||
|
|
|
@ -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<Penaatan>({
|
||||
PenaatanId: null,
|
||||
NamaPenaatan: "",
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [deleteConfirm, setDeleteConfirm] = useState<Penaatan | null>(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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<AuthenticatedLayout header={"Status Penaatan"}>
|
||||
<Head title="Status Penaatan" />
|
||||
<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 Penaatan..."
|
||||
value={search}
|
||||
onChange={handleSearch}
|
||||
className="pl-10 pr-4 w-full border-gray-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onOpenChange={setIsModalOpen}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setEditing(false);
|
||||
setIsModalOpen(true);
|
||||
}}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 py-2 rounded-lg flex items-center gap-2 transition-colors duration-200"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Buat Penaatan
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-xl font-semibold">
|
||||
{editing
|
||||
? "Ubah Penaatan"
|
||||
: "Buat Penaatan"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="flex flex-col gap-4 mt-4"
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-gray-700">
|
||||
Name
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Masukkan nama Penaatan"
|
||||
value={data.NamaPenaatan}
|
||||
onChange={(e) =>
|
||||
setData(
|
||||
"NamaPenaatan",
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
className="w-full"
|
||||
/>
|
||||
{/* <div className="space-y-2">
|
||||
<label className="text-sm font-medium text-gray-700">
|
||||
Publish
|
||||
</label>
|
||||
<Select
|
||||
value={
|
||||
data.is_publish
|
||||
? "true"
|
||||
: "false"
|
||||
}
|
||||
onValueChange={(
|
||||
value
|
||||
) =>
|
||||
setData(
|
||||
"is_publish",
|
||||
value === "true"
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="true">
|
||||
Published
|
||||
</SelectItem>
|
||||
<SelectItem value="false">
|
||||
Unpublished
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div> */}
|
||||
</div>
|
||||
<DialogFooter className="mt-6">
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
|
||||
>
|
||||
{editing ? "Ubah" : "Buat"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="rounded-lg border border-gray-200 overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="bg-gray-50 dark:bg-black/50">
|
||||
{/* <TableHead className="font-semibold">
|
||||
ID
|
||||
</TableHead> */}
|
||||
<TableHead className="font-semibold">
|
||||
No
|
||||
</TableHead>
|
||||
<TableHead className="font-semibold">
|
||||
Name
|
||||
</TableHead>
|
||||
<TableHead className="font-semibold">
|
||||
Actions
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{currentItems.map((penaatan, index) => (
|
||||
<TableRow
|
||||
key={penaatan.PenaatanId || "new"}
|
||||
className="hover:bg-gray-50 transition-colors duration-150"
|
||||
>
|
||||
{/* <TableCell>{category.id}</TableCell> */}
|
||||
<TableCell>
|
||||
{startIndex + index + 1}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{penaatan.NamaPenaatan}
|
||||
</TableCell>
|
||||
<TableCell className="flex gap-2">
|
||||
<Button
|
||||
onClick={() =>
|
||||
handleEdit(penaatan)
|
||||
}
|
||||
variant="outline"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
setDeleteConfirm(
|
||||
penaatan
|
||||
)
|
||||
}
|
||||
variant="destructive"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Delete
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{currentItems.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={4}
|
||||
className="text-center py-4 text-gray-500"
|
||||
>
|
||||
Tidak ada data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
{/* <div className="flex flex-row mt-3">
|
||||
<div className="text-sm w-1/2">
|
||||
1 : Pengumuman <br /> 2 : Undangan
|
||||
</div>
|
||||
<div className="text-sm w-1/2">
|
||||
3 : Peraturan <br /> 4 : Popup Home
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="flex items-center justify-between mt-4">
|
||||
<div className="text-sm text-gray-500">
|
||||
Showing {startIndex + 1} to{" "}
|
||||
{Math.min(endIndex, filteredPenaatan.length)} of{" "}
|
||||
{filteredPenaatan.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 className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-xl font-semibold">
|
||||
Konfirmasi Penghapusan
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="py-4">
|
||||
<p className="text-gray-600">
|
||||
Apakah Anda yakin ingin menghapus "
|
||||
<span className="font-medium">
|
||||
{deleteConfirm.NamaPenaatan}
|
||||
</span>
|
||||
"?
|
||||
<br />
|
||||
<span className="text-red-500">
|
||||
Tindakan ini tidak dapat dibatalkan.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter className="gap-2">
|
||||
<Button
|
||||
onClick={() => setDeleteConfirm(null)}
|
||||
variant="outline"
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleDelete}
|
||||
variant="destructive"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Ya, hapus
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
<Toaster />
|
||||
</AuthenticatedLayout>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue