style: Tambahkan beberapa icon baru dan perbaiki tata letak

main
marszayn 2025-03-03 11:52:06 +07:00
parent e37be6bc2d
commit 4ea83cf6b9
1 changed files with 519 additions and 144 deletions

View File

@ -11,7 +11,19 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { CircleHelp, FileDown, Printer } from "lucide-react"; import {
CircleHelp,
FileDown,
Printer,
ChevronLeft,
Upload,
PlusCircle,
CheckCircle2,
Clock,
AlertCircle,
ArrowUpRight,
Save,
} from "lucide-react";
import AuthenticatedLayout from "@/layouts/authenticated-layout"; import AuthenticatedLayout from "@/layouts/authenticated-layout";
import { Head } from "@inertiajs/react"; import { Head } from "@inertiajs/react";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
@ -21,6 +33,7 @@ import {
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import UploadDoc from "@/components/upload_doc"; import UploadDoc from "@/components/upload_doc";
import { Badge } from "@/components/ui/badge";
interface PelaporanALFormProps { interface PelaporanALFormProps {
onSubmit: (data: any) => void; onSubmit: (data: any) => void;
@ -31,36 +44,77 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false); const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
const [uploadedFile, setUploadedFile] = useState<File | null>(null); const [uploadedFile, setUploadedFile] = useState<File | null>(null);
// Mock data for uploaded files/attachments
const [attachments, setAttachments] = useState({
A6: { name: "hasil-uji-lab-q1-2025.pdf", status: "uploaded" },
A7: null,
A8: null,
A9: null,
A10: null,
});
const openAttachmentUpload = (itemCode: string) => {
// Implementation for attachment upload
console.log(`Opening upload for ${itemCode}`);
};
return ( return (
<AuthenticatedLayout header="Pelaporan Air Limbah"> <AuthenticatedLayout header="Pelaporan Air Limbah">
<Head title="Pelaporan Air Limbah" /> <Head title="Pelaporan Air Limbah" />
<div className="p-4 space-y-6"> <div className="p-4 space-y-6">
<Card className="shadow-lg"> <Card className="shadow-lg border-none">
<CardHeader className="bg-[#166534] text-white rounded-t-lg"> <CardHeader className="bg-gradient-to-r from-green-800 to-green-700 text-white rounded-t-lg">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div> <div>
<CardTitle className="text-xl"> <div className="flex items-center gap-2 mb-1">
Laporan Pengelolaan Air Limbah - Ujicoba <Badge className="bg-green-600">
Nama Perusahaan
</Badge>
</div>
<CardTitle className="text-xl font-bold">
Laporan Pengelolaan Air Limbah
</CardTitle> </CardTitle>
<p className="text-sm opacity-90"> <p className="text-sm opacity-90 mt-1">
Tahun 2025 - Periode Triwulan 1 Tahun 2025 - Periode Triwulan 1 (Januari -
Maret)
</p> </p>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
variant="secondary" variant="secondary"
size="sm" size="sm"
className="gap-1"
onClick={() => window.history.back()} onClick={() => window.history.back()}
> >
<ChevronLeft className="h-4 w-4" />
Kembali Kembali
</Button> </Button>
<Button <Button
variant="secondary" variant="secondary"
size="sm" size="sm"
onClick={() => window.print()} onClick={() => {
const style =
document.createElement("style");
style.innerHTML = `
@media print {
@page {
size: auto;
margin: 20mm;
}
body {
zoom: 0.5;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
}
`;
document.head.appendChild(style);
window.print();
document.head.removeChild(style);
}}
> >
<Printer /> <Printer className="h-4 w-4" />
</Button> </Button>
<Button <Button
variant="secondary" variant="secondary"
@ -69,74 +123,119 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
// Add PDF download logic here // Add PDF download logic here
}} }}
> >
<FileDown /> <FileDown className="h-4 w-4" />
</Button> </Button>
</div> </div>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="p-6"> <CardContent className="p-6">
<div className="space-y-6"> <div className="space-y-6">
{/* Header Section */} {/* Connection Status Card */}
<div className="flex justify-between items-center gap-4 mb-6"> <Card className="border shadow-sm">
<div className="flex items-center gap-2"> <CardContent className="p-4">
<h2>Tersambung IPAL Komunal:</h2> <div className="flex flex-wrap lg:flex-nowrap justify-between items-center gap-4">
<div className="flex flex-row gap-3"> <div>
<div className="flex items-center gap-2"> <h3 className="font-medium text-gray-900 mb-1">
<input Status Koneksi IPAL Komunal
type="radio" </h3>
id="tersambung" <p className="text-sm text-gray-500">
name="connection" Pilih status koneksi instalasi
className="w-4 h-4 text-teal-600" pengolahan air limbah
onChange={() => </p>
setIsConnected(true)
}
checked={isConnected === true}
/>
<Label htmlFor="tersambung">
Ya
</Label>
</div> </div>
<div className="flex items-center gap-2">
<input
type="radio"
id="tidak"
name="connection"
className="w-4 h-4 text-teal-600"
onChange={() =>
setIsConnected(false)
}
checked={isConnected === false}
/>
<Label htmlFor="tidak">Tidak</Label>
</div>
</div>
</div>
<div> <div className="flex items-center gap-6">
{isConnected && ( <div className="flex items-center gap-2">
<div className="flex items-center gap-2"> <input
<h2> type="radio"
Lampiran id="tersambung"
<span className="text-red-600"> name="connection"
* className="w-4 h-4 text-green-600 focus:ring-green-500"
</span>{" "} onChange={() =>
: setIsConnected(true)
</h2> }
<Button checked={
variant="outline" isConnected === true
className="w-48" }
onClick={() => />
setIsUploadModalOpen(true) <Label
} htmlFor="tersambung"
> className="font-medium"
{uploadedFile >
? uploadedFile.name Tersambung
: "Unggah Surat Kerjasama"} </Label>
</Button> </div>
<div className="flex items-center gap-2">
<input
type="radio"
id="tidak"
name="connection"
className="w-4 h-4 text-green-600 focus:ring-green-500"
onChange={() =>
setIsConnected(false)
}
checked={
isConnected === false ||
isConnected === null
}
/>
<Label
htmlFor="tidak"
className="font-medium"
>
Tidak Tersambung
</Label>
</div>
</div> </div>
)}
</div> {isConnected && (
</div> <div className="flex items-center gap-2 bg-green-50 p-3 rounded-lg border border-green-200">
<Upload className="h-4 w-4 text-green-600" />
<span className="text-sm font-medium text-green-800">
Lampiran Wajib
<span className="text-red-600 ml-1">
*
</span>
:
</span>
<Button
variant="outline"
size="sm"
className={`ml-2 ${
uploadedFile
? "bg-green-50 text-green-700 border-green-300"
: ""
}`}
onClick={() =>
setIsUploadModalOpen(
true
)
}
>
{uploadedFile ? (
<div className="flex items-center gap-2">
<CheckCircle2 className="h-4 w-4 text-green-600" />
<span className="truncate max-w-36">
{
uploadedFile.name
}
</span>
</div>
) : (
<div className="flex items-center gap-2">
<PlusCircle className="h-4 w-4" />
<span>
Unggah Surat
Kerjasama
</span>
</div>
)}
</Button>
</div>
)}
</div>
</CardContent>
</Card>
<UploadDoc <UploadDoc
isOpen={isUploadModalOpen} isOpen={isUploadModalOpen}
@ -149,10 +248,10 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
/> />
{/* Main Form Table */} {/* Main Form Table */}
<div className="border rounded-lg overflow-hidden"> <div className="border rounded-lg overflow-hidden shadow-sm">
<table className="w-full"> <table className="w-full">
<thead> <thead>
<tr className="bg-[#166534] text-white"> <tr className="bg-gradient-to-r from-green-800 to-green-700 text-white">
<th className="p-3 text-left w-16"> <th className="p-3 text-left w-16">
No No
</th> </th>
@ -178,7 +277,7 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
</thead> </thead>
<tbody> <tbody>
{/* Section 1 */} {/* Section 1 */}
<tr className="bg-teal-50"> <tr className="bg-green-50">
<td className="p-3">I</td> <td className="p-3">I</td>
<td <td
className="p-3 font-medium" className="p-3 font-medium"
@ -189,47 +288,74 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
(%) (%)
</td> </td>
<td className="p-3"></td> <td className="p-3"></td>
<td className="p-3">100</td> <td className="p-3">
<span className="font-semibold text-green-700">
100
</span>
</td>
<td className="p-3"></td> <td className="p-3"></td>
<td className="p-3"></td> <td className="p-3"></td>
<td className="p-3"></td> <td className="p-3"></td>
</tr> </tr>
{/* Technical Requirements */} {/* Technical Requirements Section Header */}
<tr className="bg-gray-100">
<td className="p-3"></td>
<td
className="p-3 font-semibold text-gray-700"
colSpan={6}
>
1. Persyaratan Teknis
</td>
</tr>
{/* Technical Requirements A1-A5 */}
{[ {[
"Instalasi pengolah air limbah", "Instalasi pengolah air limbah",
"Flowmeter", "Flowmeter",
"Titik pengambilan sampel", "Titik pengambilan sampel",
"Saluran air limbah & air hujan terpisah", "Saluran air limbah & air hujan terpisah",
"Izin pembuangan air limbah", // "Izin pembuangan air limbah",
].map((item, index) => ( ].map((item, index) => (
<tr <tr
key={index} key={index}
className="border-t" className="border-t hover:bg-gray-50"
> >
<td className="p-3"> <td className="p-3 font-medium">
A{index + 1} A{index + 1}
</td> </td>
<td className="p-3"> <td className="p-3">
<div className="flex justify-between items-center w-full"> <div className="flex justify-between items-center w-full">
<div>{item}</div> <div className="text-gray-800">
{item}
</div>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<CircleHelp className="text-teal-600 w-5 h-5" /> <CircleHelp className="text-green-600 w-5 h-5" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent className="bg-white p-3 rounded-lg shadow-lg border max-w-sm">
<p> <h4 className="font-medium text-green-700 mb-1">
{item}
</h4>
<p className="text-sm text-gray-600">
Deskripsi Deskripsi
untuk {item} persyaratan
teknis untuk{" "}
{item.toLowerCase()}
. Pastikan
data yang
diisi sesuai
dengan
kondisi
aktual.
</p> </p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</div> </div>
</td> </td>
<td className="p-3"> <td className="p-3">
{" "}
<Select> <Select>
<SelectTrigger className="w-24"> <SelectTrigger className="w-28 border-gray-300">
<SelectValue placeholder="Ada" /> <SelectValue placeholder="Ada" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -242,52 +368,95 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
</SelectContent> </SelectContent>
</Select> </Select>
</td> </td>
<td className="p-3">100</td> <td className="p-3 font-medium">
<td className="p-3"></td> 100
<td className="p-3"></td> </td>
<td className="p-3"></td> <td className="p-3">
<Button
variant="ghost"
size="sm"
className="flex items-center gap-1 text-green-700 hover:bg-green-50 hover:text-green-800"
onClick={() =>
openAttachmentUpload(
`A${index + 1}`
)
}
>
<Upload className="h-4 w-4" />
<span>Unggah</span>
</Button>
</td>
<td className="p-3">
<Badge
variant="outline"
className="bg-amber-50 text-amber-700 border-amber-200"
>
<Clock className="h-3 w-3 mr-1" />
Menunggu
</Badge>
</td>
</tr> </tr>
))} ))}
{/* Implementation Section */} {/* Implementation Section Header */}
<tr className="bg-gray-100">
<td className="p-3"></td>
<td
className="p-3 font-semibold text-gray-700"
colSpan={6}
>
2. Perijinan
</td>
</tr>
{/* Implementation Section A6-A10 */}
{[ {[
{ {
name: "Pengujian air limbah", code: "A5",
hasAttachment: true, name: "Izin pembuangan air limbah",
},
{
name: "Pemenuhan baku mutu air limbah",
hasAttachment: false, hasAttachment: false,
}, },
{ ].map((item) => (
name: "Pelaksanaan dan pemutusan wewenang",
hasSelect: true,
},
{
name: "Pembuatan neraca air",
hasSelect: true,
},
{
name: "Sertifikasi kompetensi",
hasSelect: true,
},
].map((item, index) => (
<tr <tr
key={index} key={item.code}
className="border-t" className="border-t hover:bg-gray-50"
> >
<td className="p-3"> <td className="p-3 font-medium">
A{index + 6} {item.code}
</td> </td>
<td className="p-3"> <td className="p-3">
<div className="flex justify-between items-center w-full"> <div className="flex justify-between items-center w-full">
<div>{item.name}</div> <div className="text-gray-800">
<CircleHelp className="text-teal-600 w-5 h-5" /> {item.name}
</div>
<Tooltip>
<TooltipTrigger>
<CircleHelp className="text-green-600 w-5 h-5" />
</TooltipTrigger>
<TooltipContent className="bg-white p-3 rounded-lg shadow-lg border max-w-sm">
<h4 className="font-medium text-green-700 mb-1">
Info:{" "}
{item.name}
</h4>
<p className="text-sm text-gray-600">
Deskripsi
untuk
persyaratan{" "}
{item.name.toLowerCase()}
. Pastikan
data yang
diisi sesuai
dengan
dokumen
pendukung.
</p>
</TooltipContent>
</Tooltip>
</div> </div>
</td> </td>
<td className="p-3"> <td className="p-3">
<Select> <Select>
<SelectTrigger className="w-24"> <SelectTrigger className="w-28 border-gray-300">
<SelectValue placeholder="Ada" /> <SelectValue placeholder="Ada" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@ -300,16 +469,206 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
</SelectContent> </SelectContent>
</Select> </Select>
</td> </td>
<td className="p-3">100</td> <td className="p-3 font-medium">
100
</td>
<td className="p-3"> <td className="p-3">
{item.hasAttachment && ( {attachments[
<span className="text-teal-600"> item.code as keyof typeof attachments
Data... ] ? (
</span> <Button
variant="ghost"
size="sm"
className="flex items-center gap-1 text-green-700 bg-green-50 hover:bg-green-100"
>
<CheckCircle2 className="h-4 w-4" />
<span className="truncate max-w-24">
{
attachments[
item.code as keyof typeof attachments
]?.name
}
</span>
</Button>
) : (
<Button
variant="ghost"
size="sm"
className="flex items-center gap-1 text-green-700 hover:bg-green-50 hover:text-green-800"
onClick={() =>
openAttachmentUpload(
item.code
)
}
>
<Upload className="h-4 w-4" />
<span>Data...</span>
</Button>
)}
</td>
<td className="p-3">
{item.code === "A6" ? (
<Badge className="bg-green-100 text-green-700 border-none">
<CheckCircle2 className="h-3 w-3 mr-1" />
Terverifikasi
</Badge>
) : (
<Badge
variant="outline"
className="bg-amber-50 text-amber-700 border-amber-200"
>
<Clock className="h-3 w-3 mr-1" />
Menunggu
</Badge>
)}
</td>
</tr>
))}
{/* Implementation Section Header */}
<tr className="bg-gray-100">
<td className="p-3"></td>
<td
className="p-3 font-semibold text-gray-700"
colSpan={6}
>
3. Pelaksanaan
</td>
</tr>
{/* Implementation Section A6-A10 */}
{[
{
code: "A6",
name: "Pengujian air limbah",
hasAttachment: true,
},
{
code: "A7",
name: "Pemenuhan baku mutu air limbah",
hasAttachment: true,
},
{
code: "A8",
name: "Pelaksanaan dan pemutusan wewenang",
hasAttachment: true,
},
{
code: "A9",
name: "Pembuatan neraca air",
hasAttachment: true,
},
{
code: "A10",
name: "Sertifikasi kompetensi",
hasAttachment: true,
},
].map((item) => (
<tr
key={item.code}
className="border-t hover:bg-gray-50"
>
<td className="p-3 font-medium">
{item.code}
</td>
<td className="p-3">
<div className="flex justify-between items-center w-full">
<div className="text-gray-800">
{item.name}
</div>
<Tooltip>
<TooltipTrigger>
<CircleHelp className="text-green-600 w-5 h-5" />
</TooltipTrigger>
<TooltipContent className="bg-white p-3 rounded-lg shadow-lg border max-w-sm">
<h4 className="font-medium text-green-700 mb-1">
Info:{" "}
{item.name}
</h4>
<p className="text-sm text-gray-600">
Deskripsi
untuk
persyaratan{" "}
{item.name.toLowerCase()}
. Pastikan
data yang
diisi sesuai
dengan
dokumen
pendukung.
</p>
</TooltipContent>
</Tooltip>
</div>
</td>
<td className="p-3">
<Select>
<SelectTrigger className="w-28 border-gray-300">
<SelectValue placeholder="Ada" />
</SelectTrigger>
<SelectContent>
<SelectItem value="ada">
Ada
</SelectItem>
<SelectItem value="tidak">
Tidak Ada
</SelectItem>
</SelectContent>
</Select>
</td>
<td className="p-3 font-medium">
100
</td>
<td className="p-3">
{attachments[
item.code as keyof typeof attachments
] ? (
<Button
variant="ghost"
size="sm"
className="flex items-center gap-1 text-green-700 bg-green-50 hover:bg-green-100"
>
<CheckCircle2 className="h-4 w-4" />
<span className="truncate max-w-24">
{
attachments[
item.code as keyof typeof attachments
]?.name
}
</span>
</Button>
) : (
<Button
variant="ghost"
size="sm"
className="flex items-center gap-1 text-green-700 hover:bg-green-50 hover:text-green-800"
onClick={() =>
openAttachmentUpload(
item.code
)
}
>
<Upload className="h-4 w-4" />
<span>Data...</span>
</Button>
)}
</td>
<td className="p-3">
{item.code === "A6" ? (
<Badge className="bg-green-100 text-green-700 border-none">
<CheckCircle2 className="h-3 w-3 mr-1" />
Terverifikasi
</Badge>
) : (
<Badge
variant="outline"
className="bg-amber-50 text-amber-700 border-amber-200"
>
<Clock className="h-3 w-3 mr-1" />
Menunggu
</Badge>
)} )}
</td> </td>
<td className="p-3"></td>
<td className="p-3"></td>
</tr> </tr>
))} ))}
</tbody> </tbody>
@ -317,41 +676,57 @@ const PelaporanALForm = ({ onSubmit }: PelaporanALFormProps) => {
</div> </div>
{/* Notes Section */} {/* Notes Section */}
<div className="bg-gray-50 p-6 rounded-lg border border-gray-200 mt-6"> <Card className="border shadow-sm">
<h2 className="text-lg font-semibold mb-3 text-gray-800"> <CardContent className="p-5">
Catatan <h2 className="text-lg font-semibold mb-3 text-gray-800 flex items-center gap-2">
</h2> <span>Catatan</span>
<Textarea {/* <span className="text-sm font-normal text-gray-500">
placeholder="Tambahkan catatan atau komentar tambahan di sini..." (Opsional)
className="min-h-[100px] bg-white" </span> */}
/> </h2>
</div> <Textarea
placeholder="Tambahkan catatan atau komentar tambahan di sini..."
className="min-h-[100px] bg-white border-gray-300 focus:border-green-500 focus:ring-green-500"
/>
</CardContent>
</Card>
{/* Agreement & Submit Section */} {/* Agreement & Submit Section */}
<div className="mt-8 space-y-6"> <div className="mt-8 space-y-6">
<div className="flex items-start gap-3 p-4 bg-green-50 rounded-lg border border-teal-200"> <div className="flex items-start gap-3 p-4 bg-green-50 rounded-lg border border-green-200">
<Checkbox id="agreement" className="mt-1" /> <Checkbox
<Label id="agreement"
htmlFor="agreement" className="mt-1 text-green-600 focus:ring-green-500"
className="text-sm leading-relaxed text-gray-700" />
> <div>
Dengan mencentang ini, kami menyatakan <Label
bahwa laporan ini telah disusun htmlFor="agreement"
berdasarkan ketentuan peraturan yang className="text-sm font-medium text-gray-800"
berlaku dan kami bersedia bertanggung >
jawab atas kebenaran data-data yang kami Pernyataan Kebenaran Data
kirimkan sesuai dengan fakta dilapangan. </Label>
</Label> <p className="text-sm leading-relaxed text-gray-700 mt-1">
Kami menyatakan bahwa laporan ini
telah disusun berdasarkan ketentuan
peraturan yang berlaku dan kami
bersedia bertanggung jawab atas
kebenaran data-data yang kami
kirimkan sesuai dengan fakta
dilapangan.
</p>
</div>
</div> </div>
<div className="flex justify-end gap-4"> <div className="flex justify-end gap-4">
<Button <Button
variant="outline" variant="outline"
className="hover:bg-gray-100" className="hover:bg-gray-100 gap-2"
> >
<Save className="h-4 w-4" />
Simpan Draft Simpan Draft
</Button> </Button>
<Button className="bg-[#166534] hover:bg-green-700 transition-colors px-8"> <Button className="bg-green-800 hover:bg-green-700 transition-colors px-8 gap-2">
<ArrowUpRight className="h-4 w-4" />
Kirim Laporan Kirim Laporan
</Button> </Button>
</div> </div>