update : image detail approval

This commit is contained in:
hanif salafi 2025-08-21 10:38:38 +07:00
parent 9fc973d151
commit 82bf3a8709
1 changed files with 313 additions and 83 deletions

View File

@ -171,11 +171,16 @@ export default function FormImageDetail() {
satker: false,
});
const [isLoading, setIsLoading] = useState(false);
const [checkedLevels, setCheckedLevels] = useState<any>(new Set());
const [checkedLevels, setCheckedLevels] = useState<Set<number>>(new Set());
const [selectedTarget, setSelectedTarget] = useState("");
const [files, setFiles] = useState<FileType[]>([]);
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
const [expandedPolda, setExpandedPolda] = useState([{}]);
const [expandedPolda, setExpandedPolda] = useState<Record<number, boolean>>({});
// State untuk melacak apakah perubahan berasal dari checkbox utama
const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] = useState(false);
// State untuk melacak jenis perubahan spesifik
const [mainCheckboxChangeType, setMainCheckboxChangeType] = useState<string>("");
const [wilayahPublish, setWilayahPublish] = React.useState({
semua: false,
nasional: false,
@ -240,30 +245,175 @@ export default function FormImageDetail() {
fetchPoldaPolres();
}, []);
// useEffect untuk sinkronisasi checkbox modal dengan checkbox utama
useEffect(() => {
const updated = new Set(checkedLevels);
if (listDest.length > 0 && isUpdatingFromMainCheckbox && mainCheckboxChangeType) {
syncModalWithMainCheckbox();
}
}, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]);
if (unitSelection.polda) {
listDest.forEach((polda) => {
updated.add(polda.id); // hanya id polda
// useEffect untuk update checkbox utama ketika pilihan modal berubah
useEffect(() => {
if (!isUpdatingFromMainCheckbox && listDest.length > 0) {
updateMainCheckboxFromModal();
}
}, [checkedLevels, isUpdatingFromMainCheckbox]);
// Fungsi untuk update checkbox utama berdasarkan checkbox modal
const updateMainCheckboxFromModal = () => {
if (!isUpdatingFromMainCheckbox && listDest.length > 0) {
// Hitung item yang dipilih berdasarkan checkedLevels
const checkedPoldaCount = listDest.filter((item: any) =>
item.levelNumber === 2 &&
item.name !== "SATKER POLRI" &&
checkedLevels.has(Number(item.id))
).length;
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
if (item.subDestination && item.name !== "SATKER POLRI") {
// Hanya hitung sub-item dari POLDA (bukan dari SATKER POLRI)
return total + item.subDestination.filter((sub: any) => checkedLevels.has(Number(sub.id))).length;
}
return total;
}, 0);
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
const checkedSatkerCount = satkerItem ? (
(checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) +
(satkerItem.subDestination?.filter((sub: any) => checkedLevels.has(Number(sub.id))).length || 0)
) : 0;
// Checkbox aktif jika ADA item yang dipilih dalam kategori tersebut
const hasSelectedPolda = checkedPoldaCount > 0;
const hasSelectedPolres = checkedPolresCount > 0;
const hasSelectedSatker = checkedSatkerCount > 0;
// Update unitSelection berdasarkan yang dipilih di modal
setUnitSelection(prev => {
const newState = { ...prev };
// Update individual checkboxes
newState.polda = hasSelectedPolda;
newState.polres = hasSelectedPolres;
newState.satker = hasSelectedSatker;
// Update checkbox "semua" berdasarkan semua checkbox yang aktif
newState.semua = newState.nasional && newState.wilayah && newState.international && hasSelectedPolda && hasSelectedPolres && hasSelectedSatker;
return newState;
});
}
};
if (unitSelection.polres) {
listDest.forEach((polda) => {
polda?.subDestination?.forEach((polres: any) => {
updated.add(polres.id); // hanya id polres
// Fungsi untuk sinkronisasi checkbox modal dengan checkbox utama
const syncModalWithMainCheckbox = () => {
if (isUpdatingFromMainCheckbox) {
const newCheckedLevels = new Set(checkedLevels);
// Handle checklist actions - menambahkan semua item ke modal
if (mainCheckboxChangeType === "polda_checked") {
// Checklist semua polda
listDest.forEach((item: any) => {
if (item.levelNumber === 2 && item.name !== "SATKER POLRI") {
newCheckedLevels.add(Number(item.id));
}
});
} else if (mainCheckboxChangeType === "polres_checked") {
// Checklist semua polres, tapi hanya yang poldanya sudah di-checklist
// Jangan checklist sub-item SATKER POLRI
listDest.forEach((item: any) => {
if (item.levelNumber === 2 && item.name !== "SATKER POLRI" && newCheckedLevels.has(Number(item.id))) {
if (item.subDestination) {
item.subDestination.forEach((polres: any) => {
newCheckedLevels.add(Number(polres.id));
});
}
}
});
setCheckedLevels(updated);
}, [unitSelection.polda, unitSelection.polres, listDest]);
// Tidak perlu menghapus SATKER ketika POLRES di-checklist
// Biarkan keduanya bisa aktif bersamaan
// SATKER dan POLRES adalah konsep yang berbeda:
// - SATKER: unit-unit seperti ITWASUM, BAINTELKAM, dll.
// - POLRES: unit-unit seperti POLRES METRO JAKARTA PUSAT, dll.
} else if (mainCheckboxChangeType === "satker_checked") {
// Checklist satker
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
if (satkerItem) {
newCheckedLevels.add(Number(satkerItem.id));
// Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES)
if (satkerItem.subDestination) {
satkerItem.subDestination.forEach((sub: any) => {
newCheckedLevels.add(Number(sub.id));
});
}
}
} else if (mainCheckboxChangeType === "semua_checked") {
// Checklist semua item
listDest.forEach((item: any) => {
newCheckedLevels.add(Number(item.id));
// Checklist semua sub-item di bawah setiap item
if (item.subDestination) {
item.subDestination.forEach((sub: any) => {
newCheckedLevels.add(Number(sub.id));
});
}
});
}
// Handle unchecklist actions - menghapus item dari modal
else if (mainCheckboxChangeType === "polres_unchecked") {
// Clear polres dari checkedLevels, tapi jangan hapus sub-item SATKER POLRI
listDest.forEach((item: any) => {
if (item.subDestination && item.name !== "SATKER POLRI") {
item.subDestination.forEach((polres: any) => {
newCheckedLevels.delete(Number(polres.id));
});
}
});
} else if (mainCheckboxChangeType === "polda_unchecked") {
// Clear polda dan polres dari checkedLevels, tapi jangan hapus SATKER POLRI
listDest.forEach((item: any) => {
if (item.levelNumber === 2 && item.name !== "SATKER POLRI") {
newCheckedLevels.delete(Number(item.id));
if (item.subDestination) {
item.subDestination.forEach((polres: any) => {
newCheckedLevels.delete(Number(polres.id));
});
}
}
});
} else if (mainCheckboxChangeType === "satker_unchecked") {
// Clear satker dan semua sub-item di bawahnya dari checkedLevels
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
if (satkerItem) {
newCheckedLevels.delete(Number(satkerItem.id));
if (satkerItem.subDestination) {
satkerItem.subDestination.forEach((sub: any) => {
newCheckedLevels.delete(Number(sub.id));
});
}
}
} else if (mainCheckboxChangeType === "semua_unchecked") {
// Clear semua
newCheckedLevels.clear();
}
setCheckedLevels(newCheckedLevels);
// Reset flag setelah sinkronisasi selesai
setIsUpdatingFromMainCheckbox(false);
setMainCheckboxChangeType("");
}
};
const handleUnitChange = (
key: keyof typeof unitSelection,
value: boolean
) => {
// Set flag bahwa perubahan berasal dari checkbox utama
setIsUpdatingFromMainCheckbox(true);
setMainCheckboxChangeType(key + (value ? "_checked" : "_unchecked"));
if (key === "semua") {
// Jika klik Semua, set semua value ke true/false
const newState = {
@ -277,6 +427,28 @@ export default function FormImageDetail() {
};
setUnitSelection(newState);
} else {
// Validasi khusus untuk POLRES
if (key === "polres" && value) {
// Cek apakah ada POLDA yang sudah dipilih di modal
const hasSelectedPolda = listDest.some((item: any) =>
item.levelNumber === 2 &&
item.name !== "SATKER POLRI" &&
checkedLevels.has(Number(item.id))
);
if (!hasSelectedPolda) {
// Jika tidak ada POLDA yang dipilih, tampilkan peringatan dan batalkan
alert("Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.");
// Reset flag karena perubahan dibatalkan
setIsUpdatingFromMainCheckbox(false);
setMainCheckboxChangeType("");
return; // Batalkan perubahan
}
}
// Tidak ada validasi khusus untuk SATKER dan POLRES
// Keduanya bisa aktif bersamaan
// Update salah satu saja
const updatedSelection = {
...unitSelection,
@ -326,12 +498,38 @@ export default function FormImageDetail() {
};
const handleCheckboxChangePlacement = (levelId: number) => {
setCheckedLevels((prev: any) => {
const updatedLevels = new Set(prev);
if (updatedLevels.has(levelId)) {
setCheckedLevels((prev: Set<number>) => {
const updatedLevels = new Set<number>(prev);
const isCurrentlyChecked = updatedLevels.has(levelId);
if (isCurrentlyChecked) {
updatedLevels.delete(levelId);
// Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya
const poldaItem = listDest.find((item: any) => Number(item.id) === levelId) as any;
if (poldaItem && poldaItem.subDestination && poldaItem.name !== "SATKER POLRI") {
poldaItem.subDestination.forEach((polres: any) => {
updatedLevels.delete(Number(polres.id));
});
}
// Jika ini adalah SATKER POLRI yang di-unchecklist, unchecklist juga semua sub-item di bawahnya
if (poldaItem && poldaItem.name === "SATKER POLRI") {
poldaItem.subDestination?.forEach((subItem: any) => {
updatedLevels.delete(Number(subItem.id));
});
}
} else {
updatedLevels.add(levelId);
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
const satkerItem = listDest.find((item: any) => Number(item.id) === levelId) as any;
if (satkerItem && satkerItem.name === "SATKER POLRI") {
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
satkerItem.subDestination?.forEach((subItem: any) => {
updatedLevels.add(Number(subItem.id));
});
}
}
return updatedLevels;
});
@ -395,7 +593,7 @@ export default function FormImageDetail() {
setupPlacementCheck(details?.files?.length);
if (details?.assignedToLevel) {
const levels = new Set(
const levels = new Set<number>(
details.assignedToLevel.split(",").map(Number)
);
setCheckedLevels(levels);
@ -519,10 +717,23 @@ export default function FormImageDetail() {
if (checked) {
if (placement === "all") {
temp[index] = ["all", "mabes", "polda", "international"];
} else if (placement === "satker") {
// Ketika satker di-checklist, HANYA tambahkan satker saja
// JANGAN otomatis checklist polres
const now = temp[index] || [];
if (!now.includes("satker")) {
now.push("satker");
}
temp[index] = now;
} else {
const now = temp[index];
now?.push(placement);
if (now.length === 3 && !now.includes("all")) {
const now = temp[index] || [];
if (!now.includes(placement)) {
now.push(placement);
}
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
// JANGAN include satker dalam perhitungan auto "all"
const nonSatkerItems = now.filter(item => item !== "satker" && item !== "all");
if (nonSatkerItems.length === 3 && !now.includes("all")) {
now.push("all");
}
temp[index] = now;
@ -534,12 +745,16 @@ export default function FormImageDetail() {
const now = temp[index].filter((a) => a !== placement);
console.log("now", now);
temp[index] = now;
if (now.length === 3 && now.includes("all")) {
// Hapus "all" jika tidak semua item ter-checklist
if (now.includes("all")) {
const nonSatkerItems = now.filter(item => item !== "satker" && item !== "all");
if (nonSatkerItems.length < 3) {
const newData = now.filter((b) => b !== "all");
temp[index] = newData;
}
}
}
}
setFilePlacements(temp);
};
@ -1031,45 +1246,30 @@ export default function FormImageDetail() {
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listDest.map((polda: any) => {
const poldaChecked =
unitSelection.polda;
const polresChecked =
unitSelection.polres;
const isPoldaDisabled =
poldaChecked;
const isPolresDisabled =
polresChecked;
return (
{listDest.map((polda: any) => (
<div
key={polda.id}
className="border p-2"
>
<Label className="flex items-center">
<div className="flex items-center">
<Label className="flex items-center flex-1">
<Checkbox
checked={
poldaChecked ||
checkedLevels.has(
polda.id
)
checked={checkedLevels.has(Number(polda.id))}
onCheckedChange={() =>
handleCheckboxChangePlacement(Number(polda.id))
}
disabled={isPoldaDisabled}
onCheckedChange={() => {
if (isPoldaDisabled)
return;
handleCheckboxChangePlacement(
polda.id
);
}}
className="mr-3"
/>
{polda.name}
</Label>
<button
onClick={() =>
toggleExpand(polda.id)
}
className="ml-2 focus:outline-none"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
toggleExpand(polda.id);
}}
className="ml-2 focus:outline-none p-1 hover:bg-gray-100 rounded"
type="button"
>
{expandedPolda[polda.id] ? (
<ChevronUp size={16} />
@ -1077,10 +1277,55 @@ export default function FormImageDetail() {
<ChevronDown size={16} />
)}
</button>
</Label>
</div>
{expandedPolda[polda.id] && (
<div className="ml-6 mt-2">
<Label className="block">
<Checkbox
checked={polda?.subDestination?.every(
(polres: any) =>
checkedLevels.has(Number(polres.id))
)}
onCheckedChange={(isChecked) => {
const updatedLevels = new Set<number>(
checkedLevels
);
// Jika ini adalah SATKER POLRI, checklist juga sub-item di bawahnya
if (polda.name === "SATKER POLRI") {
if (isChecked) {
updatedLevels.add(Number(polda.id));
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
polda?.subDestination?.forEach((subItem: any) => {
updatedLevels.add(Number(subItem.id));
});
} else {
updatedLevels.delete(Number(polda.id));
// Unchecklist semua sub-item di bawah SATKER POLRI
polda?.subDestination?.forEach((subItem: any) => {
updatedLevels.delete(Number(subItem.id));
});
}
} else {
// Untuk POLDA biasa, checklist/unchecklist polres
polda?.subDestination?.forEach(
(polres: any) => {
if (isChecked) {
updatedLevels.add(Number(polres.id));
} else {
updatedLevels.delete(Number(polres.id));
}
}
);
}
setCheckedLevels(updatedLevels);
}}
className="mr-2"
/>
{polda.name === "SATKER POLRI" ? "Pilih SATKER" : "Pilih Semua"}
</Label>
{polda?.subDestination?.map(
(polres: any) => (
<Label
@ -1088,24 +1333,10 @@ export default function FormImageDetail() {
className="block mt-1"
>
<Checkbox
checked={
polresChecked ||
checkedLevels.has(
polres.id
)
checked={checkedLevels.has(Number(polres.id))}
onCheckedChange={() =>
handleCheckboxChangePlacement(Number(polres.id))
}
disabled={
isPolresDisabled
}
onCheckedChange={() => {
if (
isPolresDisabled
)
return;
handleCheckboxChangePlacement(
polres.id
);
}}
className="mr-2"
/>
{polres.name}
@ -1115,8 +1346,7 @@ export default function FormImageDetail() {
</div>
)}
</div>
);
})}
))}
</div>
</DialogContent>
</Dialog>