fixing
This commit is contained in:
parent
e5a2fc2bf1
commit
285bcad1d8
|
|
@ -198,6 +198,12 @@ export default function FormAudioDetail() {
|
||||||
}>
|
}>
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||||
|
setIsUserMabesApprover(true);
|
||||||
|
}
|
||||||
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
// Fungsi untuk mengupdate state individual file
|
// Fungsi untuk mengupdate state individual file
|
||||||
const handleFileUnitChange = (
|
const handleFileUnitChange = (
|
||||||
fileIndex: number,
|
fileIndex: number,
|
||||||
|
|
@ -1298,6 +1304,13 @@ export default function FormAudioDetail() {
|
||||||
<p className="text-sm text-gray-600 break-all">
|
<p className="text-sm text-gray-600 break-all">
|
||||||
{file.fileName}
|
{file.fileName}
|
||||||
</p>
|
</p>
|
||||||
|
{isUserMabesApprover ? (
|
||||||
|
""
|
||||||
|
) : (
|
||||||
|
<p className="status text-success text-sm mb-0">
|
||||||
|
Selesai
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -1315,6 +1328,7 @@ export default function FormAudioDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
|
{isUserMabesApprover ? (
|
||||||
<div className="bg-white rounded-md p-4 border">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
<Icon
|
<Icon
|
||||||
|
|
@ -1481,7 +1495,9 @@ export default function FormAudioDetail() {
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleExpand(polda.id);
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
>
|
>
|
||||||
|
|
@ -1513,7 +1529,9 @@ export default function FormAudioDetail() {
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(sub.id)
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
@ -1533,7 +1551,9 @@ export default function FormAudioDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-indeterminate-small"
|
icon="material-symbols:check-indeterminate-small"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Batal Semua
|
Batal Semua
|
||||||
|
|
@ -1543,7 +1563,9 @@ export default function FormAudioDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-all"
|
icon="material-symbols:check-all"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Pilih Semua
|
Pilih Semua
|
||||||
|
|
@ -1615,6 +1637,9 @@ export default function FormAudioDetail() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import {
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
|
||||||
|
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import {
|
import {
|
||||||
|
|
@ -163,7 +162,8 @@ export default function FormImageDetail() {
|
||||||
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
const [isUserMabesApprover, setIsUserMabesApprover] = useState(false);
|
||||||
const [approval, setApproval] = useState<any>();
|
const [approval, setApproval] = useState<any>();
|
||||||
// State untuk setiap file secara individual
|
// State untuk setiap file secara individual
|
||||||
const [fileUnitSelections, setFileUnitSelections] = useState<Array<{
|
const [fileUnitSelections, setFileUnitSelections] = useState<
|
||||||
|
Array<{
|
||||||
semua: boolean;
|
semua: boolean;
|
||||||
nasional: boolean;
|
nasional: boolean;
|
||||||
wilayah: boolean;
|
wilayah: boolean;
|
||||||
|
|
@ -171,10 +171,19 @@ export default function FormImageDetail() {
|
||||||
polda: boolean;
|
polda: boolean;
|
||||||
polres: boolean;
|
polres: boolean;
|
||||||
satker: boolean;
|
satker: boolean;
|
||||||
}>>([]);
|
}>
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||||
|
setIsUserMabesApprover(true);
|
||||||
|
}
|
||||||
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
// State untuk setiap file secara individual - checklist levels
|
// State untuk setiap file secara individual - checklist levels
|
||||||
const [fileCheckedLevels, setFileCheckedLevels] = useState<Array<Set<number>>>([]);
|
const [fileCheckedLevels, setFileCheckedLevels] = useState<
|
||||||
|
Array<Set<number>>
|
||||||
|
>([]);
|
||||||
|
|
||||||
// State global untuk kompatibilitas (akan dihapus nanti)
|
// State global untuk kompatibilitas (akan dihapus nanti)
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
|
|
@ -191,12 +200,16 @@ export default function FormImageDetail() {
|
||||||
const [selectedTarget, setSelectedTarget] = useState("");
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
const [files, setFiles] = useState<FileType[]>([]);
|
const [files, setFiles] = useState<FileType[]>([]);
|
||||||
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
|
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
|
||||||
const [expandedPolda, setExpandedPolda] = useState<Record<number, boolean>>({});
|
const [expandedPolda, setExpandedPolda] = useState<Record<number, boolean>>(
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
// State untuk melacak apakah perubahan berasal dari checkbox utama
|
// State untuk melacak apakah perubahan berasal dari checkbox utama
|
||||||
const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] = useState(false);
|
const [isUpdatingFromMainCheckbox, setIsUpdatingFromMainCheckbox] =
|
||||||
|
useState(false);
|
||||||
// State untuk melacak jenis perubahan spesifik
|
// State untuk melacak jenis perubahan spesifik
|
||||||
const [mainCheckboxChangeType, setMainCheckboxChangeType] = useState<string>("");
|
const [mainCheckboxChangeType, setMainCheckboxChangeType] =
|
||||||
|
useState<string>("");
|
||||||
const [wilayahPublish, setWilayahPublish] = React.useState({
|
const [wilayahPublish, setWilayahPublish] = React.useState({
|
||||||
semua: false,
|
semua: false,
|
||||||
nasional: false,
|
nasional: false,
|
||||||
|
|
@ -263,7 +276,11 @@ export default function FormImageDetail() {
|
||||||
|
|
||||||
// useEffect untuk sinkronisasi checkbox modal dengan checkbox utama
|
// useEffect untuk sinkronisasi checkbox modal dengan checkbox utama
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (listDest.length > 0 && isUpdatingFromMainCheckbox && mainCheckboxChangeType) {
|
if (
|
||||||
|
listDest.length > 0 &&
|
||||||
|
isUpdatingFromMainCheckbox &&
|
||||||
|
mainCheckboxChangeType
|
||||||
|
) {
|
||||||
syncModalWithMainCheckbox();
|
syncModalWithMainCheckbox();
|
||||||
}
|
}
|
||||||
}, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]);
|
}, [isUpdatingFromMainCheckbox, mainCheckboxChangeType]);
|
||||||
|
|
@ -279,7 +296,8 @@ export default function FormImageDetail() {
|
||||||
const updateMainCheckboxFromModalLegacy = () => {
|
const updateMainCheckboxFromModalLegacy = () => {
|
||||||
if (!isUpdatingFromMainCheckbox && listDest.length > 0) {
|
if (!isUpdatingFromMainCheckbox && listDest.length > 0) {
|
||||||
// Hitung item yang dipilih berdasarkan checkedLevels
|
// Hitung item yang dipilih berdasarkan checkedLevels
|
||||||
const checkedPoldaCount = listDest.filter((item: any) =>
|
const checkedPoldaCount = listDest.filter(
|
||||||
|
(item: any) =>
|
||||||
item.levelNumber === 2 &&
|
item.levelNumber === 2 &&
|
||||||
item.name !== "SATKER POLRI" &&
|
item.name !== "SATKER POLRI" &&
|
||||||
checkedLevels.has(Number(item.id))
|
checkedLevels.has(Number(item.id))
|
||||||
|
|
@ -288,16 +306,25 @@ export default function FormImageDetail() {
|
||||||
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
|
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
|
||||||
if (item.subDestination && item.name !== "SATKER POLRI") {
|
if (item.subDestination && item.name !== "SATKER POLRI") {
|
||||||
// Hanya hitung sub-item dari POLDA (bukan dari 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 +
|
||||||
|
item.subDestination.filter((sub: any) =>
|
||||||
|
checkedLevels.has(Number(sub.id))
|
||||||
|
).length
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem: any = listDest.find(
|
||||||
const checkedSatkerCount = satkerItem ? (
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
(checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) +
|
);
|
||||||
(satkerItem.subDestination?.filter((sub: any) => checkedLevels.has(Number(sub.id))).length || 0)
|
const checkedSatkerCount = satkerItem
|
||||||
) : 0;
|
? (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
|
// Checkbox aktif jika ADA item yang dipilih dalam kategori tersebut
|
||||||
const hasSelectedPolda = checkedPoldaCount > 0;
|
const hasSelectedPolda = checkedPoldaCount > 0;
|
||||||
|
|
@ -305,7 +332,7 @@ export default function FormImageDetail() {
|
||||||
const hasSelectedSatker = checkedSatkerCount > 0;
|
const hasSelectedSatker = checkedSatkerCount > 0;
|
||||||
|
|
||||||
// Update unitSelection berdasarkan yang dipilih di modal
|
// Update unitSelection berdasarkan yang dipilih di modal
|
||||||
setUnitSelection(prev => {
|
setUnitSelection((prev) => {
|
||||||
const newState = { ...prev };
|
const newState = { ...prev };
|
||||||
|
|
||||||
// Update individual checkboxes
|
// Update individual checkboxes
|
||||||
|
|
@ -314,7 +341,13 @@ export default function FormImageDetail() {
|
||||||
newState.satker = hasSelectedSatker;
|
newState.satker = hasSelectedSatker;
|
||||||
|
|
||||||
// Update checkbox "semua" berdasarkan semua checkbox yang aktif
|
// Update checkbox "semua" berdasarkan semua checkbox yang aktif
|
||||||
newState.semua = newState.nasional && newState.wilayah && newState.international && hasSelectedPolda && hasSelectedPolres && hasSelectedSatker;
|
newState.semua =
|
||||||
|
newState.nasional &&
|
||||||
|
newState.wilayah &&
|
||||||
|
newState.international &&
|
||||||
|
hasSelectedPolda &&
|
||||||
|
hasSelectedPolres &&
|
||||||
|
hasSelectedSatker;
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
});
|
});
|
||||||
|
|
@ -338,7 +371,11 @@ export default function FormImageDetail() {
|
||||||
// Checklist semua polres, tapi hanya yang poldanya sudah di-checklist
|
// Checklist semua polres, tapi hanya yang poldanya sudah di-checklist
|
||||||
// Jangan checklist sub-item SATKER POLRI
|
// Jangan checklist sub-item SATKER POLRI
|
||||||
listDest.forEach((item: any) => {
|
listDest.forEach((item: any) => {
|
||||||
if (item.levelNumber === 2 && item.name !== "SATKER POLRI" && newCheckedLevels.has(Number(item.id))) {
|
if (
|
||||||
|
item.levelNumber === 2 &&
|
||||||
|
item.name !== "SATKER POLRI" &&
|
||||||
|
newCheckedLevels.has(Number(item.id))
|
||||||
|
) {
|
||||||
if (item.subDestination) {
|
if (item.subDestination) {
|
||||||
item.subDestination.forEach((polres: any) => {
|
item.subDestination.forEach((polres: any) => {
|
||||||
newCheckedLevels.add(Number(polres.id));
|
newCheckedLevels.add(Number(polres.id));
|
||||||
|
|
@ -354,7 +391,9 @@ export default function FormImageDetail() {
|
||||||
// - POLRES: unit-unit seperti POLRES METRO JAKARTA PUSAT, dll.
|
// - POLRES: unit-unit seperti POLRES METRO JAKARTA PUSAT, dll.
|
||||||
} else if (mainCheckboxChangeType === "satker_checked") {
|
} else if (mainCheckboxChangeType === "satker_checked") {
|
||||||
// Checklist satker
|
// Checklist satker
|
||||||
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem: any = listDest.find(
|
||||||
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
|
);
|
||||||
if (satkerItem) {
|
if (satkerItem) {
|
||||||
newCheckedLevels.add(Number(satkerItem.id));
|
newCheckedLevels.add(Number(satkerItem.id));
|
||||||
// Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES)
|
// Checklist semua sub-item yang ada di bawah SATKER (bukan POLRES)
|
||||||
|
|
@ -400,7 +439,9 @@ export default function FormImageDetail() {
|
||||||
});
|
});
|
||||||
} else if (mainCheckboxChangeType === "satker_unchecked") {
|
} else if (mainCheckboxChangeType === "satker_unchecked") {
|
||||||
// Clear satker dan semua sub-item di bawahnya dari checkedLevels
|
// Clear satker dan semua sub-item di bawahnya dari checkedLevels
|
||||||
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem: any = listDest.find(
|
||||||
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
|
);
|
||||||
if (satkerItem) {
|
if (satkerItem) {
|
||||||
newCheckedLevels.delete(Number(satkerItem.id));
|
newCheckedLevels.delete(Number(satkerItem.id));
|
||||||
if (satkerItem.subDestination) {
|
if (satkerItem.subDestination) {
|
||||||
|
|
@ -428,7 +469,7 @@ export default function FormImageDetail() {
|
||||||
key: keyof typeof unitSelection,
|
key: keyof typeof unitSelection,
|
||||||
value: boolean
|
value: boolean
|
||||||
) => {
|
) => {
|
||||||
setFileUnitSelections(prev => {
|
setFileUnitSelections((prev) => {
|
||||||
const newSelections = [...prev];
|
const newSelections = [...prev];
|
||||||
const currentSelection = { ...newSelections[fileIndex] };
|
const currentSelection = { ...newSelections[fileIndex] };
|
||||||
|
|
||||||
|
|
@ -445,14 +486,19 @@ export default function FormImageDetail() {
|
||||||
// Validasi khusus untuk POLRES - harus ada POLDA yang ter-checklist
|
// Validasi khusus untuk POLRES - harus ada POLDA yang ter-checklist
|
||||||
if (key === "polres" && value) {
|
if (key === "polres" && value) {
|
||||||
const currentFileCheckedLevels = fileCheckedLevels[fileIndex];
|
const currentFileCheckedLevels = fileCheckedLevels[fileIndex];
|
||||||
const hasSelectedPolda = currentFileCheckedLevels && listDest.some((item: any) =>
|
const hasSelectedPolda =
|
||||||
|
currentFileCheckedLevels &&
|
||||||
|
listDest.some(
|
||||||
|
(item: any) =>
|
||||||
item.levelNumber === 2 &&
|
item.levelNumber === 2 &&
|
||||||
item.name !== "SATKER POLRI" &&
|
item.name !== "SATKER POLRI" &&
|
||||||
currentFileCheckedLevels.has(Number(item.id))
|
currentFileCheckedLevels.has(Number(item.id))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!hasSelectedPolda) {
|
if (!hasSelectedPolda) {
|
||||||
alert("Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.");
|
alert(
|
||||||
|
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES."
|
||||||
|
);
|
||||||
return prev; // Batalkan perubahan
|
return prev; // Batalkan perubahan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -503,7 +549,8 @@ export default function FormImageDetail() {
|
||||||
// Validasi khusus untuk POLRES
|
// Validasi khusus untuk POLRES
|
||||||
if (key === "polres" && value) {
|
if (key === "polres" && value) {
|
||||||
// Cek apakah ada POLDA yang sudah dipilih di modal
|
// Cek apakah ada POLDA yang sudah dipilih di modal
|
||||||
const hasSelectedPolda = listDest.some((item: any) =>
|
const hasSelectedPolda = listDest.some(
|
||||||
|
(item: any) =>
|
||||||
item.levelNumber === 2 &&
|
item.levelNumber === 2 &&
|
||||||
item.name !== "SATKER POLRI" &&
|
item.name !== "SATKER POLRI" &&
|
||||||
checkedLevels.has(Number(item.id))
|
checkedLevels.has(Number(item.id))
|
||||||
|
|
@ -511,7 +558,9 @@ export default function FormImageDetail() {
|
||||||
|
|
||||||
if (!hasSelectedPolda) {
|
if (!hasSelectedPolda) {
|
||||||
// Jika tidak ada POLDA yang dipilih, tampilkan peringatan dan batalkan
|
// Jika tidak ada POLDA yang dipilih, tampilkan peringatan dan batalkan
|
||||||
alert("Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.");
|
alert(
|
||||||
|
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES."
|
||||||
|
);
|
||||||
// Reset flag karena perubahan dibatalkan
|
// Reset flag karena perubahan dibatalkan
|
||||||
setIsUpdatingFromMainCheckbox(false);
|
setIsUpdatingFromMainCheckbox(false);
|
||||||
setMainCheckboxChangeType("");
|
setMainCheckboxChangeType("");
|
||||||
|
|
@ -571,7 +620,10 @@ export default function FormImageDetail() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fungsi untuk mengupdate checklist levels untuk file tertentu
|
// Fungsi untuk mengupdate checklist levels untuk file tertentu
|
||||||
const handleFileCheckboxChangePlacement = (fileIndex: number, levelId: number) => {
|
const handleFileCheckboxChangePlacement = (
|
||||||
|
fileIndex: number,
|
||||||
|
levelId: number
|
||||||
|
) => {
|
||||||
setFileCheckedLevels((prev) => {
|
setFileCheckedLevels((prev) => {
|
||||||
const newArray = [...prev];
|
const newArray = [...prev];
|
||||||
const currentFileLevels = new Set<number>(newArray[fileIndex]);
|
const currentFileLevels = new Set<number>(newArray[fileIndex]);
|
||||||
|
|
@ -581,8 +633,14 @@ export default function FormImageDetail() {
|
||||||
currentFileLevels.delete(levelId);
|
currentFileLevels.delete(levelId);
|
||||||
|
|
||||||
// Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya
|
// 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;
|
const poldaItem = listDest.find(
|
||||||
if (poldaItem && poldaItem.subDestination && poldaItem.name !== "SATKER POLRI") {
|
(item: any) => Number(item.id) === levelId
|
||||||
|
) as any;
|
||||||
|
if (
|
||||||
|
poldaItem &&
|
||||||
|
poldaItem.subDestination &&
|
||||||
|
poldaItem.name !== "SATKER POLRI"
|
||||||
|
) {
|
||||||
poldaItem.subDestination.forEach((polres: any) => {
|
poldaItem.subDestination.forEach((polres: any) => {
|
||||||
currentFileLevels.delete(Number(polres.id));
|
currentFileLevels.delete(Number(polres.id));
|
||||||
});
|
});
|
||||||
|
|
@ -598,7 +656,9 @@ export default function FormImageDetail() {
|
||||||
currentFileLevels.add(levelId);
|
currentFileLevels.add(levelId);
|
||||||
|
|
||||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
// 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;
|
const satkerItem = listDest.find(
|
||||||
|
(item: any) => Number(item.id) === levelId
|
||||||
|
) as any;
|
||||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||||
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
|
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
|
||||||
satkerItem.subDestination?.forEach((subItem: any) => {
|
satkerItem.subDestination?.forEach((subItem: any) => {
|
||||||
|
|
@ -664,38 +724,57 @@ export default function FormImageDetail() {
|
||||||
if (!currentFileLevels) return prev;
|
if (!currentFileLevels) return prev;
|
||||||
|
|
||||||
// Hitung total POLDA yang ada (bukan SATKER POLRI)
|
// Hitung total POLDA yang ada (bukan SATKER POLRI)
|
||||||
const totalPoldaCount = listDest.filter((item: any) =>
|
const totalPoldaCount = listDest.filter(
|
||||||
item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
||||||
const checkedPoldaCount = listDest.reduce((total: number, item: any) => {
|
const checkedPoldaCount = listDest.reduce((total: number, item: any) => {
|
||||||
if (item.levelNumber === 2 && item.name !== "SATKER POLRI" && currentFileLevels.has(Number(item.id))) {
|
if (
|
||||||
|
item.levelNumber === 2 &&
|
||||||
|
item.name !== "SATKER POLRI" &&
|
||||||
|
currentFileLevels.has(Number(item.id))
|
||||||
|
) {
|
||||||
return total + 1;
|
return total + 1;
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Hitung total POLRES yang ada dari POLDA yang ter-checklist
|
// Hitung total POLRES yang ada dari POLDA yang ter-checklist
|
||||||
const totalPolresFromCheckedPolda = listDest.reduce((total: number, item: any) => {
|
const totalPolresFromCheckedPolda = listDest.reduce(
|
||||||
if (item.subDestination && item.name !== "SATKER POLRI" && currentFileLevels.has(Number(item.id))) {
|
(total: number, item: any) => {
|
||||||
|
if (
|
||||||
|
item.subDestination &&
|
||||||
|
item.name !== "SATKER POLRI" &&
|
||||||
|
currentFileLevels.has(Number(item.id))
|
||||||
|
) {
|
||||||
return total + item.subDestination.length;
|
return total + item.subDestination.length;
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
},
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
// Hitung berapa banyak POLRES yang ter-checklist
|
// Hitung berapa banyak POLRES yang ter-checklist
|
||||||
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
|
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
|
||||||
if (item.subDestination && item.name !== "SATKER POLRI") {
|
if (item.subDestination && item.name !== "SATKER POLRI") {
|
||||||
// Hanya hitung sub-item dari POLDA (bukan dari SATKER POLRI)
|
// Hanya hitung sub-item dari POLDA (bukan dari SATKER POLRI)
|
||||||
return total + item.subDestination.filter((sub: any) => currentFileLevels.has(Number(sub.id))).length;
|
return (
|
||||||
|
total +
|
||||||
|
item.subDestination.filter((sub: any) =>
|
||||||
|
currentFileLevels.has(Number(sub.id))
|
||||||
|
).length
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Cek apakah SATKER POLRI ter-checklist
|
// Cek apakah SATKER POLRI ter-checklist
|
||||||
const satkerItem = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem = listDest.find(
|
||||||
const isSatkerChecked = satkerItem && currentFileLevels.has(Number(satkerItem.id));
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
|
);
|
||||||
|
const isSatkerChecked =
|
||||||
|
satkerItem && currentFileLevels.has(Number(satkerItem.id));
|
||||||
|
|
||||||
// Update checkbox berdasarkan kondisi
|
// Update checkbox berdasarkan kondisi
|
||||||
// POLDA aktif jika ada minimal 1 POLDA ter-checklist
|
// POLDA aktif jika ada minimal 1 POLDA ter-checklist
|
||||||
|
|
@ -719,8 +798,14 @@ export default function FormImageDetail() {
|
||||||
updatedLevels.delete(levelId);
|
updatedLevels.delete(levelId);
|
||||||
|
|
||||||
// Jika ini adalah POLDA yang di-unchecklist, unchecklist juga semua polres di bawahnya
|
// 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;
|
const poldaItem = listDest.find(
|
||||||
if (poldaItem && poldaItem.subDestination && poldaItem.name !== "SATKER POLRI") {
|
(item: any) => Number(item.id) === levelId
|
||||||
|
) as any;
|
||||||
|
if (
|
||||||
|
poldaItem &&
|
||||||
|
poldaItem.subDestination &&
|
||||||
|
poldaItem.name !== "SATKER POLRI"
|
||||||
|
) {
|
||||||
poldaItem.subDestination.forEach((polres: any) => {
|
poldaItem.subDestination.forEach((polres: any) => {
|
||||||
updatedLevels.delete(Number(polres.id));
|
updatedLevels.delete(Number(polres.id));
|
||||||
});
|
});
|
||||||
|
|
@ -736,7 +821,9 @@ export default function FormImageDetail() {
|
||||||
updatedLevels.add(levelId);
|
updatedLevels.add(levelId);
|
||||||
|
|
||||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
// 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;
|
const satkerItem = listDest.find(
|
||||||
|
(item: any) => Number(item.id) === levelId
|
||||||
|
) as any;
|
||||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||||
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
|
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
|
||||||
satkerItem.subDestination?.forEach((subItem: any) => {
|
satkerItem.subDestination?.forEach((subItem: any) => {
|
||||||
|
|
@ -971,7 +1058,9 @@ export default function FormImageDetail() {
|
||||||
}
|
}
|
||||||
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
||||||
// JANGAN include satker dalam perhitungan auto "all"
|
// JANGAN include satker dalam perhitungan auto "all"
|
||||||
const nonSatkerItems = now.filter(item => item !== "satker" && item !== "all");
|
const nonSatkerItems = now.filter(
|
||||||
|
(item) => item !== "satker" && item !== "all"
|
||||||
|
);
|
||||||
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
||||||
now.push("all");
|
now.push("all");
|
||||||
}
|
}
|
||||||
|
|
@ -986,7 +1075,9 @@ export default function FormImageDetail() {
|
||||||
temp[index] = now;
|
temp[index] = now;
|
||||||
// Hapus "all" jika tidak semua item ter-checklist
|
// Hapus "all" jika tidak semua item ter-checklist
|
||||||
if (now.includes("all")) {
|
if (now.includes("all")) {
|
||||||
const nonSatkerItems = now.filter(item => item !== "satker" && item !== "all");
|
const nonSatkerItems = now.filter(
|
||||||
|
(item) => item !== "satker" && item !== "all"
|
||||||
|
);
|
||||||
if (nonSatkerItems.length < 3) {
|
if (nonSatkerItems.length < 3) {
|
||||||
const newData = now.filter((b) => b !== "all");
|
const newData = now.filter((b) => b !== "all");
|
||||||
temp[index] = newData;
|
temp[index] = newData;
|
||||||
|
|
@ -1001,7 +1092,11 @@ export default function FormImageDetail() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fungsi untuk mengupdate checklist levels di modal berdasarkan placement
|
// Fungsi untuk mengupdate checklist levels di modal berdasarkan placement
|
||||||
const updateModalChecklistLevels = (fileIndex: number, placement: string, checked: boolean) => {
|
const updateModalChecklistLevels = (
|
||||||
|
fileIndex: number,
|
||||||
|
placement: string,
|
||||||
|
checked: boolean
|
||||||
|
) => {
|
||||||
if (!listDest || listDest.length === 0) return;
|
if (!listDest || listDest.length === 0) return;
|
||||||
|
|
||||||
setFileCheckedLevels((prev) => {
|
setFileCheckedLevels((prev) => {
|
||||||
|
|
@ -1032,7 +1127,9 @@ export default function FormImageDetail() {
|
||||||
});
|
});
|
||||||
} else if (placement === "satker") {
|
} else if (placement === "satker") {
|
||||||
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
||||||
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem: any = listDest.find(
|
||||||
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
|
);
|
||||||
if (satkerItem) {
|
if (satkerItem) {
|
||||||
currentFileLevels.add(Number(satkerItem.id));
|
currentFileLevels.add(Number(satkerItem.id));
|
||||||
if (satkerItem.subDestination) {
|
if (satkerItem.subDestination) {
|
||||||
|
|
@ -1066,7 +1163,9 @@ export default function FormImageDetail() {
|
||||||
});
|
});
|
||||||
} else if (placement === "satker") {
|
} else if (placement === "satker") {
|
||||||
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
||||||
const satkerItem: any = listDest.find((item: any) => item.name === "SATKER POLRI");
|
const satkerItem: any = listDest.find(
|
||||||
|
(item: any) => item.name === "SATKER POLRI"
|
||||||
|
);
|
||||||
if (satkerItem) {
|
if (satkerItem) {
|
||||||
currentFileLevels.delete(Number(satkerItem.id));
|
currentFileLevels.delete(Number(satkerItem.id));
|
||||||
if (satkerItem.subDestination) {
|
if (satkerItem.subDestination) {
|
||||||
|
|
@ -1439,13 +1538,19 @@ export default function FormImageDetail() {
|
||||||
<DialogContent className="max-h-[90vh] max-w-[95vw] lg:max-w-[1200px]">
|
<DialogContent className="max-h-[90vh] max-w-[95vw] lg:max-w-[1200px]">
|
||||||
<DialogHeader className="border-b border-gray-200 pb-4">
|
<DialogHeader className="border-b border-gray-200 pb-4">
|
||||||
<DialogTitle className="text-xl font-semibold">
|
<DialogTitle className="text-xl font-semibold">
|
||||||
{t("leave-comment", { defaultValue: "Kelola Persetujuan Konten" })}
|
{t("leave-comment", {
|
||||||
|
defaultValue: "Kelola Persetujuan Konten",
|
||||||
|
})}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="flex flex-col gap-4 max-h-[40vh] overflow-y-auto p-1">
|
<div className="flex flex-col gap-4 max-h-[40vh] overflow-y-auto p-1">
|
||||||
{status == "2" && files?.map((file, index) => (
|
{status == "2" &&
|
||||||
<div key={file.id} className="border border-gray-200 rounded-lg p-4 bg-gray-50">
|
files?.map((file, index) => (
|
||||||
|
<div
|
||||||
|
key={file.id}
|
||||||
|
className="border border-gray-200 rounded-lg p-4 bg-gray-50"
|
||||||
|
>
|
||||||
{/* Header File */}
|
{/* Header File */}
|
||||||
<div className="flex items-center justify-between mb-4 bg-white p-3 rounded-md border">
|
<div className="flex items-center justify-between mb-4 bg-white p-3 rounded-md border">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|
@ -1461,8 +1566,19 @@ export default function FormImageDetail() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium text-gray-900 mb-1">File {index + 1}</h4>
|
<h4 className="font-medium text-gray-900 mb-1">
|
||||||
<p className="text-sm text-gray-600 break-all">{file.fileName}</p>
|
File {index + 1}
|
||||||
|
</h4>
|
||||||
|
<p className="text-sm text-gray-600 break-all">
|
||||||
|
{file.fileName}
|
||||||
|
</p>
|
||||||
|
{isUserMabesApprover ? (
|
||||||
|
""
|
||||||
|
) : (
|
||||||
|
<p className="status text-success text-sm mb-0">
|
||||||
|
Selesai
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -1470,42 +1586,71 @@ export default function FormImageDetail() {
|
||||||
className="p-2 hover:bg-red-50 rounded-full transition-colors"
|
className="p-2 hover:bg-red-50 rounded-full transition-colors"
|
||||||
title="Hapus file"
|
title="Hapus file"
|
||||||
>
|
>
|
||||||
<Icon icon="humbleicons:times" color="red" width={20} height={20} />
|
<Icon
|
||||||
|
icon="humbleicons:times"
|
||||||
|
color="red"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
|
{isUserMabesApprover ? (
|
||||||
<div className="bg-white rounded-md p-4 border">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
<Icon icon="material-symbols:settings-outline" width={18} height={18} />
|
<Icon
|
||||||
|
icon="material-symbols:settings-outline"
|
||||||
|
width={18}
|
||||||
|
height={18}
|
||||||
|
/>
|
||||||
Pengaturan Distribusi
|
Pengaturan Distribusi
|
||||||
</h5>
|
</h5>
|
||||||
|
|
||||||
{/* Checkbox Tingkat Utama */}
|
{/* Checkbox Tingkat Utama */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-700 mb-3">Tingkat Distribusi:</p>
|
<p className="text-sm font-medium text-gray-700 mb-3">
|
||||||
|
Tingkat Distribusi:
|
||||||
|
</p>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ key: "semua", label: "Semua" },
|
{ key: "semua", label: "Semua" },
|
||||||
{ key: "nasional", label: "Nasional" },
|
{ key: "nasional", label: "Nasional" },
|
||||||
{ key: "wilayah", label: "Wilayah" },
|
{ key: "wilayah", label: "Wilayah" },
|
||||||
{ key: "international", label: "Internasional" },
|
{
|
||||||
|
key: "international",
|
||||||
|
label: "Internasional",
|
||||||
|
},
|
||||||
].map((item, idx) => (
|
].map((item, idx) => (
|
||||||
<div key={item.key} className="flex items-center gap-2 p-2 border border-gray-200 rounded-md hover:bg-gray-50">
|
<div
|
||||||
|
key={item.key}
|
||||||
|
className="flex items-center gap-2 p-2 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`${item.key}-${index}`}
|
id={`${item.key}-${index}`}
|
||||||
checked={fileUnitSelections[index]?.[item.key as keyof typeof unitSelection] || false}
|
checked={
|
||||||
|
fileUnitSelections[index]?.[
|
||||||
|
item.key as keyof typeof unitSelection
|
||||||
|
] || false
|
||||||
|
}
|
||||||
onCheckedChange={(value) => {
|
onCheckedChange={(value) => {
|
||||||
handleFileUnitChange(
|
handleFileUnitChange(
|
||||||
index,
|
index,
|
||||||
item.key as keyof typeof unitSelection,
|
item.key as keyof typeof unitSelection,
|
||||||
value as boolean
|
value as boolean
|
||||||
);
|
);
|
||||||
setupPlacement(index, item.key, Boolean(value));
|
setupPlacement(
|
||||||
|
index,
|
||||||
|
item.key,
|
||||||
|
Boolean(value)
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={`${item.key}-${index}`} className="text-sm font-medium cursor-pointer">
|
<Label
|
||||||
|
htmlFor={`${item.key}-${index}`}
|
||||||
|
className="text-sm font-medium cursor-pointer"
|
||||||
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1516,7 +1661,9 @@ export default function FormImageDetail() {
|
||||||
{/* Detail Wilayah */}
|
{/* Detail Wilayah */}
|
||||||
{fileUnitSelections[index]?.wilayah && (
|
{fileUnitSelections[index]?.wilayah && (
|
||||||
<div className="border-t border-gray-200 pt-2">
|
<div className="border-t border-gray-200 pt-2">
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">Detail Wilayah:</p>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Detail Wilayah:
|
||||||
|
</p>
|
||||||
|
|
||||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||||
|
|
@ -1525,20 +1672,34 @@ export default function FormImageDetail() {
|
||||||
{ key: "polres", label: "POLRES" },
|
{ key: "polres", label: "POLRES" },
|
||||||
{ key: "satker", label: "SATKER" },
|
{ key: "satker", label: "SATKER" },
|
||||||
].map((item, idx) => (
|
].map((item, idx) => (
|
||||||
<div key={item.key} className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50">
|
<div
|
||||||
|
key={item.key}
|
||||||
|
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`${item.key}-${index}`}
|
id={`${item.key}-${index}`}
|
||||||
checked={fileUnitSelections[index]?.[item.key as keyof typeof unitSelection] || false}
|
checked={
|
||||||
|
fileUnitSelections[index]?.[
|
||||||
|
item.key as keyof typeof unitSelection
|
||||||
|
] || false
|
||||||
|
}
|
||||||
onCheckedChange={(value) => {
|
onCheckedChange={(value) => {
|
||||||
handleFileUnitChange(
|
handleFileUnitChange(
|
||||||
index,
|
index,
|
||||||
item.key as keyof typeof unitSelection,
|
item.key as keyof typeof unitSelection,
|
||||||
value as boolean
|
value as boolean
|
||||||
);
|
);
|
||||||
setupPlacement(index, item.key, Boolean(value));
|
setupPlacement(
|
||||||
|
index,
|
||||||
|
item.key,
|
||||||
|
Boolean(value)
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={`${item.key}-${index}`} className="text-sm font-medium cursor-pointer">
|
<Label
|
||||||
|
htmlFor={`${item.key}-${index}`}
|
||||||
|
className="text-sm font-medium cursor-pointer"
|
||||||
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1548,9 +1709,19 @@ export default function FormImageDetail() {
|
||||||
<div className="flex items-center justify-center p-3">
|
<div className="flex items-center justify-center p-3">
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button variant="outline" size="sm" className="gap-2">
|
<Button
|
||||||
<Icon icon="material-symbols:tune" width={16} height={16} />
|
variant="outline"
|
||||||
{t("custom", { defaultValue: "Kustom" })}
|
size="sm"
|
||||||
|
className="gap-2"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:tune"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
{t("custom", {
|
||||||
|
defaultValue: "Kustom",
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
||||||
|
|
@ -1561,57 +1732,110 @@ export default function FormImageDetail() {
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 max-h-[70vh] overflow-y-auto p-1">
|
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 max-h-[70vh] overflow-y-auto p-1">
|
||||||
{listDest.map((polda: any) => (
|
{listDest.map((polda: any) => (
|
||||||
<div key={polda.id} className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow">
|
<div
|
||||||
|
key={polda.id}
|
||||||
|
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
||||||
|
>
|
||||||
{/* Header POLDA */}
|
{/* Header POLDA */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={fileCheckedLevels[index]?.has(Number(polda.id)) || false}
|
checked={
|
||||||
onCheckedChange={() => handleFileCheckboxChangePlacement(index, Number(polda.id))}
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(polda.id)
|
||||||
|
) || false
|
||||||
|
}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleFileCheckboxChangePlacement(
|
||||||
|
index,
|
||||||
|
Number(polda.id)
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<span className="font-semibold text-gray-900 text-sm">{polda.name}</span>
|
<span className="font-semibold text-gray-900 text-sm">
|
||||||
|
{polda.name}
|
||||||
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
{polda.subDestination && (
|
{polda.subDestination && (
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleExpand(polda.id);
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon={expandedPolda[polda.id] ? "mdi:chevron-up" : "mdi:chevron-down"}
|
icon={
|
||||||
width={16} height={16}
|
expandedPolda[
|
||||||
|
polda.id
|
||||||
|
]
|
||||||
|
? "mdi:chevron-up"
|
||||||
|
: "mdi:chevron-down"
|
||||||
|
}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sub-items */}
|
{/* Sub-items */}
|
||||||
{polda.subDestination && expandedPolda[polda.id] && (
|
{polda.subDestination &&
|
||||||
|
expandedPolda[polda.id] && (
|
||||||
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
||||||
{/* Tombol Pilih Semua untuk sub-items */}
|
{/* Tombol Pilih Semua untuk sub-items */}
|
||||||
<div className="mb-2 flex justify-start">
|
<div className="mb-2 flex justify-start">
|
||||||
{(() => {
|
{(() => {
|
||||||
const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
|
const allSubItemsChecked =
|
||||||
fileCheckedLevels[index]?.has(Number(sub.id))
|
polda.subDestination?.every(
|
||||||
|
(sub: any) =>
|
||||||
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="text-xs h-6 px-2"
|
className="text-xs h-6 px-2"
|
||||||
onClick={() => handleSelectAllSubItems(index, polda)}
|
onClick={() =>
|
||||||
|
handleSelectAllSubItems(
|
||||||
|
index,
|
||||||
|
polda
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{allSubItemsChecked ? (
|
{allSubItemsChecked ? (
|
||||||
<>
|
<>
|
||||||
<Icon icon="material-symbols:check-indeterminate-small" width={12} height={12} className="mr-1" />
|
<Icon
|
||||||
|
icon="material-symbols:check-indeterminate-small"
|
||||||
|
width={12}
|
||||||
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
Batal Semua
|
Batal Semua
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Icon icon="material-symbols:check-all" width={12} height={12} className="mr-1" />
|
<Icon
|
||||||
|
icon="material-symbols:check-all"
|
||||||
|
width={12}
|
||||||
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
Pilih Semua
|
Pilih Semua
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1620,15 +1844,37 @@ export default function FormImageDetail() {
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{polda.subDestination.map((sub: any) => (
|
{polda.subDestination.map(
|
||||||
<Label key={sub.id} className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs">
|
(sub: any) => (
|
||||||
|
<Label
|
||||||
|
key={sub.id}
|
||||||
|
className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={fileCheckedLevels[index]?.has(Number(sub.id)) || false}
|
checked={
|
||||||
onCheckedChange={() => handleFileCheckboxChangePlacement(index, Number(sub.id))}
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
) || false
|
||||||
|
}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleFileCheckboxChangePlacement(
|
||||||
|
index,
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<span className="text-gray-700">{sub.name}</span>
|
<span className="text-gray-700">
|
||||||
|
{sub.name}
|
||||||
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1638,12 +1884,16 @@ export default function FormImageDetail() {
|
||||||
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||||
<DialogClose asChild>
|
<DialogClose asChild>
|
||||||
<Button variant="outline">
|
<Button variant="outline">
|
||||||
{t("cancel", { defaultValue: "Batal" })}
|
{t("cancel", {
|
||||||
|
defaultValue: "Batal",
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
<DialogClose asChild>
|
<DialogClose asChild>
|
||||||
<Button>
|
<Button>
|
||||||
{t("save", { defaultValue: "Simpan" })}
|
{t("save", {
|
||||||
|
defaultValue: "Simpan",
|
||||||
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1655,6 +1905,9 @@ export default function FormImageDetail() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1663,7 +1916,10 @@ export default function FormImageDetail() {
|
||||||
<div className="border-t border-gray-200 pt-6">
|
<div className="border-t border-gray-200 pt-6">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="comment" className="text-sm font-medium text-gray-900 mb-2 block">
|
<Label
|
||||||
|
htmlFor="comment"
|
||||||
|
className="text-sm font-medium text-gray-900 mb-2 block"
|
||||||
|
>
|
||||||
Komentar / Catatan:
|
Komentar / Catatan:
|
||||||
</Label>
|
</Label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|
@ -1679,17 +1935,23 @@ export default function FormImageDetail() {
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{status == "3" || status == "4" ? (
|
{status == "3" || status == "4" ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">Template Komentar Penolakan:</p>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Template Komentar Penolakan:
|
||||||
|
</p>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{[
|
{[
|
||||||
"Kualitas media kurang baik",
|
"Kualitas media kurang baik",
|
||||||
"Deskripsi kurang lengkap",
|
"Deskripsi kurang lengkap",
|
||||||
"Judul kurang tepat"
|
"Judul kurang tepat",
|
||||||
].map((template) => (
|
].map((template) => (
|
||||||
<Button
|
<Button
|
||||||
key={template}
|
key={template}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={description === template ? "default" : "outline"}
|
variant={
|
||||||
|
description === template
|
||||||
|
? "default"
|
||||||
|
: "outline"
|
||||||
|
}
|
||||||
className="text-xs"
|
className="text-xs"
|
||||||
onClick={() => setDescription(template)}
|
onClick={() => setDescription(template)}
|
||||||
>
|
>
|
||||||
|
|
@ -1700,22 +1962,27 @@ export default function FormImageDetail() {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">Template Komentar Persetujuan:</p>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Template Komentar Persetujuan:
|
||||||
|
</p>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{[
|
{["Konten sangat bagus", "Konten menarik"].map(
|
||||||
"Konten sangat bagus",
|
(template) => (
|
||||||
"Konten menarik"
|
|
||||||
].map((template) => (
|
|
||||||
<Button
|
<Button
|
||||||
key={template}
|
key={template}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={description === template ? "default" : "outline"}
|
variant={
|
||||||
|
description === template
|
||||||
|
? "default"
|
||||||
|
: "outline"
|
||||||
|
}
|
||||||
className="text-xs"
|
className="text-xs"
|
||||||
onClick={() => setDescription(template)}
|
onClick={() => setDescription(template)}
|
||||||
>
|
>
|
||||||
{template}
|
{template}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,12 @@ export default function FormTeksDetail() {
|
||||||
}>
|
}>
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||||
|
setIsUserMabesApprover(true);
|
||||||
|
}
|
||||||
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
// Fungsi untuk mengupdate state individual file
|
// Fungsi untuk mengupdate state individual file
|
||||||
const handleFileUnitChange = (
|
const handleFileUnitChange = (
|
||||||
fileIndex: number,
|
fileIndex: number,
|
||||||
|
|
@ -1266,6 +1272,13 @@ export default function FormTeksDetail() {
|
||||||
<p className="text-sm text-gray-600 break-all">
|
<p className="text-sm text-gray-600 break-all">
|
||||||
{file.fileName}
|
{file.fileName}
|
||||||
</p>
|
</p>
|
||||||
|
{isUserMabesApprover ? (
|
||||||
|
""
|
||||||
|
) : (
|
||||||
|
<p className="status text-success text-sm mb-0">
|
||||||
|
Selesai
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -1283,6 +1296,7 @@ export default function FormTeksDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
|
{isUserMabesApprover ? (
|
||||||
<div className="bg-white rounded-md p-4 border">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
<Icon
|
<Icon
|
||||||
|
|
@ -1449,7 +1463,9 @@ export default function FormTeksDetail() {
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleExpand(polda.id);
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
>
|
>
|
||||||
|
|
@ -1481,7 +1497,9 @@ export default function FormTeksDetail() {
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(sub.id)
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
@ -1501,7 +1519,9 @@ export default function FormTeksDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-indeterminate-small"
|
icon="material-symbols:check-indeterminate-small"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Batal Semua
|
Batal Semua
|
||||||
|
|
@ -1511,7 +1531,9 @@ export default function FormTeksDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-all"
|
icon="material-symbols:check-all"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Pilih Semua
|
Pilih Semua
|
||||||
|
|
@ -1583,6 +1605,9 @@ export default function FormTeksDetail() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,12 @@ export default function FormVideoDetail() {
|
||||||
}>
|
}>
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||||
|
setIsUserMabesApprover(true);
|
||||||
|
}
|
||||||
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
// Fungsi untuk mengupdate state individual file
|
// Fungsi untuk mengupdate state individual file
|
||||||
const handleFileUnitChange = (
|
const handleFileUnitChange = (
|
||||||
fileIndex: number,
|
fileIndex: number,
|
||||||
|
|
@ -1283,6 +1289,7 @@ export default function FormVideoDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
|
{isUserMabesApprover ? (
|
||||||
<div className="bg-white rounded-md p-4 border">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
<Icon
|
<Icon
|
||||||
|
|
@ -1449,7 +1456,9 @@ export default function FormVideoDetail() {
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleExpand(polda.id);
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
>
|
>
|
||||||
|
|
@ -1481,7 +1490,9 @@ export default function FormVideoDetail() {
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(sub.id)
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
@ -1501,7 +1512,9 @@ export default function FormVideoDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-indeterminate-small"
|
icon="material-symbols:check-indeterminate-small"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Batal Semua
|
Batal Semua
|
||||||
|
|
@ -1511,7 +1524,9 @@ export default function FormVideoDetail() {
|
||||||
<Icon
|
<Icon
|
||||||
icon="material-symbols:check-all"
|
icon="material-symbols:check-all"
|
||||||
width={12}
|
width={12}
|
||||||
height={12}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
className="mr-1"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
Pilih Semua
|
Pilih Semua
|
||||||
|
|
@ -1583,6 +1598,9 @@ export default function FormVideoDetail() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -533,16 +533,17 @@ const HeroNew = (props: { group?: string }) => {
|
||||||
|
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
{content && content.length > 0 && (
|
{content && content.length > 0 && (
|
||||||
|
<>
|
||||||
<Swiper
|
<Swiper
|
||||||
modules={[Autoplay, Navigation]}
|
modules={[Autoplay, Navigation]}
|
||||||
autoplay={{
|
autoplay={{
|
||||||
delay: 10000,
|
delay: 10000,
|
||||||
disableOnInteraction: false,
|
disableOnInteraction: false,
|
||||||
}}
|
}}
|
||||||
loop={true}
|
loop
|
||||||
navigation={{
|
navigation={{
|
||||||
nextEl: ".swiper-button-next",
|
nextEl: ".hero-next",
|
||||||
prevEl: ".swiper-button-prev",
|
prevEl: ".hero-prev",
|
||||||
}}
|
}}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
|
|
@ -580,29 +581,39 @@ const HeroNew = (props: { group?: string }) => {
|
||||||
<span className="text-red-600 text-[10px] lg:text-lg font-bold uppercase">
|
<span className="text-red-600 text-[10px] lg:text-lg font-bold uppercase">
|
||||||
{list?.categoryName}
|
{list?.categoryName}
|
||||||
</span>
|
</span>
|
||||||
<h2 className="text-[14px] lg:text-xl font-bold">{list?.title}</h2>
|
<h2 className="text-[14px] lg:text-xl font-bold">
|
||||||
|
{list?.title}
|
||||||
|
</h2>
|
||||||
<p className="text-[9px] lg:text-sm mt-2">
|
<p className="text-[9px] lg:text-sm mt-2">
|
||||||
{formatDateToIndonesian(new Date(list?.createdAt))}{" "}
|
{formatDateToIndonesian(new Date(list?.createdAt))}{" "}
|
||||||
{list?.timezone || "WIB"} | 👁 {list?.clickCount}
|
{list?.timezone || "WIB"} | 👁 {list?.clickCount}
|
||||||
</p>
|
</p>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="absolute left-2 top-[45%] z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full">
|
|
||||||
<Icon
|
|
||||||
icon="mdi:chevron-left"
|
|
||||||
className="w-5 lg:w-10 h-5 lg:h-10"
|
|
||||||
/>{" "}
|
|
||||||
</div>
|
|
||||||
<div className="absolute right-2 top-[45%] z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full">
|
|
||||||
<Icon
|
|
||||||
icon="mdi:chevron-right"
|
|
||||||
className="w-5 lg:w-10 h-5 lg:h-10"
|
|
||||||
/>{" "}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
|
{/* Tombol navigasi — render SEKALI dan beri selector yang di-bind */}
|
||||||
|
<button
|
||||||
|
className="hero-prev absolute left-2 top-1/2 z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full"
|
||||||
|
aria-label="Previous"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="mdi:chevron-left"
|
||||||
|
className="w-5 lg:w-10 h-5 lg:h-10"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="hero-next absolute right-2 top-1/2 z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full"
|
||||||
|
aria-label="Next"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="mdi:chevron-right"
|
||||||
|
className="w-5 lg:w-10 h-5 lg:h-10"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue