skl/resources/js/components/AL/ALTable.tsx

417 lines
19 KiB
TypeScript

import React from "react";
import { Button } from "@/components/ui/button";
import {
Tooltip,
TooltipTrigger,
TooltipContent,
} from "@/components/ui/tooltip";
import { CircleHelp } from "lucide-react";
import {
Select,
SelectTrigger,
SelectContent,
SelectItem,
SelectValue,
} from "@/components/ui/select";
interface KomponenData {
id: number;
nama: string;
kode: string;
nilai: number;
hasil?: {
id: number;
nama: string;
nilai: number;
}[];
nama_refhasil?: string;
verifikasi?: boolean;
keterangan?: string;
lampiran?: boolean;
}
interface JenisData {
nama: string;
komponen: Record<string, KomponenData>;
}
interface ALTableProps {
dataTable: Record<string, JenisData>;
nilaiKomponen: Record<string, any>;
nilaiSyaratTeknis: Record<string, number>;
nilai_A6: number;
nilai_A7: number;
idmcpelaporan: number;
idrefpelaporan: number;
rowspan_1: number;
spl: number;
spl_2: number;
editable: boolean;
onUpdateNilai: (kode: string, nilai: number) => void;
onOpenLampiranModal: (kode: string, idrefkomponen: number) => void;
onOpenSplModal: () => void;
}
const ALTable: React.FC<ALTableProps> = ({
dataTable,
nilaiKomponen,
nilaiSyaratTeknis,
nilai_A6,
nilai_A7,
idmcpelaporan,
idrefpelaporan,
rowspan_1,
spl,
spl_2,
editable,
onUpdateNilai,
onOpenLampiranModal,
onOpenSplModal,
}) => {
const [sklNilai, setSklNilai] = React.useState<number>(0);
const komponenHide = ["A1", "A2", "A3", "A4", "A5"];
const daftarNilai = React.useRef<Record<string, number>>({});
React.useEffect(() => {
// Initialize daftarNilai
const nilai: Record<string, number> = {};
Object.entries(dataTable).forEach(([_noJenis, jenis]) => {
Object.entries(jenis.komponen).forEach(
([kodeKomponen, komponen]) => {
if (kodeKomponen !== "SK") {
if (komponenHide.includes(kodeKomponen)) {
nilai[kodeKomponen.toLowerCase()] = parseFloat(
nilaiSyaratTeknis[kodeKomponen].toFixed(2)
);
} else if (kodeKomponen === "A6") {
nilai[kodeKomponen.toLowerCase()] = parseFloat(
nilai_A6.toFixed(2)
);
} else if (kodeKomponen === "A7") {
nilai[kodeKomponen.toLowerCase()] = parseFloat(
nilai_A7.toFixed(2)
);
} else {
const val = nilaiKomponen[kodeKomponen];
nilai[kodeKomponen.toLowerCase()] = val
? parseFloat(val.nilai)
: 0;
}
}
}
);
});
daftarNilai.current = nilai;
calculateSklNilai();
}, [dataTable, nilaiKomponen, nilaiSyaratTeknis, nilai_A6, nilai_A7]);
const calculateSklNilai = () => {
const kelompok1 = ["a1", "a2", "a3", "a4"];
const kelompok2 = ["a5"];
const kelompok3 = ["a6", "a7", "a8", "a9", "a10"];
let total1 = 0;
let total2 = 0;
let total3 = 0;
for (const [key, value] of Object.entries(daftarNilai.current)) {
if (typeof value === "number") {
if (kelompok1.includes(key)) {
total1 += value;
} else if (kelompok2.includes(key)) {
total2 += value;
} else if (kelompok3.includes(key)) {
total3 += value;
}
}
}
const newSklNilai =
(15 * (total1 / kelompok1.length)) / 100 +
(15 * (total2 / kelompok2.length)) / 100 +
(70 * (total3 / kelompok3.length)) / 100;
setSklNilai(parseFloat(newSklNilai.toFixed(2)));
};
const handleHasilChange = (komponen: KomponenData, hasilId: number) => {
if (!editable) return;
const hasil = komponen.hasil?.find(
(h) => h.id === parseInt(hasilId.toString())
);
if (hasil) {
daftarNilai.current[komponen.kode.toLowerCase()] = hasil.nilai;
onUpdateNilai(komponen.kode, hasil.nilai);
calculateSklNilai();
}
};
return (
<table className="w-full border-collapse text-sm">
<thead>
<tr className="bg-gray-100">
<th className="border border-gray-300 p-2 text-center">
No
</th>
<th className="border border-gray-300 p-2 text-center">
Komponen
</th>
<th className="border border-gray-300 p-2 text-center">
Hasil
</th>
<th className="border border-gray-300 p-2 text-center">
Nilai
</th>
<th className="border border-gray-300 p-2 text-center">
Lampiran
</th>
<th className="border border-gray-300 p-2 text-center">
Verifikasi
</th>
<th className="border border-gray-300 p-2 text-center">
Keterangan
</th>
</tr>
</thead>
<tbody>
<tr>
<td
rowSpan={rowspan_1}
className="border border-gray-300 p-2 text-center"
>
<strong>I</strong>
</td>
<td colSpan={2} className="border border-gray-300 p-2">
<strong>
Nilai tingkat ketaatan pengelolaan air limbah (SKL
<sub>AL</sub>) (%)
</strong>
<input
type="hidden"
name="skl-nilai"
id="skl"
value={sklNilai}
/>
</td>
<td
id="skl-nilai"
className="border border-gray-300 p-2 text-right font-bold"
>
{sklNilai}
</td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
</tr>
{Object.entries(dataTable).map(([noJenis, jenis]) => (
<React.Fragment key={noJenis}>
{noJenis && (
<tr>
<td
colSpan={2}
className="border border-gray-300 p-2"
>
{noJenis}. {jenis.nama}
</td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
</tr>
)}
{Object.entries(jenis.komponen).map(
([kodeKomponen, komponen]) =>
kodeKomponen !== "SK" && (
<tr key={kodeKomponen}>
<td className="border border-gray-300 p-2 pl-[3%]">
{kodeKomponen}. {komponen.nama}
</td>
{/* Kolom Hasil */}
<td className="border border-gray-300 p-2">
{komponen.hasil &&
!komponenHide.includes(
kodeKomponen
) ? (
<Select
value={
nilaiKomponen[
kodeKomponen
]?.nilai?.toString() ||
"0"
}
disabled={
!editable ||
daftarNilai.current[
kodeKomponen.toLowerCase()
] === undefined
}
onValueChange={(value) => {
const selectedHasil =
komponen.hasil?.find(
(h) =>
h.nilai.toString() ===
value
);
if (selectedHasil) {
handleHasilChange(
komponen,
selectedHasil.id
);
}
}}
>
<SelectTrigger
className="w-full"
data-komponen={kodeKomponen.toLowerCase()}
>
<SelectValue placeholder="Pilih hasil" />
</SelectTrigger>
<SelectContent>
{komponen.hasil.map(
(hasil) => (
<SelectItem
key={
hasil.id
}
value={hasil.nilai.toString()}
data-nilai={
hasil.nilai
}
>
{hasil.nama}
</SelectItem>
)
)}
</SelectContent>
</Select>
) : null}
</td>
{/* Kolom Nilai */}
<td
className="border border-gray-300 p-2 text-right nilai-komponen"
id={`${kodeKomponen.toLowerCase()}-nilai`}
data-komponen={kodeKomponen.toLowerCase()}
>
{komponenHide.includes(kodeKomponen)
? parseFloat(
(
nilaiSyaratTeknis[
kodeKomponen
] || 0
).toFixed(2)
)
: kodeKomponen === "A6"
? parseFloat(
nilai_A6.toFixed(2)
)
: kodeKomponen === "A7"
? parseFloat(
nilai_A7.toFixed(2)
)
: nilaiKomponen[kodeKomponen]
? nilaiKomponen[kodeKomponen]
.nilai
: 0}
</td>
{/* Kolom Lampiran */}
<td className="border border-gray-300 p-2 text-center">
{komponen.lampiran &&
!komponenHide.includes(
kodeKomponen
) && (
<button
onClick={() =>
onOpenLampiranModal(
kodeKomponen,
komponen.id
)
}
className="text-blue-600 hover:text-blue-800 hover:underline"
disabled={!editable}
>
{kodeKomponen === "A6"
? "Data..."
: "Lampiran"}
</button>
)}
</td>
{/* Kolom Verifikasi */}
<td
className="border border-gray-300 p-2 verifikasi"
data-komponen={kodeKomponen}
>
{!komponenHide.includes(
kodeKomponen
) &&
nilaiKomponen[kodeKomponen]
?.verifikasi !==
undefined &&
(nilaiKomponen[kodeKomponen]
?.verifikasi ? (
<span className="text-green-600">
Approved
</span>
) : (
<span className="text-red-600">
Not Approved
</span>
))}
</td>
{/* Kolom Keterangan */}
<td className="border border-gray-300 p-2">
{!komponenHide.includes(
kodeKomponen
) &&
nilaiKomponen[kodeKomponen]
?.keterangan}
</td>
</tr>
)
)}
</React.Fragment>
))}
<tr>
<td className="border border-gray-300 p-2 text-center">
<strong>II</strong>
</td>
<td colSpan={2} className="border border-gray-300 p-2">
<strong>
Nilai tingkat pemenuhan baku mutu air limbah{" "}
<sup>*</sup> (SPBM<sub>AL</sub>) (%)
</strong>
</td>
<td
id="nilai-spl"
data-spl2={spl_2}
className="border border-gray-300 p-2 text-right font-bold"
>
{parseFloat(spl.toString())}
</td>
<td className="border border-gray-300 p-2 text-center">
<button
onClick={onOpenSplModal}
className="text-blue-600 hover:text-blue-800 hover:underline spl-link-modal"
data-id={idmcpelaporan}
disabled={!editable}
>
Data...
</button>
</td>
<td className="border border-gray-300 p-2"></td>
<td className="border border-gray-300 p-2"></td>
</tr>
</tbody>
</table>
);
};
export default ALTable;