feat: Tambahkan komponen FilterPencarian dan ModalIzinLingkungan

main
marszayn 2025-03-10 14:09:32 +07:00
parent 4c21af6209
commit 3c71e9289c
5 changed files with 751 additions and 84 deletions

View File

@ -0,0 +1,336 @@
import React, { useState } from "react";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import Select from "react-select";
import { CalendarIcon, Search } from "lucide-react";
import { format } from "date-fns";
import { DateRange } from "react-day-picker";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Calendar as UIDatePicker } from "@/components/ui/calendar";
import {
Perusahaan,
JenisDokIL,
JenisKegiatan,
PerizinanLingkunganType,
} from "@/types/perusahaan";
type SelectOption = {
value: string;
label: string;
};
type FilterPerizinanLingkunganProps = {
perusahaan?: Perusahaan[];
jenisDokIL?: JenisDokIL[];
jenisKegiatan?: JenisKegiatan[];
izinLingkungan?: PerizinanLingkunganType[];
onSearch: (filters: {
selectedPerusahaan: SelectOption | null;
selectedJenisKegiatan: SelectOption | null;
Alamat: string;
TeleponFax: string;
Email: string;
selectedJenisIzin: SelectOption | null;
ILNomor: string;
ILTanggal: string | null;
}) => void;
};
export default function FilterPerizinanLingkungan({
perusahaan = [],
jenisDokIL = [],
jenisKegiatan = [],
onSearch,
}: FilterPerizinanLingkunganProps) {
const [dateRange, setDateRange] = useState<DateRange | undefined>({
from: undefined,
to: undefined,
});
const perusahaanOptions: SelectOption[] = perusahaan.map((p) => ({
value: p.PerusahaanId.toString(),
label: p.NamaPerusahaan,
}));
const jenisKegiatanOptions: SelectOption[] = jenisKegiatan.map((jk) => ({
value: jk.JenisKegiatanId.toString(),
label: jk.NamaJenisKegiatan,
}));
const jenisIzinOptions: SelectOption[] = jenisDokIL.map((jdi) => ({
value: jdi.JenisDokILId.toString(),
label: jdi.NamaJenisDokIL,
}));
const selectStyles = {
control: (base: any) => ({
...base,
minHeight: "38px",
borderRadius: "0.375rem",
borderColor: "#e2e8f0",
boxShadow: "none",
"&:hover": {
borderColor: "#cbd5e0",
},
}),
};
const [selectedPerusahaan, setSelectedPerusahaan] =
useState<SelectOption | null>(null);
const [selectedJenisKegiatan, setSelectedJenisKegiatan] =
useState<SelectOption | null>(null);
const [Alamat, setAlamat] = useState<string>("");
const [TeleponFax, setTeleponFax] = useState<string>("");
const [Email, setEmail] = useState<string>("");
const [selectedJenisIzin, setSelectedJenisIzin] =
useState<SelectOption | null>(null);
const [ILNomor, setILNomor] = useState<string>("");
const [ILTanggal, setILTanggal] = useState<Date | null>(null);
function handleSearch() {
let formattedDate: string | null = null;
if (dateRange?.from && dateRange?.to) {
// Jika kedua tanggal dipilih, format sebagai rentang
formattedDate = `${format(dateRange.from, "yyyy-MM-dd")} - ${format(
dateRange.to,
"yyyy-MM-dd"
)}`;
} else if (dateRange?.from) {
// Jika hanya tanggal mulai yang dipilih, gunakan tanggal tersebut
formattedDate = format(dateRange.from, "yyyy-MM-dd");
}
onSearch({
selectedPerusahaan,
selectedJenisKegiatan,
Alamat,
TeleponFax,
Email,
selectedJenisIzin,
ILNomor,
ILTanggal: formattedDate,
});
}
function handleReset() {
// Reset all form state
setDateRange({ from: undefined, to: undefined });
setSelectedPerusahaan(null);
setSelectedJenisKegiatan(null);
setAlamat("");
setTeleponFax("");
setEmail("");
setSelectedJenisIzin(null);
setILNomor("");
setILTanggal(null);
// Reset the search results by calling onSearch with empty/default values
onSearch({
selectedPerusahaan: null,
selectedJenisKegiatan: null,
Alamat: "",
TeleponFax: "",
Email: "",
selectedJenisIzin: null,
ILNomor: "",
ILTanggal: null,
});
}
return (
<div className="bg-white py-6 rounded-lg shadow-sm mb-6">
<Card className="shadow-md border-slate-200">
<CardHeader className="pb-3">
<CardTitle className="text-lg font-medium">
Filter Pencarian Perizinan Lingkungan
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Kolom Kiri */}
<div className="space-y-4">
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Nama Perusahaan
</label>
<div className="col-span-2">
<Select
options={perusahaanOptions}
value={selectedPerusahaan}
onChange={setSelectedPerusahaan}
placeholder="Pilih Perusahaan"
isClearable
isSearchable
styles={selectStyles}
noOptionsMessage={() =>
"Tidak ada data"
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Jenis Kegiatan
</label>
<div className="col-span-2">
<Select
options={jenisKegiatanOptions}
value={selectedJenisKegiatan}
onChange={setSelectedJenisKegiatan}
placeholder="Pilih Jenis Kegiatan"
isClearable
isSearchable
styles={selectStyles}
noOptionsMessage={() =>
"Tidak ada data"
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Alamat
</label>
<div className="col-span-2">
<Input
placeholder="Masukkan Alamat"
value={Alamat}
onChange={(e) =>
setAlamat(e.target.value)
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Telepon/Fax
</label>
<div className="col-span-2">
<Input
placeholder="Masukkan Telepon/Fax"
value={TeleponFax}
onChange={(e) =>
setTeleponFax(e.target.value)
}
/>
</div>
</div>
</div>
{/* Kolom Kanan */}
<div className="space-y-4">
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Email
</label>
<div className="col-span-2">
<Input
placeholder="Masukkan Email"
value={Email}
onChange={(e) =>
setEmail(e.target.value)
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Jenis Izin
</label>
<div className="col-span-2">
<Select
options={jenisIzinOptions}
value={selectedJenisIzin}
onChange={setSelectedJenisIzin}
placeholder="Pilih Jenis Izin"
isClearable
isSearchable
styles={selectStyles}
noOptionsMessage={() =>
"Tidak ada data"
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Nomor Izin
</label>
<div className="col-span-2">
<Input
placeholder="Masukkan Nomor Izin"
value={ILNomor}
onChange={(e) =>
setILNomor(e.target.value)
}
/>
</div>
</div>
<div className="grid grid-cols-3 items-center gap-4">
<label className="text-sm font-medium text-gray-700">
Rentang Tanggal Izin
</label>
<div className="col-span-2">
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className="w-full text-left"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{dateRange?.from
? dateRange.to
? `${format(
dateRange.from,
"dd/MM/yyyy"
)} - ${format(
dateRange.to,
"dd/MM/yyyy"
)}`
: format(
dateRange.from,
"dd/MM/yyyy"
)
: "Pilih Rentang Tanggal"}
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto p-0"
align="start"
>
<UIDatePicker
initialFocus
mode="range"
defaultMonth={dateRange?.from}
selected={dateRange}
onSelect={setDateRange}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</div>
<div className="flex justify-end mt-6 gap-2">
<Button
className="bg-green-600 hover:bg-green-700 text-white"
onClick={handleSearch}
>
<Search className="w-4 h-4 mr-2" />
Cari
</Button>
<Button
className="bg-gray-600 hover:bg-gray-700 text-white"
onClick={handleReset}
>
Reset
</Button>
</div>
</CardContent>
</Card>
</div>
);
}

View File

@ -0,0 +1,224 @@
import React, { useState } from "react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import Select from "react-select";
import { router } from "@inertiajs/react";
import { Perusahaan, JenisKegiatan } from "@/types/perusahaan";
type ModalIzinLingkunganProps = {
open: boolean;
onClose: () => void;
onSuccess: () => void;
selectedPerusahaan: Perusahaan | null;
jenisKegiatan: JenisKegiatan[]; // Ganti dari jenisDokIL menjadi jenisKegiatan
};
export function ModalIzinLingkungan({
open,
onClose,
onSuccess,
selectedPerusahaan,
jenisKegiatan,
}: ModalIzinLingkunganProps) {
if (!selectedPerusahaan) return null;
// State untuk field Nomor & Tanggal Izin Lingkungan (contoh)
const [nomorIzin, setNomorIzin] = useState(
selectedPerusahaan.ILNomor || ""
);
const [tanggalIzin, setTanggalIzin] = useState(
selectedPerusahaan.ILTanggal
? new Date(selectedPerusahaan.ILTanggal).toISOString().split("T")[0]
: ""
);
const [dokumen, setDokumen] = useState<File | null>(null);
// State untuk dropdown Jenis Kegiatan
// Jika perusahaan sudah memiliki jenis_kegiatan, kita set default-nya
const [selectedJenisKegiatan, setSelectedJenisKegiatan] = useState<{
value: number;
label: string;
} | null>(
selectedPerusahaan.jenis_kegiatan
? {
value: selectedPerusahaan.jenis_kegiatan.JenisKegiatanId,
label: selectedPerusahaan.jenis_kegiatan.NamaJenisKegiatan,
}
: null
);
// Konversi data jenisKegiatan agar bisa dibaca oleh react-select
const jenisKegiatanOptions = jenisKegiatan.map((jk) => ({
value: jk.JenisKegiatanId,
label: jk.NamaJenisKegiatan,
}));
// Handler submit form
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!selectedPerusahaan) return;
// Siapkan FormData untuk dikirim via Inertia
const formData = new FormData();
formData.append(
"PerusahaanId",
String(selectedPerusahaan.PerusahaanId)
);
formData.append("ILNomor", nomorIzin);
formData.append("ILTanggal", tanggalIzin);
// Ganti JenisDokILId -> JenisKegiatanId (sesuaikan dengan field di DB)
formData.append(
"JenisKegiatanId",
selectedJenisKegiatan?.value.toString() || ""
);
if (dokumen) {
formData.append("ILDokumen", dokumen);
}
router.post(
`/admin/perizinan_lingkungan/${selectedPerusahaan.PerusahaanId}`,
formData,
{
onSuccess: () => {
onSuccess(); // menutup modal & refresh data
},
}
);
};
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent className="max-w-xl max-h-[85vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Perizinan Lingkungan</DialogTitle>
</DialogHeader>
{/* Detail perusahaan */}
<div className="mb-4 p-4 bg-blue-100 rounded-md border border-gray-200">
<div className="grid grid-cols-2 gap-2 text-sm">
<div className="font-bold">No Induk:</div>
<div>{selectedPerusahaan.NomorInduk || "-"}</div>
<div className="font-bold">Perusahaan:</div>
<div>{selectedPerusahaan.NamaPerusahaan || "-"}</div>
<div className="font-bold">Jenis Kegiatan:</div>
<div>
{selectedPerusahaan.jenis_kegiatan
?.NamaJenisKegiatan || "-"}
</div>
<div className="font-bold">Alamat:</div>
<div>{selectedPerusahaan.Alamat || "-"}</div>
<div className="font-bold">Telepon:</div>
<div>{selectedPerusahaan.Telepon || "-"}</div>
<div className="font-bold">Fax:</div>
<div>{selectedPerusahaan.Fax || "-"}</div>
<div className="font-bold">Email:</div>
<div>{selectedPerusahaan.Email || "-"}</div>
</div>
</div>
{/* Form update dokumen izin */}
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
Nomor Izin Lingkungan
</label>
<Input
type="text"
value={nomorIzin}
onChange={(e) => setNomorIzin(e.target.value)}
/>
</div>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
Tanggal Izin
</label>
<Input
type="date"
value={tanggalIzin}
onChange={(e) => setTanggalIzin(e.target.value)}
/>
</div>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
Jenis Kegiatan
</label>
<Select
options={jenisKegiatanOptions}
value={selectedJenisKegiatan}
onChange={setSelectedJenisKegiatan}
placeholder="Pilih Jenis Kegiatan"
isClearable
isSearchable
/>
</div>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700">
Upload Dokumen
</label>
<Input
type="file"
onChange={(e) => {
if (
e.target.files &&
e.target.files.length > 0
) {
setDokumen(e.target.files[0]);
}
}}
/>
</div>
{selectedPerusahaan.ILDokumen && (
<div className="mb-4">
<Button
className="bg-green-100"
type="button"
variant="outline"
size="sm"
onClick={() =>
window.open(
`/storage/${selectedPerusahaan.ILDokumen}`,
"_blank"
)
}
>
Lihat File saat ini
</Button>
</div>
)}
<div className="flex justify-end mt-6">
<Button
variant="outline"
onClick={onClose}
className="mr-2"
>
Batal
</Button>
<Button
type="submit"
className="bg-green-600 text-white"
>
Simpan
</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
}

View File

@ -0,0 +1,32 @@
import React from "react";
import { Link } from "@inertiajs/react";
const Pagination = ({ links }) => {
return (
<nav
className="mb-sm-0 d-flex justify-content-center"
aria-label="navigation"
>
<ul className="pagination pagination-md pagination-primary-soft mb-0">
{/* Loop through the pagination links */}
{links.map((link, index) => (
<li
key={index}
className={`page-item ${link.active ? "active" : ""} ${
!link.url ? "disabled" : ""
}`}
>
<Link
href={link.url || "#"}
className="page-link"
tabIndex={!link.url ? "-1" : "0"}
dangerouslySetInnerHTML={{ __html: link.label }}
/>
</li>
))}
</ul>
</nav>
);
};
export default Pagination;

View File

@ -25,6 +25,7 @@ import {
} from "lucide-react";
import Select from "react-select";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
interface SKLData {
no: number;
@ -87,59 +88,76 @@ export default function PelaporanIndex() {
<div className="p-8">
{/* Filter Section */}
<div className="mb-6 space-y-4">
<div className="flex justify-between items-center">
<div className="flex gap-4 items-center">
<Select
options={companyOptions}
value={company}
onChange={setCompany}
placeholder="Pilih Perusahaan"
isSearchable
className="w-[300px]"
/>
<div className="bg-white rounded-lg shadow-sm mb-6">
<Card className="shadow-md border-slate-200 justify-between">
<CardHeader className="pb-3">
<CardTitle className="text-lg font-medium">
Pelaporan SKL
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-col md:flex-row md:justify-between md:items-center gap-4">
<div className="flex flex-col sm:flex-row gap-4 items-start sm:items-center w-full">
<Select
options={companyOptions}
value={company}
onChange={setCompany}
placeholder="Pilih Perusahaan"
isSearchable
className="w-full sm:w-[300px]"
/>
<Input
type="number"
value={year}
onChange={(e) => setYear(e.target.value)}
className="w-24"
/>
<div className="flex gap-4 w-full sm:w-auto">
<Input
type="number"
value={year}
onChange={(e) =>
setYear(e.target.value)
}
className="w-full sm:w-24"
/>
<Select
options={[
{
value: "Triwulan 1",
label: "Triwulan 1",
},
{
value: "Triwulan 2",
label: "Triwulan 2",
},
{
value: "Triwulan 3",
label: "Triwulan 3",
},
{
value: "Triwulan 4",
label: "Triwulan 4",
},
]}
value={{ value: quarter, label: quarter }}
onChange={(newValue) =>
setQuarter(newValue?.value || "Triwulan 1")
}
placeholder="Pilih Periode"
className="w-[150px]"
/>
<Select
options={[
{
value: "Triwulan 1",
label: "Triwulan 1",
},
{
value: "Triwulan 2",
label: "Triwulan 2",
},
{
value: "Triwulan 3",
label: "Triwulan 3",
},
{
value: "Triwulan 4",
label: "Triwulan 4",
},
]}
value={{
value: quarter,
label: quarter,
}}
onChange={(newValue) =>
setQuarter(
newValue?.value ||
"Triwulan 1"
)
}
placeholder="Pilih Periode"
className="w-full sm:w-[150px]"
/>
</div>
<Button>
<Search className="w-4 h-4 mr-2" />
Cari
</Button>
</div>
<Button className="w-full sm:w-auto">
<Search className="w-4 h-4 mr-2" />
Cari
</Button>
</div>
{/* <div className="flex gap-2">
{/* <div className="flex gap-2">
<Button variant="outline">
<Upload className="w-4 h-4 mr-2" />
Import
@ -153,7 +171,9 @@ export default function PelaporanIndex() {
Template
</Button>
</div> */}
</div>
</div>
</CardContent>
</Card>
</div>
{/* Table Section */}
@ -284,14 +304,14 @@ export default function PelaporanIndex() {
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-red-100 text-red-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-red-100 text-red-700"
>
00.00
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-red-100 text-red-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-red-100 text-red-700"
>
<Link href="/admin/pelaporan/al">
00.00
@ -300,37 +320,37 @@ export default function PelaporanIndex() {
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-red-100 text-red-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-red-100 text-red-700"
>
00.00
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-gray-100 text-gray-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-gray-100 text-gray-700"
>
76.70
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-gray-100 text-gray-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-gray-100 text-gray-700"
>
76.70
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-orange-100 text-orange-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-orange-100 text-orange-700"
>
76.70
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-green-100 text-green-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-green-100 text-green-700"
>
76.70
</TableCell>
<TableCell
colSpan={1}
className="text-center text-muted-foreground border-r border-l bg-green-100 text-green-700"
className="text-center hover:underline text-muted-foreground border-r border-l bg-green-100 text-green-700"
>
76.70
</TableCell>
@ -362,69 +382,69 @@ export default function PelaporanIndex() {
</div> */}
{/* Legend Section */}
<div className="mt-6 grid grid-cols-2 gap-6">
<div className="mt-6 flex flex-col md:grid md:grid-cols-2 gap-6">
{/* Keterangan Section */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="bg-white rounded-lg shadow-sm border p-4 md:p-6">
<div className="flex items-center gap-2 mb-4">
<FileText className="w-5 h-5 text-green-600" />
<h3 className="font-semibold text-lg">
Keterangan
</h3>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="space-y-2">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
SKL : Status Ketaatan Lingkungan
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
SPBM : Status Pemenuhan Baku Mutu
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
IL : Ijin Lingkungan
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">AL : Air Limbah</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">LB3 : Limbah B3</p>
</div>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
SB : Sumber Bergerak
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
BS : Kebisingan & Udara Ambien
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
STB : Sumber Tidak Bergerak
</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">LP : Limbah Padat</p>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
KDM : Kawasan Dilarang Merokok
</p>
@ -432,15 +452,15 @@ export default function PelaporanIndex() {
</div>
<div className="space-y-2 pt-3">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
STT : Surat Tanda Terima
</p>
</div>
</div>
<div className="space-y-2 pt-3">
<div className="space-y-2 pt-3">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"></div>
<div className="min-w-[8px] w-2 h-2 rounded-full bg-green-500"></div>
<p className="text-sm">
SE : Surat Evaluasi
</p>
@ -450,34 +470,34 @@ export default function PelaporanIndex() {
</div>
{/* Status Data Section */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="bg-white rounded-lg shadow-sm border p-4 md:p-6 mt-4 md:mt-0">
<div className="flex items-center gap-2 mb-4">
<BadgeCheck className="w-5 h-5 text-green-600" />
<h3 className="font-semibold text-lg">
Status Data
</h3>
</div>
<div className="space-y-4">
<div className="space-y-3">
<div className="flex items-center gap-3 p-2 rounded-md bg-red-100">
<div className="w-3 h-3 rounded-full bg-red-500"></div>
<div className="min-w-[12px] w-3 h-3 rounded-full bg-red-500"></div>
<p className="text-sm text-red-700">
Data belum diisi
</p>
</div>
<div className="flex items-center gap-3 p-2 rounded-md bg-gray-100">
<div className="w-3 h-3 rounded-full bg-gray-500"></div>
<div className="min-w-[12px] w-3 h-3 rounded-full bg-gray-500"></div>
<p className="text-sm text-gray-700">
Data telah diisi dan belum diverifikasi
</p>
</div>
<div className="flex items-center gap-3 p-2 rounded-md bg-orange-100">
<div className="w-3 h-3 rounded-full bg-orange-500"></div>
<div className="min-w-[12px] w-3 h-3 rounded-full bg-orange-500"></div>
<p className="text-sm text-orange-700">
Data telah siap untuk diverifikasi
</p>
</div>
<div className="flex items-center gap-3 p-2 rounded-md bg-green-100">
<div className="w-3 h-3 rounded-full bg-green-500"></div>
<div className="min-w-[12px] w-3 h-3 rounded-full bg-green-500"></div>
<p className="text-sm text-green-700">
Data telah diisi dan diverifikasi
</p>

View File

@ -1,5 +1,7 @@
<?php
use App\Http\Controllers\Admin\RoleController;
use App\Http\Controllers\Admin\RolesController;
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\DaftarPerusahaanController;
use App\Http\Controllers\HistoryKegiatanController;
@ -34,6 +36,9 @@ use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Illuminate\Http\Response;
use Spatie\Permission\Middleware\PermissionMiddleware;
use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\PerizinanLingkunganController;
Route::get('/', [HomeController::class, 'index'])->name('home');
@ -70,9 +75,23 @@ Route::get('/search', [SearchController::class, 'index'])->name('search');
// Dashboard Route
Route::get('/dashboard', function () {
return Inertia::render('dashboard');
})->middleware(['auth'])->name('dashboard');
// Route::get('/dashboard', function () {
// return Inertia::render('dashboard');
// })->middleware(['auth','permission:Dashboard.index' ])->name('dashboard');
Route::middleware(['auth', PermissionMiddleware::using('Dashboard.index')])->group(function () {
Route::get('/dashboard', DashboardController::class)->name('dashboard');
});
// buatkan route untuk view dashboard_other, tanpa auth dan middleware, jadi langsung nembak url
Route::get('/dashboard_other', function () {
return Inertia::render('dashboard_other');
})->name('dashboard_other');
Route::get('/dashboard_perusahaan', function () {
return Inertia::render('dashboard_perusahaan');
})->name('dashboard_perusahaan');
Route::middleware(['auth'])->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
@ -165,10 +184,11 @@ Route::middleware(['auth'])->prefix('admin')->group(function () {
Route::middleware(['auth'])->prefix('admin')->group(function () {
Route::get('/history_perusahaan', [HistoryPerusahaanController::class, 'index'])->name('admin.history_perusahaan.index');
Route::get('/history_perusahaan/add', [HistoryPerusahaanController::class, 'create'])->name('admin.history_perusahaan.create');
Route::post('/history_perusahaan', [HistoryPerusahaanController::class, 'store'])->name('admin.history_perusahaan.store');
Route::get('/history_perusahaan/{history_perusahaan}', [HistoryPerusahaanController::class, 'edit'])->name('admin.history_perusahaan.edit');
Route::post('/history_perusahaan/{history_perusahaan}', [HistoryPerusahaanController::class, 'update'])->name('admin.history_perusahaan.update');
Route::delete('/history_perusahaan/{history_perusahaan}', [HistoryPerusahaanController::class, 'destroy'])->name('admin.history_perusahaan.destroy');
Route::get('/history_perusahaan/detail/{perusahaanId}', [HistoryPerusahaanController::class, 'detail'])->name('admin.history_perusahaan.detail');
Route::post('/history_perusahaan/detail/{perusahaanId}/store', [HistoryPerusahaanController::class, 'store'])->name('admin.history_perusahaan.store');
});
Route::middleware(['auth'])->prefix('admin')->group(function () {
@ -189,4 +209,39 @@ Route::middleware(['auth'])->prefix('admin')->group(function () {
Route::delete('/perusahaan/{perusahaan}', [PerusahaanController::class, 'destroy'])->name('admin.perusahaan.destroy');
});
Route::middleware(['auth'])->prefix('admin')->group(function () {
Route::get('/perizinan_lingkungan', [PerizinanLingkunganController::class, 'index'])->name('admin.perizinan_lingkungan.index');
Route::post('/perizinan_lingkungan/{perusahaan}', [PerizinanLingkunganController::class, 'update'])->name('admin.perizinan_lingkungan.update');
});
// Route::middleware(['auth'])->prefix('admin')->name('admin.')->group(function () {
// Route::get('/roles', [RolesController::class, 'index'])->name('roles.index');
// Route::get('/roles/add', [RolesController::class, 'create'])->name('roles.create');
// Route::post('/roles', [RolesController::class, 'store'])->name('roles.store');
// Route::get('/roles/{role}', [RolesController::class, 'edit'])->name('roles.edit');
// Route::post('/roles/{role}', [RolesController::class, 'update'])->name('roles.update');
// Route::delete('/roles/{role}', [RolesController::class, 'destroy'])->name('roles.destroy');
// });
// Route::prefix('admin')->middleware(['auth'])->name('admin.')->group(function () {
// Route::get('/roles', \App\Http\Controllers\Admin\RoleController::class)->name('roles')->middleware('permission:Roles.index');
// $resources = [
// 'roles' => [
// 'controller' => \App\Http\Controllers\Admin\RoleController::class,
// 'permissions' => 'Roles.index',
// 'names' => 'Roles'
// ],
// ];
// foreach ($resources as $name => $resource) {
// $route = Route::resource($name, $resource['controller'])
// ->middleware("permission:{$resource['permissions']}");
// if (isset($resource['names'])) {
// $route->names($resource['names']);
// }
// }
// });
require __DIR__.'/auth.php';