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,84 +1328,36 @@ export default function FormAudioDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
<div className="bg-white rounded-md p-4 border">
|
{isUserMabesApprover ? (
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<Icon
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
icon="material-symbols:settings-outline"
|
<Icon
|
||||||
width={18}
|
icon="material-symbols:settings-outline"
|
||||||
height={18}
|
width={18}
|
||||||
/>
|
height={18}
|
||||||
Pengaturan Distribusi
|
/>
|
||||||
</h5>
|
Pengaturan Distribusi
|
||||||
|
</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">
|
<p className="text-sm font-medium text-gray-700 mb-3">
|
||||||
Tingkat Distribusi:
|
Tingkat Distribusi:
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
|
||||||
{ key: "semua", label: "Semua" },
|
|
||||||
{ key: "nasional", label: "Nasional" },
|
|
||||||
{ key: "wilayah", label: "Wilayah" },
|
|
||||||
{
|
|
||||||
key: "international",
|
|
||||||
label: "Internasional",
|
|
||||||
},
|
|
||||||
].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"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
id={`${item.key}-${index}`}
|
|
||||||
checked={
|
|
||||||
fileUnitSelections[index]?.[
|
|
||||||
item.key as keyof typeof unitSelection
|
|
||||||
] || false
|
|
||||||
}
|
|
||||||
onCheckedChange={(value) => {
|
|
||||||
handleFileUnitChange(
|
|
||||||
index,
|
|
||||||
item.key as keyof typeof unitSelection,
|
|
||||||
value as boolean
|
|
||||||
);
|
|
||||||
setupPlacement(
|
|
||||||
index,
|
|
||||||
item.key,
|
|
||||||
Boolean(value)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${item.key}-${index}`}
|
|
||||||
className="text-sm font-medium cursor-pointer"
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Detail Wilayah */}
|
|
||||||
{fileUnitSelections[index]?.wilayah && (
|
|
||||||
<div className="border-t border-gray-200 pt-2">
|
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
|
||||||
Detail Wilayah:
|
|
||||||
</p>
|
</p>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
{[
|
||||||
{ key: "polda", label: "POLDA" },
|
{ key: "semua", label: "Semua" },
|
||||||
{ key: "polres", label: "POLRES" },
|
{ key: "nasional", label: "Nasional" },
|
||||||
{ key: "satker", label: "SATKER" },
|
{ key: "wilayah", label: "Wilayah" },
|
||||||
|
{
|
||||||
|
key: "international",
|
||||||
|
label: "Internasional",
|
||||||
|
},
|
||||||
].map((item, idx) => (
|
].map((item, idx) => (
|
||||||
<div
|
<div
|
||||||
key={item.key}
|
key={item.key}
|
||||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
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}`}
|
||||||
|
|
@ -1422,199 +1387,259 @@ export default function FormAudioDetail() {
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
{/* Detail Wilayah */}
|
||||||
<div className="flex items-center justify-center p-3">
|
{fileUnitSelections[index]?.wilayah && (
|
||||||
<Dialog>
|
<div className="border-t border-gray-200 pt-2">
|
||||||
<DialogTrigger asChild>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
<Button
|
Detail Wilayah:
|
||||||
variant="outline"
|
</p>
|
||||||
size="sm"
|
|
||||||
className="gap-2"
|
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||||
|
{[
|
||||||
|
{ key: "polda", label: "POLDA" },
|
||||||
|
{ key: "polres", label: "POLRES" },
|
||||||
|
{ key: "satker", label: "SATKER" },
|
||||||
|
].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"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
id={`${item.key}-${index}`}
|
||||||
|
checked={
|
||||||
|
fileUnitSelections[index]?.[
|
||||||
|
item.key as keyof typeof unitSelection
|
||||||
|
] || false
|
||||||
|
}
|
||||||
|
onCheckedChange={(value) => {
|
||||||
|
handleFileUnitChange(
|
||||||
|
index,
|
||||||
|
item.key as keyof typeof unitSelection,
|
||||||
|
value as boolean
|
||||||
|
);
|
||||||
|
setupPlacement(
|
||||||
|
index,
|
||||||
|
item.key,
|
||||||
|
Boolean(value)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`${item.key}-${index}`}
|
||||||
|
className="text-sm font-medium cursor-pointer"
|
||||||
>
|
>
|
||||||
<Icon
|
{item.label}
|
||||||
icon="material-symbols:tune"
|
</Label>
|
||||||
width={16}
|
</div>
|
||||||
height={16}
|
))}
|
||||||
/>
|
|
||||||
{t("custom", {
|
|
||||||
defaultValue: "Kustom",
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
|
||||||
<DialogHeader className="border-b border-gray-200 pb-4">
|
|
||||||
<DialogTitle className="text-lg font-semibold">
|
|
||||||
Daftar Wilayah POLDA dan POLRES
|
|
||||||
</DialogTitle>
|
|
||||||
</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">
|
|
||||||
{listDest.map((polda: any) => (
|
|
||||||
<div
|
|
||||||
key={polda.id}
|
|
||||||
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
|
||||||
>
|
|
||||||
{/* Header POLDA */}
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
|
||||||
<Checkbox
|
|
||||||
checked={
|
|
||||||
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>
|
|
||||||
</Label>
|
|
||||||
{polda.subDestination && (
|
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
toggleExpand(polda.id);
|
|
||||||
}}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon={
|
|
||||||
expandedPolda[
|
|
||||||
polda.id
|
|
||||||
]
|
|
||||||
? "mdi:chevron-up"
|
|
||||||
: "mdi:chevron-down"
|
|
||||||
}
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sub-items */}
|
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||||
{polda.subDestination &&
|
<div className="flex items-center justify-center p-3">
|
||||||
expandedPolda[polda.id] && (
|
<Dialog>
|
||||||
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
<DialogTrigger asChild>
|
||||||
{/* Tombol Pilih Semua untuk sub-items */}
|
<Button
|
||||||
<div className="mb-2 flex justify-start">
|
variant="outline"
|
||||||
{(() => {
|
size="sm"
|
||||||
const allSubItemsChecked =
|
className="gap-2"
|
||||||
polda.subDestination?.every(
|
>
|
||||||
(sub: any) =>
|
<Icon
|
||||||
fileCheckedLevels[
|
icon="material-symbols:tune"
|
||||||
index
|
width={16}
|
||||||
]?.has(
|
height={16}
|
||||||
Number(sub.id)
|
/>
|
||||||
)
|
{t("custom", {
|
||||||
);
|
defaultValue: "Kustom",
|
||||||
return (
|
})}
|
||||||
<Button
|
</Button>
|
||||||
size="sm"
|
</DialogTrigger>
|
||||||
variant="outline"
|
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
||||||
className="text-xs h-6 px-2"
|
<DialogHeader className="border-b border-gray-200 pb-4">
|
||||||
onClick={() =>
|
<DialogTitle className="text-lg font-semibold">
|
||||||
handleSelectAllSubItems(
|
Daftar Wilayah POLDA dan POLRES
|
||||||
index,
|
</DialogTitle>
|
||||||
polda
|
</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">
|
||||||
}
|
{listDest.map((polda: any) => (
|
||||||
>
|
<div
|
||||||
{allSubItemsChecked ? (
|
key={polda.id}
|
||||||
<>
|
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
||||||
<Icon
|
>
|
||||||
icon="material-symbols:check-indeterminate-small"
|
{/* Header POLDA */}
|
||||||
width={12}
|
<div className="flex items-center justify-between">
|
||||||
height={12}
|
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
||||||
className="mr-1"
|
<Checkbox
|
||||||
/>
|
checked={
|
||||||
Batal Semua
|
fileCheckedLevels[
|
||||||
</>
|
index
|
||||||
) : (
|
]?.has(
|
||||||
<>
|
Number(polda.id)
|
||||||
<Icon
|
) || false
|
||||||
icon="material-symbols:check-all"
|
}
|
||||||
width={12}
|
onCheckedChange={() =>
|
||||||
height={12}
|
handleFileCheckboxChangePlacement(
|
||||||
className="mr-1"
|
index,
|
||||||
/>
|
Number(polda.id)
|
||||||
Pilih Semua
|
)
|
||||||
</>
|
}
|
||||||
)}
|
/>
|
||||||
</Button>
|
<span className="font-semibold text-gray-900 text-sm">
|
||||||
|
{polda.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
{polda.subDestination && (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
);
|
);
|
||||||
})()}
|
}}
|
||||||
</div>
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
<div className="space-y-1">
|
>
|
||||||
{polda.subDestination.map(
|
<Icon
|
||||||
(sub: any) => (
|
icon={
|
||||||
<Label
|
expandedPolda[
|
||||||
key={sub.id}
|
polda.id
|
||||||
className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
|
]
|
||||||
>
|
? "mdi:chevron-up"
|
||||||
<Checkbox
|
: "mdi:chevron-down"
|
||||||
checked={
|
}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sub-items */}
|
||||||
|
{polda.subDestination &&
|
||||||
|
expandedPolda[polda.id] && (
|
||||||
|
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
||||||
|
{/* Tombol Pilih Semua untuk sub-items */}
|
||||||
|
<div className="mb-2 flex justify-start">
|
||||||
|
{(() => {
|
||||||
|
const allSubItemsChecked =
|
||||||
|
polda.subDestination?.every(
|
||||||
|
(sub: any) =>
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(
|
Number(
|
||||||
sub.id
|
sub.id
|
||||||
)
|
)
|
||||||
) || false
|
)
|
||||||
}
|
);
|
||||||
onCheckedChange={() =>
|
return (
|
||||||
handleFileCheckboxChangePlacement(
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs h-6 px-2"
|
||||||
|
onClick={() =>
|
||||||
|
handleSelectAllSubItems(
|
||||||
index,
|
index,
|
||||||
Number(
|
polda
|
||||||
sub.id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
<span className="text-gray-700">
|
{allSubItemsChecked ? (
|
||||||
{sub.name}
|
<>
|
||||||
</span>
|
<Icon
|
||||||
</Label>
|
icon="material-symbols:check-indeterminate-small"
|
||||||
)
|
width={12}
|
||||||
)}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Batal Semua
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:check-all"
|
||||||
|
width={12}
|
||||||
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Pilih Semua
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
{polda.subDestination.map(
|
||||||
|
(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
|
||||||
|
checked={
|
||||||
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
) || false
|
||||||
|
}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleFileCheckboxChangePlacement(
|
||||||
|
index,
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="text-gray-700">
|
||||||
|
{sub.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
<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", {
|
||||||
{t("cancel", {
|
defaultValue: "Batal",
|
||||||
defaultValue: "Batal",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
<DialogClose asChild>
|
||||||
<DialogClose asChild>
|
<Button>
|
||||||
<Button>
|
{t("save", {
|
||||||
{t("save", {
|
defaultValue: "Simpan",
|
||||||
defaultValue: "Simpan",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
</div>
|
||||||
</div>
|
</DialogContent>
|
||||||
</DialogContent>
|
</Dialog>
|
||||||
</Dialog>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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,84 +1296,36 @@ export default function FormTeksDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
<div className="bg-white rounded-md p-4 border">
|
{isUserMabesApprover ? (
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<Icon
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
icon="material-symbols:settings-outline"
|
<Icon
|
||||||
width={18}
|
icon="material-symbols:settings-outline"
|
||||||
height={18}
|
width={18}
|
||||||
/>
|
height={18}
|
||||||
Pengaturan Distribusi
|
/>
|
||||||
</h5>
|
Pengaturan Distribusi
|
||||||
|
</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">
|
<p className="text-sm font-medium text-gray-700 mb-3">
|
||||||
Tingkat Distribusi:
|
Tingkat Distribusi:
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
|
||||||
{ key: "semua", label: "Semua" },
|
|
||||||
{ key: "nasional", label: "Nasional" },
|
|
||||||
{ key: "wilayah", label: "Wilayah" },
|
|
||||||
{
|
|
||||||
key: "international",
|
|
||||||
label: "Internasional",
|
|
||||||
},
|
|
||||||
].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"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
id={`${item.key}-${index}`}
|
|
||||||
checked={
|
|
||||||
fileUnitSelections[index]?.[
|
|
||||||
item.key as keyof typeof unitSelection
|
|
||||||
] || false
|
|
||||||
}
|
|
||||||
onCheckedChange={(value) => {
|
|
||||||
handleFileUnitChange(
|
|
||||||
index,
|
|
||||||
item.key as keyof typeof unitSelection,
|
|
||||||
value as boolean
|
|
||||||
);
|
|
||||||
setupPlacement(
|
|
||||||
index,
|
|
||||||
item.key,
|
|
||||||
Boolean(value)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${item.key}-${index}`}
|
|
||||||
className="text-sm font-medium cursor-pointer"
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Detail Wilayah */}
|
|
||||||
{fileUnitSelections[index]?.wilayah && (
|
|
||||||
<div className="border-t border-gray-200 pt-2">
|
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
|
||||||
Detail Wilayah:
|
|
||||||
</p>
|
</p>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
{[
|
||||||
{ key: "polda", label: "POLDA" },
|
{ key: "semua", label: "Semua" },
|
||||||
{ key: "polres", label: "POLRES" },
|
{ key: "nasional", label: "Nasional" },
|
||||||
{ key: "satker", label: "SATKER" },
|
{ key: "wilayah", label: "Wilayah" },
|
||||||
|
{
|
||||||
|
key: "international",
|
||||||
|
label: "Internasional",
|
||||||
|
},
|
||||||
].map((item, idx) => (
|
].map((item, idx) => (
|
||||||
<div
|
<div
|
||||||
key={item.key}
|
key={item.key}
|
||||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
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}`}
|
||||||
|
|
@ -1390,199 +1355,259 @@ export default function FormTeksDetail() {
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
{/* Detail Wilayah */}
|
||||||
<div className="flex items-center justify-center p-3">
|
{fileUnitSelections[index]?.wilayah && (
|
||||||
<Dialog>
|
<div className="border-t border-gray-200 pt-2">
|
||||||
<DialogTrigger asChild>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
<Button
|
Detail Wilayah:
|
||||||
variant="outline"
|
</p>
|
||||||
size="sm"
|
|
||||||
className="gap-2"
|
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||||
|
{[
|
||||||
|
{ key: "polda", label: "POLDA" },
|
||||||
|
{ key: "polres", label: "POLRES" },
|
||||||
|
{ key: "satker", label: "SATKER" },
|
||||||
|
].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"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
id={`${item.key}-${index}`}
|
||||||
|
checked={
|
||||||
|
fileUnitSelections[index]?.[
|
||||||
|
item.key as keyof typeof unitSelection
|
||||||
|
] || false
|
||||||
|
}
|
||||||
|
onCheckedChange={(value) => {
|
||||||
|
handleFileUnitChange(
|
||||||
|
index,
|
||||||
|
item.key as keyof typeof unitSelection,
|
||||||
|
value as boolean
|
||||||
|
);
|
||||||
|
setupPlacement(
|
||||||
|
index,
|
||||||
|
item.key,
|
||||||
|
Boolean(value)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`${item.key}-${index}`}
|
||||||
|
className="text-sm font-medium cursor-pointer"
|
||||||
>
|
>
|
||||||
<Icon
|
{item.label}
|
||||||
icon="material-symbols:tune"
|
</Label>
|
||||||
width={16}
|
</div>
|
||||||
height={16}
|
))}
|
||||||
/>
|
|
||||||
{t("custom", {
|
|
||||||
defaultValue: "Kustom",
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
|
||||||
<DialogHeader className="border-b border-gray-200 pb-4">
|
|
||||||
<DialogTitle className="text-lg font-semibold">
|
|
||||||
Daftar Wilayah POLDA dan POLRES
|
|
||||||
</DialogTitle>
|
|
||||||
</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">
|
|
||||||
{listDest.map((polda: any) => (
|
|
||||||
<div
|
|
||||||
key={polda.id}
|
|
||||||
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
|
||||||
>
|
|
||||||
{/* Header POLDA */}
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
|
||||||
<Checkbox
|
|
||||||
checked={
|
|
||||||
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>
|
|
||||||
</Label>
|
|
||||||
{polda.subDestination && (
|
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
toggleExpand(polda.id);
|
|
||||||
}}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon={
|
|
||||||
expandedPolda[
|
|
||||||
polda.id
|
|
||||||
]
|
|
||||||
? "mdi:chevron-up"
|
|
||||||
: "mdi:chevron-down"
|
|
||||||
}
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sub-items */}
|
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||||
{polda.subDestination &&
|
<div className="flex items-center justify-center p-3">
|
||||||
expandedPolda[polda.id] && (
|
<Dialog>
|
||||||
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
<DialogTrigger asChild>
|
||||||
{/* Tombol Pilih Semua untuk sub-items */}
|
<Button
|
||||||
<div className="mb-2 flex justify-start">
|
variant="outline"
|
||||||
{(() => {
|
size="sm"
|
||||||
const allSubItemsChecked =
|
className="gap-2"
|
||||||
polda.subDestination?.every(
|
>
|
||||||
(sub: any) =>
|
<Icon
|
||||||
fileCheckedLevels[
|
icon="material-symbols:tune"
|
||||||
index
|
width={16}
|
||||||
]?.has(
|
height={16}
|
||||||
Number(sub.id)
|
/>
|
||||||
)
|
{t("custom", {
|
||||||
);
|
defaultValue: "Kustom",
|
||||||
return (
|
})}
|
||||||
<Button
|
</Button>
|
||||||
size="sm"
|
</DialogTrigger>
|
||||||
variant="outline"
|
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
||||||
className="text-xs h-6 px-2"
|
<DialogHeader className="border-b border-gray-200 pb-4">
|
||||||
onClick={() =>
|
<DialogTitle className="text-lg font-semibold">
|
||||||
handleSelectAllSubItems(
|
Daftar Wilayah POLDA dan POLRES
|
||||||
index,
|
</DialogTitle>
|
||||||
polda
|
</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">
|
||||||
}
|
{listDest.map((polda: any) => (
|
||||||
>
|
<div
|
||||||
{allSubItemsChecked ? (
|
key={polda.id}
|
||||||
<>
|
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
||||||
<Icon
|
>
|
||||||
icon="material-symbols:check-indeterminate-small"
|
{/* Header POLDA */}
|
||||||
width={12}
|
<div className="flex items-center justify-between">
|
||||||
height={12}
|
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
||||||
className="mr-1"
|
<Checkbox
|
||||||
/>
|
checked={
|
||||||
Batal Semua
|
fileCheckedLevels[
|
||||||
</>
|
index
|
||||||
) : (
|
]?.has(
|
||||||
<>
|
Number(polda.id)
|
||||||
<Icon
|
) || false
|
||||||
icon="material-symbols:check-all"
|
}
|
||||||
width={12}
|
onCheckedChange={() =>
|
||||||
height={12}
|
handleFileCheckboxChangePlacement(
|
||||||
className="mr-1"
|
index,
|
||||||
/>
|
Number(polda.id)
|
||||||
Pilih Semua
|
)
|
||||||
</>
|
}
|
||||||
)}
|
/>
|
||||||
</Button>
|
<span className="font-semibold text-gray-900 text-sm">
|
||||||
|
{polda.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
{polda.subDestination && (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
);
|
);
|
||||||
})()}
|
}}
|
||||||
</div>
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
<div className="space-y-1">
|
>
|
||||||
{polda.subDestination.map(
|
<Icon
|
||||||
(sub: any) => (
|
icon={
|
||||||
<Label
|
expandedPolda[
|
||||||
key={sub.id}
|
polda.id
|
||||||
className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
|
]
|
||||||
>
|
? "mdi:chevron-up"
|
||||||
<Checkbox
|
: "mdi:chevron-down"
|
||||||
checked={
|
}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sub-items */}
|
||||||
|
{polda.subDestination &&
|
||||||
|
expandedPolda[polda.id] && (
|
||||||
|
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
||||||
|
{/* Tombol Pilih Semua untuk sub-items */}
|
||||||
|
<div className="mb-2 flex justify-start">
|
||||||
|
{(() => {
|
||||||
|
const allSubItemsChecked =
|
||||||
|
polda.subDestination?.every(
|
||||||
|
(sub: any) =>
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(
|
Number(
|
||||||
sub.id
|
sub.id
|
||||||
)
|
)
|
||||||
) || false
|
)
|
||||||
}
|
);
|
||||||
onCheckedChange={() =>
|
return (
|
||||||
handleFileCheckboxChangePlacement(
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs h-6 px-2"
|
||||||
|
onClick={() =>
|
||||||
|
handleSelectAllSubItems(
|
||||||
index,
|
index,
|
||||||
Number(
|
polda
|
||||||
sub.id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
<span className="text-gray-700">
|
{allSubItemsChecked ? (
|
||||||
{sub.name}
|
<>
|
||||||
</span>
|
<Icon
|
||||||
</Label>
|
icon="material-symbols:check-indeterminate-small"
|
||||||
)
|
width={12}
|
||||||
)}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Batal Semua
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:check-all"
|
||||||
|
width={12}
|
||||||
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Pilih Semua
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
{polda.subDestination.map(
|
||||||
|
(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
|
||||||
|
checked={
|
||||||
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
) || false
|
||||||
|
}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleFileCheckboxChangePlacement(
|
||||||
|
index,
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="text-gray-700">
|
||||||
|
{sub.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
<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", {
|
||||||
{t("cancel", {
|
defaultValue: "Batal",
|
||||||
defaultValue: "Batal",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
<DialogClose asChild>
|
||||||
<DialogClose asChild>
|
<Button>
|
||||||
<Button>
|
{t("save", {
|
||||||
{t("save", {
|
defaultValue: "Simpan",
|
||||||
defaultValue: "Simpan",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
</div>
|
||||||
</div>
|
</DialogContent>
|
||||||
</DialogContent>
|
</Dialog>
|
||||||
</Dialog>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</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,84 +1289,36 @@ export default function FormVideoDetail() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Pengaturan Distribusi */}
|
{/* Section Pengaturan Distribusi */}
|
||||||
<div className="bg-white rounded-md p-4 border">
|
{isUserMabesApprover ? (
|
||||||
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
<div className="bg-white rounded-md p-4 border">
|
||||||
<Icon
|
<h5 className="font-medium text-gray-900 mb-4 flex items-center gap-2">
|
||||||
icon="material-symbols:settings-outline"
|
<Icon
|
||||||
width={18}
|
icon="material-symbols:settings-outline"
|
||||||
height={18}
|
width={18}
|
||||||
/>
|
height={18}
|
||||||
Pengaturan Distribusi
|
/>
|
||||||
</h5>
|
Pengaturan Distribusi
|
||||||
|
</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">
|
<p className="text-sm font-medium text-gray-700 mb-3">
|
||||||
Tingkat Distribusi:
|
Tingkat Distribusi:
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
|
||||||
{ key: "semua", label: "Semua" },
|
|
||||||
{ key: "nasional", label: "Nasional" },
|
|
||||||
{ key: "wilayah", label: "Wilayah" },
|
|
||||||
{
|
|
||||||
key: "international",
|
|
||||||
label: "Internasional",
|
|
||||||
},
|
|
||||||
].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"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
id={`${item.key}-${index}`}
|
|
||||||
checked={
|
|
||||||
fileUnitSelections[index]?.[
|
|
||||||
item.key as keyof typeof unitSelection
|
|
||||||
] || false
|
|
||||||
}
|
|
||||||
onCheckedChange={(value) => {
|
|
||||||
handleFileUnitChange(
|
|
||||||
index,
|
|
||||||
item.key as keyof typeof unitSelection,
|
|
||||||
value as boolean
|
|
||||||
);
|
|
||||||
setupPlacement(
|
|
||||||
index,
|
|
||||||
item.key,
|
|
||||||
Boolean(value)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${item.key}-${index}`}
|
|
||||||
className="text-sm font-medium cursor-pointer"
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Detail Wilayah */}
|
|
||||||
{fileUnitSelections[index]?.wilayah && (
|
|
||||||
<div className="border-t border-gray-200 pt-2">
|
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
|
||||||
Detail Wilayah:
|
|
||||||
</p>
|
</p>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
|
||||||
{[
|
{[
|
||||||
{ key: "polda", label: "POLDA" },
|
{ key: "semua", label: "Semua" },
|
||||||
{ key: "polres", label: "POLRES" },
|
{ key: "nasional", label: "Nasional" },
|
||||||
{ key: "satker", label: "SATKER" },
|
{ key: "wilayah", label: "Wilayah" },
|
||||||
|
{
|
||||||
|
key: "international",
|
||||||
|
label: "Internasional",
|
||||||
|
},
|
||||||
].map((item, idx) => (
|
].map((item, idx) => (
|
||||||
<div
|
<div
|
||||||
key={item.key}
|
key={item.key}
|
||||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
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}`}
|
||||||
|
|
@ -1390,199 +1348,259 @@ export default function FormVideoDetail() {
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
{/* Detail Wilayah */}
|
||||||
<div className="flex items-center justify-center p-3">
|
{fileUnitSelections[index]?.wilayah && (
|
||||||
<Dialog>
|
<div className="border-t border-gray-200 pt-2">
|
||||||
<DialogTrigger asChild>
|
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||||
<Button
|
Detail Wilayah:
|
||||||
variant="outline"
|
</p>
|
||||||
size="sm"
|
|
||||||
className="gap-2"
|
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||||
|
{[
|
||||||
|
{ key: "polda", label: "POLDA" },
|
||||||
|
{ key: "polres", label: "POLRES" },
|
||||||
|
{ key: "satker", label: "SATKER" },
|
||||||
|
].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"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
id={`${item.key}-${index}`}
|
||||||
|
checked={
|
||||||
|
fileUnitSelections[index]?.[
|
||||||
|
item.key as keyof typeof unitSelection
|
||||||
|
] || false
|
||||||
|
}
|
||||||
|
onCheckedChange={(value) => {
|
||||||
|
handleFileUnitChange(
|
||||||
|
index,
|
||||||
|
item.key as keyof typeof unitSelection,
|
||||||
|
value as boolean
|
||||||
|
);
|
||||||
|
setupPlacement(
|
||||||
|
index,
|
||||||
|
item.key,
|
||||||
|
Boolean(value)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`${item.key}-${index}`}
|
||||||
|
className="text-sm font-medium cursor-pointer"
|
||||||
>
|
>
|
||||||
<Icon
|
{item.label}
|
||||||
icon="material-symbols:tune"
|
</Label>
|
||||||
width={16}
|
</div>
|
||||||
height={16}
|
))}
|
||||||
/>
|
|
||||||
{t("custom", {
|
|
||||||
defaultValue: "Kustom",
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
|
||||||
<DialogHeader className="border-b border-gray-200 pb-4">
|
|
||||||
<DialogTitle className="text-lg font-semibold">
|
|
||||||
Daftar Wilayah POLDA dan POLRES
|
|
||||||
</DialogTitle>
|
|
||||||
</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">
|
|
||||||
{listDest.map((polda: any) => (
|
|
||||||
<div
|
|
||||||
key={polda.id}
|
|
||||||
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
|
||||||
>
|
|
||||||
{/* Header POLDA */}
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
|
||||||
<Checkbox
|
|
||||||
checked={
|
|
||||||
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>
|
|
||||||
</Label>
|
|
||||||
{polda.subDestination && (
|
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
toggleExpand(polda.id);
|
|
||||||
}}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon={
|
|
||||||
expandedPolda[
|
|
||||||
polda.id
|
|
||||||
]
|
|
||||||
? "mdi:chevron-up"
|
|
||||||
: "mdi:chevron-down"
|
|
||||||
}
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sub-items */}
|
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||||
{polda.subDestination &&
|
<div className="flex items-center justify-center p-3">
|
||||||
expandedPolda[polda.id] && (
|
<Dialog>
|
||||||
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
<DialogTrigger asChild>
|
||||||
{/* Tombol Pilih Semua untuk sub-items */}
|
<Button
|
||||||
<div className="mb-2 flex justify-start">
|
variant="outline"
|
||||||
{(() => {
|
size="sm"
|
||||||
const allSubItemsChecked =
|
className="gap-2"
|
||||||
polda.subDestination?.every(
|
>
|
||||||
(sub: any) =>
|
<Icon
|
||||||
fileCheckedLevels[
|
icon="material-symbols:tune"
|
||||||
index
|
width={16}
|
||||||
]?.has(
|
height={16}
|
||||||
Number(sub.id)
|
/>
|
||||||
)
|
{t("custom", {
|
||||||
);
|
defaultValue: "Kustom",
|
||||||
return (
|
})}
|
||||||
<Button
|
</Button>
|
||||||
size="sm"
|
</DialogTrigger>
|
||||||
variant="outline"
|
<DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
|
||||||
className="text-xs h-6 px-2"
|
<DialogHeader className="border-b border-gray-200 pb-4">
|
||||||
onClick={() =>
|
<DialogTitle className="text-lg font-semibold">
|
||||||
handleSelectAllSubItems(
|
Daftar Wilayah POLDA dan POLRES
|
||||||
index,
|
</DialogTitle>
|
||||||
polda
|
</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">
|
||||||
}
|
{listDest.map((polda: any) => (
|
||||||
>
|
<div
|
||||||
{allSubItemsChecked ? (
|
key={polda.id}
|
||||||
<>
|
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
|
||||||
<Icon
|
>
|
||||||
icon="material-symbols:check-indeterminate-small"
|
{/* Header POLDA */}
|
||||||
width={12}
|
<div className="flex items-center justify-between">
|
||||||
height={12}
|
<Label className="flex items-center gap-3 flex-1 cursor-pointer">
|
||||||
className="mr-1"
|
<Checkbox
|
||||||
/>
|
checked={
|
||||||
Batal Semua
|
fileCheckedLevels[
|
||||||
</>
|
index
|
||||||
) : (
|
]?.has(
|
||||||
<>
|
Number(polda.id)
|
||||||
<Icon
|
) || false
|
||||||
icon="material-symbols:check-all"
|
}
|
||||||
width={12}
|
onCheckedChange={() =>
|
||||||
height={12}
|
handleFileCheckboxChangePlacement(
|
||||||
className="mr-1"
|
index,
|
||||||
/>
|
Number(polda.id)
|
||||||
Pilih Semua
|
)
|
||||||
</>
|
}
|
||||||
)}
|
/>
|
||||||
</Button>
|
<span className="font-semibold text-gray-900 text-sm">
|
||||||
|
{polda.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
{polda.subDestination && (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleExpand(
|
||||||
|
polda.id
|
||||||
);
|
);
|
||||||
})()}
|
}}
|
||||||
</div>
|
className="p-1 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
<div className="space-y-1">
|
>
|
||||||
{polda.subDestination.map(
|
<Icon
|
||||||
(sub: any) => (
|
icon={
|
||||||
<Label
|
expandedPolda[
|
||||||
key={sub.id}
|
polda.id
|
||||||
className="flex items-center gap-2 p-2 rounded-md hover:bg-gray-50 transition-colors cursor-pointer text-xs"
|
]
|
||||||
>
|
? "mdi:chevron-up"
|
||||||
<Checkbox
|
: "mdi:chevron-down"
|
||||||
checked={
|
}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sub-items */}
|
||||||
|
{polda.subDestination &&
|
||||||
|
expandedPolda[polda.id] && (
|
||||||
|
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
|
||||||
|
{/* Tombol Pilih Semua untuk sub-items */}
|
||||||
|
<div className="mb-2 flex justify-start">
|
||||||
|
{(() => {
|
||||||
|
const allSubItemsChecked =
|
||||||
|
polda.subDestination?.every(
|
||||||
|
(sub: any) =>
|
||||||
fileCheckedLevels[
|
fileCheckedLevels[
|
||||||
index
|
index
|
||||||
]?.has(
|
]?.has(
|
||||||
Number(
|
Number(
|
||||||
sub.id
|
sub.id
|
||||||
)
|
)
|
||||||
) || false
|
)
|
||||||
}
|
);
|
||||||
onCheckedChange={() =>
|
return (
|
||||||
handleFileCheckboxChangePlacement(
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs h-6 px-2"
|
||||||
|
onClick={() =>
|
||||||
|
handleSelectAllSubItems(
|
||||||
index,
|
index,
|
||||||
Number(
|
polda
|
||||||
sub.id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
<span className="text-gray-700">
|
{allSubItemsChecked ? (
|
||||||
{sub.name}
|
<>
|
||||||
</span>
|
<Icon
|
||||||
</Label>
|
icon="material-symbols:check-indeterminate-small"
|
||||||
)
|
width={12}
|
||||||
)}
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Batal Semua
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Icon
|
||||||
|
icon="material-symbols:check-all"
|
||||||
|
width={12}
|
||||||
|
height={
|
||||||
|
12
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
/>
|
||||||
|
Pilih Semua
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
{polda.subDestination.map(
|
||||||
|
(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
|
||||||
|
checked={
|
||||||
|
fileCheckedLevels[
|
||||||
|
index
|
||||||
|
]?.has(
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
) || false
|
||||||
|
}
|
||||||
|
onCheckedChange={() =>
|
||||||
|
handleFileCheckboxChangePlacement(
|
||||||
|
index,
|
||||||
|
Number(
|
||||||
|
sub.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="text-gray-700">
|
||||||
|
{sub.name}
|
||||||
|
</span>
|
||||||
|
</Label>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
<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", {
|
||||||
{t("cancel", {
|
defaultValue: "Batal",
|
||||||
defaultValue: "Batal",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
<DialogClose asChild>
|
||||||
<DialogClose asChild>
|
<Button>
|
||||||
<Button>
|
{t("save", {
|
||||||
{t("save", {
|
defaultValue: "Simpan",
|
||||||
defaultValue: "Simpan",
|
})}
|
||||||
})}
|
</Button>
|
||||||
</Button>
|
</DialogClose>
|
||||||
</DialogClose>
|
</div>
|
||||||
</div>
|
</DialogContent>
|
||||||
</DialogContent>
|
</Dialog>
|
||||||
</Dialog>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -533,76 +533,87 @@ const HeroNew = (props: { group?: string }) => {
|
||||||
|
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
{content && content.length > 0 && (
|
{content && content.length > 0 && (
|
||||||
<Swiper
|
<>
|
||||||
modules={[Autoplay, Navigation]}
|
<Swiper
|
||||||
autoplay={{
|
modules={[Autoplay, Navigation]}
|
||||||
delay: 10000,
|
autoplay={{
|
||||||
disableOnInteraction: false,
|
delay: 10000,
|
||||||
}}
|
disableOnInteraction: false,
|
||||||
loop={true}
|
}}
|
||||||
navigation={{
|
loop
|
||||||
nextEl: ".swiper-button-next",
|
navigation={{
|
||||||
prevEl: ".swiper-button-prev",
|
nextEl: ".hero-next",
|
||||||
}}
|
prevEl: ".hero-prev",
|
||||||
className="w-full"
|
}}
|
||||||
>
|
className="w-full"
|
||||||
{content.map((list: any) => (
|
>
|
||||||
<SwiperSlide key={list?.id}>
|
{content.map((list: any) => (
|
||||||
<div className="relative h-[310px] lg:h-[700px]">
|
<SwiperSlide key={list?.id}>
|
||||||
{/* Gambar */}
|
<div className="relative h-[310px] lg:h-[700px]">
|
||||||
<ImageBlurry
|
{/* Gambar */}
|
||||||
priority
|
<ImageBlurry
|
||||||
src={list?.smallThumbnailLink}
|
priority
|
||||||
alt="gambar"
|
src={list?.smallThumbnailLink}
|
||||||
style={{
|
alt="gambar"
|
||||||
objectFit: "contain",
|
style={{
|
||||||
width: "100%",
|
objectFit: "contain",
|
||||||
height: "100%",
|
width: "100%",
|
||||||
}}
|
height: "100%",
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Overlay */}
|
{/* Overlay */}
|
||||||
<div className="absolute inset-0 bg-black/40 z-10" />
|
<div className="absolute inset-0 bg-black/40 z-10" />
|
||||||
|
|
||||||
{/* Judul & Link */}
|
{/* Judul & Link */}
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
Number(list?.fileTypeId) === 1
|
Number(list?.fileTypeId) === 1
|
||||||
? `${prefixPath}/image/detail/${list?.slug}`
|
? `${prefixPath}/image/detail/${list?.slug}`
|
||||||
: Number(list?.fileTypeId) === 2
|
: Number(list?.fileTypeId) === 2
|
||||||
? `${prefixPath}/video/detail/${list?.slug}`
|
? `${prefixPath}/video/detail/${list?.slug}`
|
||||||
: Number(list?.fileTypeId) === 3
|
: Number(list?.fileTypeId) === 3
|
||||||
? `${prefixPath}/document/detail/${list?.slug}`
|
? `${prefixPath}/document/detail/${list?.slug}`
|
||||||
: `${prefixPath}/audio/detail/${list?.slug}`
|
: `${prefixPath}/audio/detail/${list?.slug}`
|
||||||
}
|
}
|
||||||
className="absolute bottom-10 lg:bottom-20 left-8 lg:left-32 z-20 text-white w-[85%] lg:w-[45%] cursor-pointer"
|
className="absolute bottom-10 lg:bottom-20 left-8 lg:left-32 z-20 text-white w-[85%] lg:w-[45%] cursor-pointer"
|
||||||
>
|
>
|
||||||
<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">
|
||||||
<p className="text-[9px] lg:text-sm mt-2">
|
{list?.title}
|
||||||
{formatDateToIndonesian(new Date(list?.createdAt))}{" "}
|
</h2>
|
||||||
{list?.timezone || "WIB"} | 👁 {list?.clickCount}
|
<p className="text-[9px] lg:text-sm mt-2">
|
||||||
</p>
|
{formatDateToIndonesian(new Date(list?.createdAt))}{" "}
|
||||||
</Link>
|
{list?.timezone || "WIB"} | 👁 {list?.clickCount}
|
||||||
|
</p>
|
||||||
<div className="absolute left-2 top-[45%] z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full">
|
</Link>
|
||||||
<Icon
|
|
||||||
icon="mdi:chevron-left"
|
|
||||||
className="w-5 lg:w-10 h-5 lg:h-10"
|
|
||||||
/>{" "}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute right-2 top-[45%] z-30 -translate-y-1/2 hover:bg-black/70 text-white p-2 rounded-full">
|
</SwiperSlide>
|
||||||
<Icon
|
))}
|
||||||
icon="mdi:chevron-right"
|
</Swiper>
|
||||||
className="w-5 lg:w-10 h-5 lg:h-10"
|
|
||||||
/>{" "}
|
{/* Tombol navigasi — render SEKALI dan beri selector yang di-bind */}
|
||||||
</div>
|
<button
|
||||||
</div>
|
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"
|
||||||
</SwiperSlide>
|
aria-label="Previous"
|
||||||
))}
|
>
|
||||||
</Swiper>
|
<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