fix: satker section all and maps

This commit is contained in:
Sabda Yagra 2026-02-11 17:12:50 +07:00
parent 44c6cc6d9d
commit 740d73d689
9 changed files with 1321 additions and 1100 deletions

View File

@ -115,7 +115,7 @@ const ViewEditor = dynamic(
() => { () => {
return import("@/components/editor/view-editor"); return import("@/components/editor/view-editor");
}, },
{ ssr: false } { ssr: false },
); );
interface Destination { interface Destination {
@ -198,6 +198,12 @@ export default function FormAudioDetail() {
satker: boolean; satker: boolean;
}> }>
>([]); >([]);
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
null,
);
const isContentFromSatker = creatorLevelNumber === 3;
const isContentFromMabesOrPolda =
creatorLevelNumber === 1 || creatorLevelNumber === 2;
useEffect(() => { useEffect(() => {
if (Number(userLevelId) === 216 && Number(roleId) === 3) { if (Number(userLevelId) === 216 && Number(roleId) === 3) {
@ -209,7 +215,7 @@ export default function FormAudioDetail() {
const handleFileUnitChange = ( const handleFileUnitChange = (
fileIndex: number, fileIndex: number,
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
setFileUnitSelections((prev) => { setFileUnitSelections((prev) => {
const newSelections = [...prev]; const newSelections = [...prev];
@ -229,7 +235,7 @@ export default function FormAudioDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[fileIndex] || new Set() newArray[fileIndex] || new Set(),
); );
if (value) { if (value) {
@ -260,12 +266,12 @@ export default function FormAudioDetail() {
(item: any) => (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( alert(
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES." "Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.",
); );
return prev; // Batalkan perubahan return prev; // Batalkan perubahan
} }
@ -302,7 +308,7 @@ export default function FormAudioDetail() {
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.assignedToTopLevel) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.assignedToTopLevel.split(",").map(Number),
); );
setUnitSelection({ setUnitSelection({
semua: outputSet.has(0), semua: outputSet.has(0),
@ -327,7 +333,7 @@ export default function FormAudioDetail() {
acc[polda.id] = false; acc[polda.id] = false;
return acc; return acc;
}, },
{} {},
); );
setExpandedPolda(initialExpandedState); setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState); console.log("polres", initialExpandedState);
@ -362,7 +368,7 @@ export default function FormAudioDetail() {
const handleUnitChange = ( const handleUnitChange = (
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
if (key === "semua") { if (key === "semua") {
const newState = { const newState = {
@ -472,7 +478,7 @@ export default function FormAudioDetail() {
const handleCheckboxChange = (id: number) => { const handleCheckboxChange = (id: number) => {
setSelectedPublishers((prev) => setSelectedPublishers((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
); );
}; };
@ -494,7 +500,7 @@ export default function FormAudioDetail() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -542,6 +548,9 @@ export default function FormAudioDetail() {
const details = response?.data?.data; const details = response?.data?.data;
setFiles(details?.files); setFiles(details?.files);
setDetail(details); setDetail(details);
if (details?.uploadedBy?.userLevel?.levelNumber) {
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
}
setMain({ setMain({
type: details?.fileType.name, type: details?.fileType.name,
url: details?.files[0]?.url, url: details?.files[0]?.url,
@ -552,14 +561,14 @@ export default function FormAudioDetail() {
if (details?.assignedToLevel) { if (details?.assignedToLevel) {
const levels = new Set( const levels = new Set(
details.assignedToLevel.split(",").map(Number) details.assignedToLevel.split(",").map(Number),
); );
setCheckedLevels(levels); setCheckedLevels(levels);
} }
if (details?.publishedForObject) { if (details?.publishedForObject) {
const publisherIds = details?.publishedForObject.map( const publisherIds = details?.publishedForObject.map(
(obj: any) => obj.id (obj: any) => obj.id,
); );
setSelectedPublishers(publisherIds); setSelectedPublishers(publisherIds);
} }
@ -709,7 +718,7 @@ export default function FormAudioDetail() {
const setupPlacement = ( const setupPlacement = (
index: number, index: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
let temp = [...filePlacements]; let temp = [...filePlacements];
if (checked) { if (checked) {
@ -720,7 +729,7 @@ export default function FormAudioDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Checklist semua item di modal // Checklist semua item di modal
@ -770,7 +779,7 @@ export default function FormAudioDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -785,7 +794,7 @@ export default function FormAudioDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Unchecklist semua item di modal // Unchecklist semua item di modal
@ -819,7 +828,7 @@ export default function FormAudioDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -838,7 +847,7 @@ export default function FormAudioDetail() {
type: string, type: string,
url: string, url: string,
names: string, names: string,
format: string format: string,
) => { ) => {
console.log("Test 3 :", type, url, names, format); console.log("Test 3 :", type, url, names, format);
setMain({ setMain({
@ -873,7 +882,7 @@ export default function FormAudioDetail() {
const updateModalChecklistLevels = ( const updateModalChecklistLevels = (
fileIndex: number, fileIndex: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
if (!listDest || listDest.length === 0) return; if (!listDest || listDest.length === 0) return;
@ -906,7 +915,7 @@ export default function FormAudioDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.add(Number(satkerItem.id)); currentFileLevels.add(Number(satkerItem.id));
@ -942,7 +951,7 @@ export default function FormAudioDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.delete(Number(satkerItem.id)); currentFileLevels.delete(Number(satkerItem.id));
@ -975,7 +984,7 @@ export default function FormAudioDetail() {
// Fungsi untuk mengupdate checklist levels untuk file tertentu // Fungsi untuk mengupdate checklist levels untuk file tertentu
const handleFileCheckboxChangePlacement = ( const handleFileCheckboxChangePlacement = (
fileIndex: number, fileIndex: number,
levelId: number levelId: number,
) => { ) => {
setFileCheckedLevels((prev) => { setFileCheckedLevels((prev) => {
const newArray = [...prev]; const newArray = [...prev];
@ -987,7 +996,7 @@ export default function FormAudioDetail() {
// 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( const poldaItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) as any;
if ( if (
poldaItem && poldaItem &&
@ -1010,7 +1019,7 @@ export default function FormAudioDetail() {
// 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( const satkerItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) 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)
@ -1041,7 +1050,7 @@ export default function FormAudioDetail() {
// Hitung total POLDA yang ada (bukan SATKER POLRI) // Hitung total POLDA yang ada (bukan SATKER POLRI)
const totalPoldaCount = listDest.filter( const totalPoldaCount = listDest.filter(
(item: any) => 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)
@ -1068,7 +1077,7 @@ export default function FormAudioDetail() {
} }
return total; return total;
}, },
0 0,
); );
// Hitung berapa banyak POLRES yang ter-checklist // Hitung berapa banyak POLRES yang ter-checklist
@ -1078,7 +1087,7 @@ export default function FormAudioDetail() {
return ( return (
total + total +
item.subDestination.filter((sub: any) => item.subDestination.filter((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
).length ).length
); );
} }
@ -1087,7 +1096,7 @@ export default function FormAudioDetail() {
// Cek apakah SATKER POLRI ter-checklist // Cek apakah SATKER POLRI ter-checklist
const satkerItem = listDest.find( const satkerItem = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
const isSatkerChecked = const isSatkerChecked =
satkerItem && currentFileLevels.has(Number(satkerItem.id)); satkerItem && currentFileLevels.has(Number(satkerItem.id));
@ -1121,7 +1130,7 @@ export default function FormAudioDetail() {
// Cek apakah semua sub-items sudah ter-checklist // Cek apakah semua sub-items sudah ter-checklist
const allSubItemsChecked = polda.subDestination?.every((sub: any) => const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
); );
if (allSubItemsChecked) { if (allSubItemsChecked) {
@ -1204,7 +1213,7 @@ export default function FormAudioDetail() {
{detail && {detail &&
!categories.find( !categories.find(
(cat) => (cat) =>
String(cat.id) === String(detail.category.id) String(cat.id) === String(detail.category.id),
) && ( ) && (
<SelectItem <SelectItem
key={String(detail.category.id)} key={String(detail.category.id)}
@ -1464,7 +1473,7 @@ export default function FormAudioDetail() {
Tingkat Distribusi: Tingkat Distribusi:
</p> </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" },
@ -1472,6 +1481,39 @@ export default function FormAudioDetail() {
key: "international", key: "international",
label: "Internasional", label: "Internasional",
}, },
] */}
{[
{ key: "semua", label: "Semua" },
...(isContentFromMabesOrPolda
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
{
key: "wilayah",
label: "Wilayah",
},
]
: []),
...(isContentFromSatker
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
]
: []),
].map((item, idx) => ( ].map((item, idx) => (
<div <div
key={item.key} key={item.key}
@ -1488,12 +1530,12 @@ export default function FormAudioDetail() {
handleFileUnitChange( handleFileUnitChange(
index, index,
item.key as keyof typeof unitSelection, item.key as keyof typeof unitSelection,
value as boolean value as boolean,
); );
setupPlacement( setupPlacement(
index, index,
item.key, item.key,
Boolean(value) Boolean(value),
); );
}} }}
/> />
@ -1509,251 +1551,262 @@ export default function FormAudioDetail() {
</div> </div>
{/* Detail Wilayah */} {/* Detail Wilayah */}
{fileUnitSelections[index]?.wilayah && ( {/* {fileUnitSelections[index]?.wilayah && ( */}
<div className="border-t border-gray-200 pt-2"> {!isContentFromSatker &&
<p className="text-sm font-medium text-gray-700 mb-2"> fileUnitSelections[index]?.wilayah && (
Detail Wilayah: <div className="border-t border-gray-200 pt-2">
</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">
{[ {[
{ key: "polda", label: "POLDA" }, { key: "polda", label: "POLDA" },
{ key: "polres", label: "POLRES" }, { key: "polres", label: "POLRES" },
{ key: "satker", label: "SATKER" }, { key: "satker", label: "SATKER" },
].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-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"
> >
{item.label} <Checkbox
</Label> id={`${item.key}-${index}`}
</div> checked={
))} fileUnitSelections[index]?.[
item.key as keyof typeof unitSelection
{/* Tombol Kustom sejajar dengan checkbox */} ] || false
<div className="flex items-center justify-center p-3"> }
<Dialog> onCheckedChange={(value) => {
<DialogTrigger asChild> handleFileUnitChange(
<Button index,
variant="outline" item.key as keyof typeof unitSelection,
size="sm" value as boolean,
className="gap-2" );
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",
) })}
); </Button>
return ( </DialogTrigger>
<Button <DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
size="sm" <DialogHeader className="border-b border-gray-200 pb-4">
variant="outline" <DialogTitle className="text-lg font-semibold">
className="text-xs h-6 px-2" Daftar Wilayah POLDA dan
onClick={() => POLRES
handleSelectAllSubItems( </DialogTitle>
index, </DialogHeader>
polda <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}
{allSubItemsChecked ? ( className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
<> >
<Icon {/* Header POLDA */}
icon="material-symbols:check-indeterminate-small" <div className="flex items-center justify-between">
width={12} <Label className="flex items-center gap-3 flex-1 cursor-pointer">
height={ <Checkbox
12 checked={
} fileCheckedLevels[
className="mr-1" index
/> ]?.has(
Batal Semua Number(polda.id),
</> ) || false
) : ( }
<> onCheckedChange={() =>
<Icon handleFileCheckboxChangePlacement(
icon="material-symbols:check-all" index,
width={12} Number(polda.id),
height={ )
12 }
} />
className="mr-1" <span className="font-semibold text-gray-900 text-sm">
/> {polda.name}
Pilih Semua </span>
</> </Label>
)} {polda.subDestination && (
</Button> <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",
})} */} })} */}
Simpan Simpan
</Button> </Button>
</DialogClose> </DialogClose>
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div>
</div> </div>
</div> </div>
</div> )}
)}
</div> </div>
</div> </div>
) : ( ) : (
@ -1832,7 +1885,7 @@ export default function FormAudioDetail() {
> >
{template} {template}
</Button> </Button>
) ),
)} )}
</div> </div>
</div> </div>

View File

@ -1806,7 +1806,7 @@ export default function FormAudio() {
</Card> </Card>
<div className="flex flex-row justify-end gap-3"> <div className="flex flex-row justify-end gap-3">
<div className="mt-4"> <div className="mt-4">
{levelNumber !== "2" && levelNumber !== "3" && ( {levelNumber !== "2" && (
<Button type="submit" color="primary"> <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> </Button>

View File

@ -115,7 +115,7 @@ const ViewEditor = dynamic(
() => { () => {
return import("@/components/editor/view-editor"); return import("@/components/editor/view-editor");
}, },
{ ssr: false } { ssr: false },
); );
interface Destination { interface Destination {
@ -172,6 +172,12 @@ export default function FormImageDetail() {
satker: boolean; satker: boolean;
}> }>
>([]); >([]);
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
null,
);
const isContentFromSatker = creatorLevelNumber === 3;
const isContentFromMabesOrPolda =
creatorLevelNumber === 1 || creatorLevelNumber === 2;
useEffect(() => { useEffect(() => {
if (Number(userLevelId) === 216 && Number(roleId) === 3) { if (Number(userLevelId) === 216 && Number(roleId) === 3) {
@ -200,7 +206,7 @@ export default function FormImageDetail() {
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
@ -231,7 +237,7 @@ export default function FormImageDetail() {
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.assignedToTopLevel) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.assignedToTopLevel.split(",").map(Number),
); );
setUnitSelection({ setUnitSelection({
semua: outputSet.has(0), semua: outputSet.has(0),
@ -260,7 +266,7 @@ export default function FormImageDetail() {
acc[polda.id] = false; acc[polda.id] = false;
return acc; return acc;
}, },
{} {},
); );
setExpandedPolda(initialExpandedState); setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState); console.log("polres", initialExpandedState);
@ -299,7 +305,7 @@ export default function FormImageDetail() {
(item: any) => (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)),
).length; ).length;
const checkedPolresCount = listDest.reduce((total: number, item: any) => { const checkedPolresCount = listDest.reduce((total: number, item: any) => {
@ -308,7 +314,7 @@ export default function FormImageDetail() {
return ( return (
total + total +
item.subDestination.filter((sub: any) => item.subDestination.filter((sub: any) =>
checkedLevels.has(Number(sub.id)) checkedLevels.has(Number(sub.id)),
).length ).length
); );
} }
@ -316,12 +322,12 @@ export default function FormImageDetail() {
}, 0); }, 0);
const satkerItem: any = listDest.find( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
const checkedSatkerCount = satkerItem const checkedSatkerCount = satkerItem
? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) + ? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) +
(satkerItem.subDestination?.filter((sub: any) => (satkerItem.subDestination?.filter((sub: any) =>
checkedLevels.has(Number(sub.id)) checkedLevels.has(Number(sub.id)),
).length || 0) ).length || 0)
: 0; : 0;
@ -391,7 +397,7 @@ export default function FormImageDetail() {
} else if (mainCheckboxChangeType === "satker_checked") { } else if (mainCheckboxChangeType === "satker_checked") {
// Checklist satker // Checklist satker
const satkerItem: any = listDest.find( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
newCheckedLevels.add(Number(satkerItem.id)); newCheckedLevels.add(Number(satkerItem.id));
@ -439,7 +445,7 @@ 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
newCheckedLevels.delete(Number(satkerItem.id)); newCheckedLevels.delete(Number(satkerItem.id));
@ -466,7 +472,7 @@ export default function FormImageDetail() {
const handleFileUnitChange = ( const handleFileUnitChange = (
fileIndex: number, fileIndex: number,
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
setFileUnitSelections((prev) => { setFileUnitSelections((prev) => {
const newSelections = [...prev]; const newSelections = [...prev];
@ -486,7 +492,7 @@ export default function FormImageDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[fileIndex] || new Set() newArray[fileIndex] || new Set(),
); );
if (value) { if (value) {
@ -517,12 +523,12 @@ export default function FormImageDetail() {
(item: any) => (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( alert(
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES." "Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.",
); );
return prev; // Batalkan perubahan return prev; // Batalkan perubahan
} }
@ -552,7 +558,7 @@ export default function FormImageDetail() {
// Fungsi lama untuk kompatibilitas (akan dihapus nanti) // Fungsi lama untuk kompatibilitas (akan dihapus nanti)
const handleUnitChange = ( const handleUnitChange = (
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
// Set flag bahwa perubahan berasal dari checkbox utama // Set flag bahwa perubahan berasal dari checkbox utama
setIsUpdatingFromMainCheckbox(true); setIsUpdatingFromMainCheckbox(true);
@ -578,13 +584,13 @@ export default function FormImageDetail() {
(item: any) => (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)),
); );
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( alert(
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES." "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);
@ -640,14 +646,14 @@ export default function FormImageDetail() {
const handleCheckboxChange = (id: number) => { const handleCheckboxChange = (id: number) => {
setSelectedPublishers((prev) => setSelectedPublishers((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
); );
}; };
// Fungsi untuk mengupdate checklist levels untuk file tertentu // Fungsi untuk mengupdate checklist levels untuk file tertentu
const handleFileCheckboxChangePlacement = ( const handleFileCheckboxChangePlacement = (
fileIndex: number, fileIndex: number,
levelId: number levelId: number,
) => { ) => {
setFileCheckedLevels((prev) => { setFileCheckedLevels((prev) => {
const newArray = [...prev]; const newArray = [...prev];
@ -659,7 +665,7 @@ export default function FormImageDetail() {
// 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( const poldaItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) as any;
if ( if (
poldaItem && poldaItem &&
@ -682,7 +688,7 @@ export default function FormImageDetail() {
// 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( const satkerItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) 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)
@ -710,7 +716,7 @@ export default function FormImageDetail() {
// Cek apakah semua sub-items sudah ter-checklist // Cek apakah semua sub-items sudah ter-checklist
const allSubItemsChecked = polda.subDestination?.every((sub: any) => const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
); );
if (allSubItemsChecked) { if (allSubItemsChecked) {
@ -750,7 +756,7 @@ export default function FormImageDetail() {
// Hitung total POLDA yang ada (bukan SATKER POLRI) // Hitung total POLDA yang ada (bukan SATKER POLRI)
const totalPoldaCount = listDest.filter( const totalPoldaCount = listDest.filter(
(item: any) => 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)
@ -777,7 +783,7 @@ export default function FormImageDetail() {
} }
return total; return total;
}, },
0 0,
); );
// Hitung berapa banyak POLRES yang ter-checklist // Hitung berapa banyak POLRES yang ter-checklist
@ -787,7 +793,7 @@ export default function FormImageDetail() {
return ( return (
total + total +
item.subDestination.filter((sub: any) => item.subDestination.filter((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
).length ).length
); );
} }
@ -796,7 +802,7 @@ export default function FormImageDetail() {
// Cek apakah SATKER POLRI ter-checklist // Cek apakah SATKER POLRI ter-checklist
const satkerItem = listDest.find( const satkerItem = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
const isSatkerChecked = const isSatkerChecked =
satkerItem && currentFileLevels.has(Number(satkerItem.id)); satkerItem && currentFileLevels.has(Number(satkerItem.id));
@ -833,7 +839,7 @@ export default function FormImageDetail() {
// 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( const poldaItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) as any;
if ( if (
poldaItem && poldaItem &&
@ -856,7 +862,7 @@ export default function FormImageDetail() {
// 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( const satkerItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) 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)
@ -887,7 +893,7 @@ export default function FormImageDetail() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -936,6 +942,11 @@ export default function FormImageDetail() {
console.log("detail", details); console.log("detail", details);
setFiles(details?.files); setFiles(details?.files);
setDetail(details); setDetail(details);
if (details?.uploadedBy?.userLevel?.levelNumber) {
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
}
setMain({ setMain({
type: details?.fileType.name, type: details?.fileType.name,
url: details?.files[0]?.url, url: details?.files[0]?.url,
@ -946,14 +957,14 @@ export default function FormImageDetail() {
if (details?.assignedToLevel) { if (details?.assignedToLevel) {
const levels = new Set<number>( const levels = new Set<number>(
details.assignedToLevel.split(",").map(Number) details.assignedToLevel.split(",").map(Number),
); );
setCheckedLevels(levels); setCheckedLevels(levels);
} }
if (details?.publishedForObject) { if (details?.publishedForObject) {
const publisherIds = details?.publishedForObject?.map( const publisherIds = details?.publishedForObject?.map(
(obj: any) => obj.id (obj: any) => obj.id,
); );
setSelectedPublishers(publisherIds); setSelectedPublishers(publisherIds);
} }
@ -963,7 +974,7 @@ export default function FormImageDetail() {
const filesData = details.files || []; const filesData = details.files || [];
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) => const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) =>
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg" file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg",
); );
setDetailThumb(fileUrls); setDetailThumb(fileUrls);
@ -1083,7 +1094,7 @@ export default function FormImageDetail() {
const setupPlacement = ( const setupPlacement = (
index: number, index: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
let temp = [...filePlacements]; let temp = [...filePlacements];
if (checked) { if (checked) {
@ -1094,7 +1105,7 @@ export default function FormImageDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Checklist semua item di modal // Checklist semua item di modal
@ -1144,7 +1155,7 @@ 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -1159,7 +1170,7 @@ export default function FormImageDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Unchecklist semua item di modal // Unchecklist semua item di modal
@ -1193,7 +1204,7 @@ export default function FormImageDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -1212,7 +1223,7 @@ export default function FormImageDetail() {
const updateModalChecklistLevels = ( const updateModalChecklistLevels = (
fileIndex: number, fileIndex: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
if (!listDest || listDest.length === 0) return; if (!listDest || listDest.length === 0) return;
@ -1245,7 +1256,7 @@ 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.add(Number(satkerItem.id)); currentFileLevels.add(Number(satkerItem.id));
@ -1281,7 +1292,7 @@ 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.delete(Number(satkerItem.id)); currentFileLevels.delete(Number(satkerItem.id));
@ -1311,7 +1322,7 @@ export default function FormImageDetail() {
type: string, type: string,
url: string, url: string,
names: string, names: string,
format: string format: string,
) => { ) => {
console.log("Test 3 :", type, url, names, format); console.log("Test 3 :", type, url, names, format);
setMain({ setMain({
@ -1411,7 +1422,7 @@ export default function FormImageDetail() {
{detail && {detail &&
!categories.find( !categories.find(
(cat) => (cat) =>
String(cat.id) === String(detail.category.id) String(cat.id) === String(detail.category.id),
) && ( ) && (
<SelectItem <SelectItem
key={String(detail.category.id)} key={String(detail.category.id)}
@ -1732,7 +1743,7 @@ export default function FormImageDetail() {
Tingkat Distribusi: Tingkat Distribusi:
</p> </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" },
@ -1740,6 +1751,39 @@ export default function FormImageDetail() {
key: "international", key: "international",
label: "Internasional", label: "Internasional",
}, },
] */}
{[
{ key: "semua", label: "Semua" },
...(isContentFromMabesOrPolda
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
{
key: "wilayah",
label: "Wilayah",
},
]
: []),
...(isContentFromSatker
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
]
: []),
].map((item, idx) => ( ].map((item, idx) => (
<div <div
key={item.key} key={item.key}
@ -1756,12 +1800,12 @@ export default function FormImageDetail() {
handleFileUnitChange( handleFileUnitChange(
index, index,
item.key as keyof typeof unitSelection, item.key as keyof typeof unitSelection,
value as boolean value as boolean,
); );
setupPlacement( setupPlacement(
index, index,
item.key, item.key,
Boolean(value) Boolean(value),
); );
}} }}
/> />
@ -1777,246 +1821,257 @@ export default function FormImageDetail() {
</div> </div>
{/* Detail Wilayah */} {/* Detail Wilayah */}
{fileUnitSelections[index]?.wilayah && ( {/* {fileUnitSelections[index]?.wilayah && ( */}
<div className="border-t border-gray-200 pt-2"> {!isContentFromSatker &&
<p className="text-sm font-medium text-gray-700 mb-2"> fileUnitSelections[index]?.wilayah && (
Detail Wilayah: <div className="border-t border-gray-200 pt-2">
</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">
{[ {[
{ key: "polda", label: "POLDA" }, { key: "polda", label: "POLDA" },
{ key: "polres", label: "POLRES" }, { key: "polres", label: "POLRES" },
{ key: "satker", label: "SATKER" }, { key: "satker", label: "SATKER" },
].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-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"
> >
{item.label} <Checkbox
</Label> id={`${item.key}-${index}`}
</div> checked={
))} fileUnitSelections[index]?.[
item.key as keyof typeof unitSelection
{/* Tombol Kustom sejajar dengan checkbox */} ] || false
<div className="flex items-center justify-center p-3"> }
<Dialog> onCheckedChange={(value) => {
<DialogTrigger asChild> handleFileUnitChange(
<Button index,
variant="outline" item.key as keyof typeof unitSelection,
size="sm" value as boolean,
className="gap-2" );
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",
) })}
); </Button>
return ( </DialogTrigger>
<Button <DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
size="sm" <DialogHeader className="border-b border-gray-200 pb-4">
variant="outline" <DialogTitle className="text-lg font-semibold">
className="text-xs h-6 px-2" Daftar Wilayah POLDA dan
onClick={() => POLRES
handleSelectAllSubItems( </DialogTitle>
index, </DialogHeader>
polda <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}
{allSubItemsChecked ? ( className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
<> >
<Icon {/* Header POLDA */}
icon="material-symbols:check-indeterminate-small" <div className="flex items-center justify-between">
width={12} <Label className="flex items-center gap-3 flex-1 cursor-pointer">
height={ <Checkbox
12 checked={
} fileCheckedLevels[
className="mr-1" index
/> ]?.has(
Batal Semua Number(polda.id),
</> ) || false
) : ( }
<> onCheckedChange={() =>
<Icon handleFileCheckboxChangePlacement(
icon="material-symbols:check-all" index,
width={12} Number(polda.id),
height={ )
12 }
} />
className="mr-1" <span className="font-semibold text-gray-900 text-sm">
/> {polda.name}
Pilih Semua </span>
</> </Label>
)} {polda.subDestination && (
</Button> <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>Simpan</Button>
<Button>Simpan</Button> </DialogClose>
</DialogClose> </div>
</div> </DialogContent>
</DialogContent> </Dialog>
</Dialog> </div>
</div> </div>
</div> </div>
</div> )}
)}
</div> </div>
</div> </div>
) : ( ) : (
@ -2095,7 +2150,7 @@ export default function FormImageDetail() {
> >
{template} {template}
</Button> </Button>
) ),
)} )}
</div> </div>
</div> </div>

View File

@ -82,7 +82,7 @@ const CustomEditor = dynamic(
() => { () => {
return import("@/components/editor/custom-editor"); return import("@/components/editor/custom-editor");
}, },
{ ssr: false } { ssr: false },
); );
export default function FormImage() { export default function FormImage() {
@ -117,7 +117,7 @@ export default function FormImage() {
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false); const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
const [articleBody, setArticleBody] = useState<string>(""); const [articleBody, setArticleBody] = useState<string>("");
const [selectedArticleId, setSelectedArticleId] = useState<string | null>( const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
null null,
); );
const [selectedMainKeyword, setSelectedMainKeyword] = useState(""); const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
const [selectedWritingStyle, setSelectedWritingStyle] = const [selectedWritingStyle, setSelectedWritingStyle] =
@ -183,17 +183,17 @@ export default function FormImage() {
.filter( .filter(
(file) => (file) =>
["image/jpeg", "image/png", "image/jpg"].includes(file.type) && ["image/jpeg", "image/png", "image/jpg"].includes(file.type) &&
file.size <= MAX_FILE_SIZE file.size <= MAX_FILE_SIZE,
) )
.map((file) => .map((file) =>
Object.assign(file, { Object.assign(file, {
preview: URL.createObjectURL(file), preview: URL.createObjectURL(file),
}) }),
); );
if (validFiles.length === 0) { if (validFiles.length === 0) {
toast.error( toast.error(
"File tidak valid. Hanya .jpg, .jpeg, .png maksimal 100MB yang diperbolehkan." "File tidak valid. Hanya .jpg, .jpeg, .png maksimal 100MB yang diperbolehkan.",
); );
return; return;
} }
@ -227,12 +227,12 @@ export default function FormImage() {
files.every( files.every(
(file: File) => (file: File) =>
["image/jpeg", "image/png", "image/jpg"].includes(file.type) && ["image/jpeg", "image/png", "image/jpg"].includes(file.type) &&
file.size <= 100 * 1024 * 1024 file.size <= 100 * 1024 * 1024,
), ),
{ {
message: message:
"Hanya file .jpg, .jpeg, .png, maksimal 100MB yang diperbolehkan.", "Hanya file .jpg, .jpeg, .png, maksimal 100MB yang diperbolehkan.",
} },
), ),
categoryId: z.string().min(1, { message: "Kategori wajib dipilih." }), categoryId: z.string().min(1, { message: "Kategori wajib dipilih." }),
tags: z tags: z
@ -454,7 +454,7 @@ export default function FormImage() {
const articleData = await waitForStatusUpdate(); const articleData = await waitForStatusUpdate();
const cleanArticleBody = articleData?.articleBody?.replace( const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g, /<img[^>]*>/g,
"" "",
); );
const articleImagesData = articleData?.imagesUrl?.split(","); const articleImagesData = articleData?.imagesUrl?.split(",");
setArticleBody(cleanArticleBody || ""); setArticleBody(cleanArticleBody || "");
@ -507,7 +507,7 @@ export default function FormImage() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -530,7 +530,7 @@ export default function FormImage() {
setPublishedFor( setPublishedFor(
options options
.filter((opt: any) => opt.id !== "all") .filter((opt: any) => opt.id !== "all")
.map((opt: any) => opt.id) .map((opt: any) => opt.id),
); );
} }
} else { } else {
@ -594,11 +594,16 @@ export default function FormImage() {
} else if (data.rewriteDescription && selectedFileType === "rewrite") { } else if (data.rewriteDescription && selectedFileType === "rewrite") {
finalDescription = data.rewriteDescription; finalDescription = data.rewriteDescription;
console.log("📤 Upload versi rewrite"); console.log("📤 Upload versi rewrite");
} else { } else if (data.description?.trim()) {
// fallback: gunakan versi Indonesia original finalDescription = data.description;
finalDescription = data.descriptionOri ?? ""; } else if (data.descriptionOri?.trim()) {
console.log("📤 Upload versi Indonesia (original)"); finalDescription = data.descriptionOri;
} }
// else {
// // fallback: gunakan versi Indonesia original
// finalDescription = data.descriptionOri ?? "";
// console.log("📤 Upload versi Indonesia (original)");
// }
if (!finalDescription?.trim()) { if (!finalDescription?.trim()) {
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error"); MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
@ -690,7 +695,7 @@ export default function FormImage() {
index, index,
String(id), String(id),
item, item,
fileTypeId == "2" || fileTypeId == "4" ? item.duration : "0" fileTypeId == "2" || fileTypeId == "4" ? item.duration : "0",
); );
}); });
@ -717,7 +722,7 @@ export default function FormImage() {
idx: number, idx: number,
id: string, id: string,
file: any, file: any,
duration: string duration: string,
) { ) {
console.log(idx, id, file, duration); console.log(idx, id, file, duration);
@ -753,7 +758,7 @@ export default function FormImage() {
onChunkComplete: ( onChunkComplete: (
chunkSize: any, chunkSize: any,
bytesAccepted: any, bytesAccepted: any,
bytesTotal: any bytesTotal: any,
) => { ) => {
const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100); const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100);
progressInfo[idx].percentage = uploadPersen; progressInfo[idx].percentage = uploadPersen;

View File

@ -114,7 +114,7 @@ const ViewEditor = dynamic(
() => { () => {
return import("@/components/editor/view-editor"); return import("@/components/editor/view-editor");
}, },
{ ssr: false } { ssr: false },
); );
interface Destination { interface Destination {
@ -191,6 +191,12 @@ export default function FormTeksDetail() {
satker: boolean; satker: boolean;
}> }>
>([]); >([]);
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
null,
);
const isContentFromSatker = creatorLevelNumber === 3;
const isContentFromMabesOrPolda =
creatorLevelNumber === 1 || creatorLevelNumber === 2;
useEffect(() => { useEffect(() => {
if (Number(userLevelId) === 216 && Number(roleId) === 3) { if (Number(userLevelId) === 216 && Number(roleId) === 3) {
@ -202,7 +208,7 @@ export default function FormTeksDetail() {
const handleFileUnitChange = ( const handleFileUnitChange = (
fileIndex: number, fileIndex: number,
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
setFileUnitSelections((prev) => { setFileUnitSelections((prev) => {
const newSelections = [...prev]; const newSelections = [...prev];
@ -222,7 +228,7 @@ export default function FormTeksDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[fileIndex] || new Set() newArray[fileIndex] || new Set(),
); );
if (value) { if (value) {
@ -253,12 +259,12 @@ export default function FormTeksDetail() {
(item: any) => (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( alert(
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES." "Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.",
); );
return prev; // Batalkan perubahan return prev; // Batalkan perubahan
} }
@ -297,7 +303,7 @@ export default function FormTeksDetail() {
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.assignedToTopLevel) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.assignedToTopLevel.split(",").map(Number),
); );
setUnitSelection({ setUnitSelection({
semua: outputSet.has(0), semua: outputSet.has(0),
@ -322,7 +328,7 @@ export default function FormTeksDetail() {
acc[polda.id] = false; acc[polda.id] = false;
return acc; return acc;
}, },
{} {},
); );
setExpandedPolda(initialExpandedState); setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState); console.log("polres", initialExpandedState);
@ -357,7 +363,7 @@ export default function FormTeksDetail() {
const handleUnitChange = ( const handleUnitChange = (
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
if (key === "semua") { if (key === "semua") {
const newState = { const newState = {
@ -436,7 +442,7 @@ export default function FormTeksDetail() {
const handleCheckboxChange = (id: number) => { const handleCheckboxChange = (id: number) => {
setSelectedPublishers((prev) => setSelectedPublishers((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
); );
}; };
@ -458,7 +464,7 @@ export default function FormTeksDetail() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -507,6 +513,9 @@ export default function FormTeksDetail() {
console.log("detail", details); console.log("detail", details);
setFiles(details?.files); setFiles(details?.files);
setDetail(details); setDetail(details);
if (details?.uploadedBy?.userLevel?.levelNumber) {
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
}
setMain({ setMain({
type: details?.fileType.name, type: details?.fileType.name,
url: details?.files[0]?.url, url: details?.files[0]?.url,
@ -517,14 +526,14 @@ export default function FormTeksDetail() {
if (details?.assignedToLevel) { if (details?.assignedToLevel) {
const levels = new Set( const levels = new Set(
details.assignedToLevel.split(",").map(Number) details.assignedToLevel.split(",").map(Number),
); );
setCheckedLevels(levels); setCheckedLevels(levels);
} }
if (details?.publishedForObject) { if (details?.publishedForObject) {
const publisherIds = details?.publishedForObject?.map( const publisherIds = details?.publishedForObject?.map(
(obj: any) => obj.id (obj: any) => obj.id,
); );
setSelectedPublishers(publisherIds); setSelectedPublishers(publisherIds);
} }
@ -696,7 +705,7 @@ export default function FormTeksDetail() {
type: string, type: string,
url: string, url: string,
names: string, names: string,
format: string format: string,
) => { ) => {
console.log("Test 3 :", type, url, names, format); console.log("Test 3 :", type, url, names, format);
setMain({ setMain({
@ -723,7 +732,7 @@ export default function FormTeksDetail() {
const setupPlacement = ( const setupPlacement = (
index: number, index: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
let temp = [...filePlacements]; let temp = [...filePlacements];
if (checked) { if (checked) {
@ -734,7 +743,7 @@ export default function FormTeksDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Checklist semua item di modal // Checklist semua item di modal
@ -784,7 +793,7 @@ export default function FormTeksDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -799,7 +808,7 @@ export default function FormTeksDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Unchecklist semua item di modal // Unchecklist semua item di modal
@ -833,7 +842,7 @@ export default function FormTeksDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -851,7 +860,7 @@ export default function FormTeksDetail() {
const updateModalChecklistLevels = ( const updateModalChecklistLevels = (
fileIndex: number, fileIndex: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
if (!listDest || listDest.length === 0) return; if (!listDest || listDest.length === 0) return;
@ -884,7 +893,7 @@ export default function FormTeksDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.add(Number(satkerItem.id)); currentFileLevels.add(Number(satkerItem.id));
@ -920,7 +929,7 @@ export default function FormTeksDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.delete(Number(satkerItem.id)); currentFileLevels.delete(Number(satkerItem.id));
@ -953,7 +962,7 @@ export default function FormTeksDetail() {
// Fungsi untuk mengupdate checklist levels untuk file tertentu // Fungsi untuk mengupdate checklist levels untuk file tertentu
const handleFileCheckboxChangePlacement = ( const handleFileCheckboxChangePlacement = (
fileIndex: number, fileIndex: number,
levelId: number levelId: number,
) => { ) => {
setFileCheckedLevels((prev) => { setFileCheckedLevels((prev) => {
const newArray = [...prev]; const newArray = [...prev];
@ -965,7 +974,7 @@ export default function FormTeksDetail() {
// 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( const poldaItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) as any;
if ( if (
poldaItem && poldaItem &&
@ -988,7 +997,7 @@ export default function FormTeksDetail() {
// 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( const satkerItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) 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)
@ -1019,7 +1028,7 @@ export default function FormTeksDetail() {
// Hitung total POLDA yang ada (bukan SATKER POLRI) // Hitung total POLDA yang ada (bukan SATKER POLRI)
const totalPoldaCount = listDest.filter( const totalPoldaCount = listDest.filter(
(item: any) => 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)
@ -1046,7 +1055,7 @@ export default function FormTeksDetail() {
} }
return total; return total;
}, },
0 0,
); );
// Hitung berapa banyak POLRES yang ter-checklist // Hitung berapa banyak POLRES yang ter-checklist
@ -1056,7 +1065,7 @@ export default function FormTeksDetail() {
return ( return (
total + total +
item.subDestination.filter((sub: any) => item.subDestination.filter((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
).length ).length
); );
} }
@ -1065,7 +1074,7 @@ export default function FormTeksDetail() {
// Cek apakah SATKER POLRI ter-checklist // Cek apakah SATKER POLRI ter-checklist
const satkerItem = listDest.find( const satkerItem = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
const isSatkerChecked = const isSatkerChecked =
satkerItem && currentFileLevels.has(Number(satkerItem.id)); satkerItem && currentFileLevels.has(Number(satkerItem.id));
@ -1099,7 +1108,7 @@ export default function FormTeksDetail() {
// Cek apakah semua sub-items sudah ter-checklist // Cek apakah semua sub-items sudah ter-checklist
const allSubItemsChecked = polda.subDestination?.every((sub: any) => const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
); );
if (allSubItemsChecked) { if (allSubItemsChecked) {
@ -1182,7 +1191,7 @@ export default function FormTeksDetail() {
{detail && {detail &&
!categories.find( !categories.find(
(cat) => (cat) =>
String(cat.id) === String(detail.category.id) String(cat.id) === String(detail.category.id),
) && ( ) && (
<SelectItem <SelectItem
key={String(detail.category.id)} key={String(detail.category.id)}
@ -1465,7 +1474,7 @@ export default function FormTeksDetail() {
Tingkat Distribusi: Tingkat Distribusi:
</p> </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" },
@ -1473,6 +1482,39 @@ export default function FormTeksDetail() {
key: "international", key: "international",
label: "Internasional", label: "Internasional",
}, },
] */}
{[
{ key: "semua", label: "Semua" },
...(isContentFromMabesOrPolda
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
{
key: "wilayah",
label: "Wilayah",
},
]
: []),
...(isContentFromSatker
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
]
: []),
].map((item, idx) => ( ].map((item, idx) => (
<div <div
key={item.key} key={item.key}
@ -1489,12 +1531,12 @@ export default function FormTeksDetail() {
handleFileUnitChange( handleFileUnitChange(
index, index,
item.key as keyof typeof unitSelection, item.key as keyof typeof unitSelection,
value as boolean value as boolean,
); );
setupPlacement( setupPlacement(
index, index,
item.key, item.key,
Boolean(value) Boolean(value),
); );
}} }}
/> />
@ -1510,251 +1552,262 @@ export default function FormTeksDetail() {
</div> </div>
{/* Detail Wilayah */} {/* Detail Wilayah */}
{fileUnitSelections[index]?.wilayah && ( {/* {fileUnitSelections[index]?.wilayah && ( */}
<div className="border-t border-gray-200 pt-2"> {!isContentFromSatker &&
<p className="text-sm font-medium text-gray-700 mb-2"> fileUnitSelections[index]?.wilayah && (
Detail Wilayah: <div className="border-t border-gray-200 pt-2">
</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">
{[ {[
{ key: "polda", label: "POLDA" }, { key: "polda", label: "POLDA" },
{ key: "polres", label: "POLRES" }, { key: "polres", label: "POLRES" },
{ key: "satker", label: "SATKER" }, { key: "satker", label: "SATKER" },
].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-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"
> >
{item.label} <Checkbox
</Label> id={`${item.key}-${index}`}
</div> checked={
))} fileUnitSelections[index]?.[
item.key as keyof typeof unitSelection
{/* Tombol Kustom sejajar dengan checkbox */} ] || false
<div className="flex items-center justify-center p-3"> }
<Dialog> onCheckedChange={(value) => {
<DialogTrigger asChild> handleFileUnitChange(
<Button index,
variant="outline" item.key as keyof typeof unitSelection,
size="sm" value as boolean,
className="gap-2" );
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",
) })}
); </Button>
return ( </DialogTrigger>
<Button <DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
size="sm" <DialogHeader className="border-b border-gray-200 pb-4">
variant="outline" <DialogTitle className="text-lg font-semibold">
className="text-xs h-6 px-2" Daftar Wilayah POLDA dan
onClick={() => POLRES
handleSelectAllSubItems( </DialogTitle>
index, </DialogHeader>
polda <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}
{allSubItemsChecked ? ( className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
<> >
<Icon {/* Header POLDA */}
icon="material-symbols:check-indeterminate-small" <div className="flex items-center justify-between">
width={12} <Label className="flex items-center gap-3 flex-1 cursor-pointer">
height={ <Checkbox
12 checked={
} fileCheckedLevels[
className="mr-1" index
/> ]?.has(
Batal Semua Number(polda.id),
</> ) || false
) : ( }
<> onCheckedChange={() =>
<Icon handleFileCheckboxChangePlacement(
icon="material-symbols:check-all" index,
width={12} Number(polda.id),
height={ )
12 }
} />
className="mr-1" <span className="font-semibold text-gray-900 text-sm">
/> {polda.name}
Pilih Semua </span>
</> </Label>
)} {polda.subDestination && (
</Button> <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",
})} */} })} */}
Simpan Simpan
</Button> </Button>
</DialogClose> </DialogClose>
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div>
</div> </div>
</div> </div>
</div> )}
)}
</div> </div>
</div> </div>
) : ( ) : (
@ -1833,7 +1886,7 @@ export default function FormTeksDetail() {
> >
{template} {template}
</Button> </Button>
) ),
)} )}
</div> </div>
</div> </div>

View File

@ -1776,7 +1776,7 @@ export default function FormTeks() {
{/* <Button type="submit" color="primary"> {/* <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> */} </Button> */}
{levelNumber !== "2" && levelNumber !== "3" && ( {levelNumber !== "2" && (
<Button type="submit" color="primary"> <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> </Button>

View File

@ -115,7 +115,7 @@ const ViewEditor = dynamic(
() => { () => {
return import("@/components/editor/view-editor"); return import("@/components/editor/view-editor");
}, },
{ ssr: false } { ssr: false },
); );
interface Destination { interface Destination {
@ -190,6 +190,12 @@ export default function FormVideoDetail() {
satker: boolean; satker: boolean;
}> }>
>([]); >([]);
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
null,
);
const isContentFromSatker = creatorLevelNumber === 3;
const isContentFromMabesOrPolda =
creatorLevelNumber === 1 || creatorLevelNumber === 2;
useEffect(() => { useEffect(() => {
if (Number(userLevelId) === 216 && Number(roleId) === 3) { if (Number(userLevelId) === 216 && Number(roleId) === 3) {
@ -201,7 +207,7 @@ export default function FormVideoDetail() {
const handleFileUnitChange = ( const handleFileUnitChange = (
fileIndex: number, fileIndex: number,
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
setFileUnitSelections((prev) => { setFileUnitSelections((prev) => {
const newSelections = [...prev]; const newSelections = [...prev];
@ -221,7 +227,7 @@ export default function FormVideoDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[fileIndex] || new Set() newArray[fileIndex] || new Set(),
); );
if (value) { if (value) {
@ -252,12 +258,12 @@ export default function FormVideoDetail() {
(item: any) => (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( alert(
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES." "Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.",
); );
return prev; // Batalkan perubahan return prev; // Batalkan perubahan
} }
@ -296,7 +302,7 @@ export default function FormVideoDetail() {
useEffect(() => { useEffect(() => {
if (detail?.assignedToTopLevel) { if (detail?.assignedToTopLevel) {
const outputSet = new Set( const outputSet = new Set(
detail.assignedToTopLevel.split(",").map(Number) detail.assignedToTopLevel.split(",").map(Number),
); );
setUnitSelection({ setUnitSelection({
semua: outputSet.has(0), semua: outputSet.has(0),
@ -321,7 +327,7 @@ export default function FormVideoDetail() {
acc[polda.id] = false; acc[polda.id] = false;
return acc; return acc;
}, },
{} {},
); );
setExpandedPolda(initialExpandedState); setExpandedPolda(initialExpandedState);
console.log("polres", initialExpandedState); console.log("polres", initialExpandedState);
@ -356,7 +362,7 @@ export default function FormVideoDetail() {
const handleUnitChange = ( const handleUnitChange = (
key: keyof typeof unitSelection, key: keyof typeof unitSelection,
value: boolean value: boolean,
) => { ) => {
if (key === "semua") { if (key === "semua") {
const newState = { const newState = {
@ -435,7 +441,7 @@ export default function FormVideoDetail() {
const handleCheckboxChange = (id: number) => { const handleCheckboxChange = (id: number) => {
setSelectedPublishers((prev) => setSelectedPublishers((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
); );
}; };
@ -457,7 +463,7 @@ export default function FormVideoDetail() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -480,6 +486,10 @@ export default function FormVideoDetail() {
console.log("detail", details); console.log("detail", details);
setFiles(details?.files); setFiles(details?.files);
setDetail(details); setDetail(details);
if (details?.uploadedBy?.userLevel?.levelNumber) {
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
}
setMain({ setMain({
type: details?.fileType.name, type: details?.fileType.name,
url: details?.files[0]?.url, url: details?.files[0]?.url,
@ -489,14 +499,14 @@ export default function FormVideoDetail() {
if (details?.assignedToLevel) { if (details?.assignedToLevel) {
const levels = new Set( const levels = new Set(
details.assignedToLevel.split(",").map(Number) details.assignedToLevel.split(",").map(Number),
); );
setCheckedLevels(levels); setCheckedLevels(levels);
} }
if (details?.publishedForObject) { if (details?.publishedForObject) {
const publisherIds = details?.publishedForObject?.map( const publisherIds = details?.publishedForObject?.map(
(obj: any) => obj.id (obj: any) => obj.id,
); );
setSelectedPublishers(publisherIds); setSelectedPublishers(publisherIds);
} }
@ -506,7 +516,7 @@ export default function FormVideoDetail() {
const filesData = details?.files || []; const filesData = details?.files || [];
const fileUrls = filesData.map((files: { url: string }) => const fileUrls = filesData.map((files: { url: string }) =>
files.url ? files.url : "default-image.jpg" files.url ? files.url : "default-image.jpg",
); );
setDetailVideo(fileUrls); setDetailVideo(fileUrls);
@ -684,7 +694,7 @@ export default function FormVideoDetail() {
const setupPlacement = ( const setupPlacement = (
index: number, index: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
let temp = [...filePlacements]; let temp = [...filePlacements];
if (checked) { if (checked) {
@ -695,7 +705,7 @@ export default function FormVideoDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Checklist semua item di modal // Checklist semua item di modal
@ -745,7 +755,7 @@ export default function FormVideoDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -760,7 +770,7 @@ export default function FormVideoDetail() {
setFileCheckedLevels((prevLevels) => { setFileCheckedLevels((prevLevels) => {
const newArray = [...prevLevels]; const newArray = [...prevLevels];
const currentFileLevels = new Set<number>( const currentFileLevels = new Set<number>(
newArray[index] || new Set() newArray[index] || new Set(),
); );
// Unchecklist semua item di modal // Unchecklist semua item di modal
@ -794,7 +804,7 @@ export default function FormVideoDetail() {
// 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( const nonSatkerItems = now.filter(
(item) => item !== "satker" && item !== "all" (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");
@ -812,7 +822,7 @@ export default function FormVideoDetail() {
const updateModalChecklistLevels = ( const updateModalChecklistLevels = (
fileIndex: number, fileIndex: number,
placement: string, placement: string,
checked: boolean checked: boolean,
) => { ) => {
if (!listDest || listDest.length === 0) return; if (!listDest || listDest.length === 0) return;
@ -845,7 +855,7 @@ export default function FormVideoDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.add(Number(satkerItem.id)); currentFileLevels.add(Number(satkerItem.id));
@ -881,7 +891,7 @@ export default function FormVideoDetail() {
} 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( const satkerItem: any = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
if (satkerItem) { if (satkerItem) {
currentFileLevels.delete(Number(satkerItem.id)); currentFileLevels.delete(Number(satkerItem.id));
@ -910,7 +920,7 @@ export default function FormVideoDetail() {
type: string, type: string,
url: string, url: string,
names: string, names: string,
format: string format: string,
) => { ) => {
console.log("Test 3 :", type, url, names, format); console.log("Test 3 :", type, url, names, format);
setMain({ setMain({
@ -951,7 +961,7 @@ export default function FormVideoDetail() {
// Fungsi untuk mengupdate checklist levels untuk file tertentu // Fungsi untuk mengupdate checklist levels untuk file tertentu
const handleFileCheckboxChangePlacement = ( const handleFileCheckboxChangePlacement = (
fileIndex: number, fileIndex: number,
levelId: number levelId: number,
) => { ) => {
setFileCheckedLevels((prev) => { setFileCheckedLevels((prev) => {
const newArray = [...prev]; const newArray = [...prev];
@ -963,7 +973,7 @@ export default function FormVideoDetail() {
// 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( const poldaItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) as any;
if ( if (
poldaItem && poldaItem &&
@ -986,7 +996,7 @@ export default function FormVideoDetail() {
// 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( const satkerItem = listDest.find(
(item: any) => Number(item.id) === levelId (item: any) => Number(item.id) === levelId,
) as any; ) 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)
@ -1017,7 +1027,7 @@ export default function FormVideoDetail() {
// Hitung total POLDA yang ada (bukan SATKER POLRI) // Hitung total POLDA yang ada (bukan SATKER POLRI)
const totalPoldaCount = listDest.filter( const totalPoldaCount = listDest.filter(
(item: any) => 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)
@ -1044,7 +1054,7 @@ export default function FormVideoDetail() {
} }
return total; return total;
}, },
0 0,
); );
// Hitung berapa banyak POLRES yang ter-checklist // Hitung berapa banyak POLRES yang ter-checklist
@ -1054,7 +1064,7 @@ export default function FormVideoDetail() {
return ( return (
total + total +
item.subDestination.filter((sub: any) => item.subDestination.filter((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
).length ).length
); );
} }
@ -1063,7 +1073,7 @@ export default function FormVideoDetail() {
// Cek apakah SATKER POLRI ter-checklist // Cek apakah SATKER POLRI ter-checklist
const satkerItem = listDest.find( const satkerItem = listDest.find(
(item: any) => item.name === "SATKER POLRI" (item: any) => item.name === "SATKER POLRI",
); );
const isSatkerChecked = const isSatkerChecked =
satkerItem && currentFileLevels.has(Number(satkerItem.id)); satkerItem && currentFileLevels.has(Number(satkerItem.id));
@ -1097,7 +1107,7 @@ export default function FormVideoDetail() {
// Cek apakah semua sub-items sudah ter-checklist // Cek apakah semua sub-items sudah ter-checklist
const allSubItemsChecked = polda.subDestination?.every((sub: any) => const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
currentFileLevels.has(Number(sub.id)) currentFileLevels.has(Number(sub.id)),
); );
if (allSubItemsChecked) { if (allSubItemsChecked) {
@ -1180,7 +1190,7 @@ export default function FormVideoDetail() {
{detail && {detail &&
!categories.find( !categories.find(
(cat) => (cat) =>
String(cat.id) === String(detail.category.id) String(cat.id) === String(detail.category.id),
) && ( ) && (
<SelectItem <SelectItem
key={String(detail.category.id)} key={String(detail.category.id)}
@ -1465,7 +1475,7 @@ export default function FormVideoDetail() {
Tingkat Distribusi: Tingkat Distribusi:
</p> </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" },
@ -1473,6 +1483,39 @@ export default function FormVideoDetail() {
key: "international", key: "international",
label: "Internasional", label: "Internasional",
}, },
] */}
{[
{ key: "semua", label: "Semua" },
...(isContentFromMabesOrPolda
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
{
key: "wilayah",
label: "Wilayah",
},
]
: []),
...(isContentFromSatker
? [
{
key: "nasional",
label: "Nasional",
},
{
key: "international",
label: "Internasional",
},
]
: []),
].map((item, idx) => ( ].map((item, idx) => (
<div <div
key={item.key} key={item.key}
@ -1489,12 +1532,12 @@ export default function FormVideoDetail() {
handleFileUnitChange( handleFileUnitChange(
index, index,
item.key as keyof typeof unitSelection, item.key as keyof typeof unitSelection,
value as boolean value as boolean,
); );
setupPlacement( setupPlacement(
index, index,
item.key, item.key,
Boolean(value) Boolean(value),
); );
}} }}
/> />
@ -1510,251 +1553,262 @@ export default function FormVideoDetail() {
</div> </div>
{/* Detail Wilayah */} {/* Detail Wilayah */}
{fileUnitSelections[index]?.wilayah && ( {/* {fileUnitSelections[index]?.wilayah && ( */}
<div className="border-t border-gray-200 pt-2"> {!isContentFromSatker &&
<p className="text-sm font-medium text-gray-700 mb-2"> fileUnitSelections[index]?.wilayah && (
Detail Wilayah: <div className="border-t border-gray-200 pt-2">
</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">
{[ {[
{ key: "polda", label: "POLDA" }, { key: "polda", label: "POLDA" },
{ key: "polres", label: "POLRES" }, { key: "polres", label: "POLRES" },
{ key: "satker", label: "SATKER" }, { key: "satker", label: "SATKER" },
].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-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"
> >
{item.label} <Checkbox
</Label> id={`${item.key}-${index}`}
</div> checked={
))} fileUnitSelections[index]?.[
item.key as keyof typeof unitSelection
{/* Tombol Kustom sejajar dengan checkbox */} ] || false
<div className="flex items-center justify-center p-3"> }
<Dialog> onCheckedChange={(value) => {
<DialogTrigger asChild> handleFileUnitChange(
<Button index,
variant="outline" item.key as keyof typeof unitSelection,
size="sm" value as boolean,
className="gap-2" );
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",
) })}
); </Button>
return ( </DialogTrigger>
<Button <DialogContent className="max-w-[95vw] lg:max-w-[1400px] max-h-[90vh]">
size="sm" <DialogHeader className="border-b border-gray-200 pb-4">
variant="outline" <DialogTitle className="text-lg font-semibold">
className="text-xs h-6 px-2" Daftar Wilayah POLDA dan
onClick={() => POLRES
handleSelectAllSubItems( </DialogTitle>
index, </DialogHeader>
polda <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}
{allSubItemsChecked ? ( className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
<> >
<Icon {/* Header POLDA */}
icon="material-symbols:check-indeterminate-small" <div className="flex items-center justify-between">
width={12} <Label className="flex items-center gap-3 flex-1 cursor-pointer">
height={ <Checkbox
12 checked={
} fileCheckedLevels[
className="mr-1" index
/> ]?.has(
Batal Semua Number(polda.id),
</> ) || false
) : ( }
<> onCheckedChange={() =>
<Icon handleFileCheckboxChangePlacement(
icon="material-symbols:check-all" index,
width={12} Number(polda.id),
height={ )
12 }
} />
className="mr-1" <span className="font-semibold text-gray-900 text-sm">
/> {polda.name}
Pilih Semua </span>
</> </Label>
)} {polda.subDestination && (
</Button> <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",
})} */} })} */}
Simpan Simpan
</Button> </Button>
</DialogClose> </DialogClose>
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div>
</div> </div>
</div> </div>
</div> )}
)}
</div> </div>
</div> </div>
) : ( ) : (
@ -1833,7 +1887,7 @@ export default function FormVideoDetail() {
> >
{template} {template}
</Button> </Button>
) ),
)} )}
</div> </div>
</div> </div>

View File

@ -59,7 +59,7 @@ const CustomEditor = dynamic(
() => { () => {
return import("@/components/editor/custom-editor"); return import("@/components/editor/custom-editor");
}, },
{ ssr: false } { ssr: false },
); );
interface FileWithPreview extends File { interface FileWithPreview extends File {
@ -111,11 +111,11 @@ export default function FormVideo() {
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false); const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
const [articleBody, setArticleBody] = useState<string>(""); const [articleBody, setArticleBody] = useState<string>("");
const [selectedArticleId, setSelectedArticleId] = useState<string | null>( const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
null null,
); );
const [selectedMainKeyword, setSelectedMainKeyword] = useState(""); const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
const [publishedForError, setPublishedForError] = useState<string | null>( const [publishedForError, setPublishedForError] = useState<string | null>(
null null,
); );
const [selectedSize, setSelectedSize] = useState(""); const [selectedSize, setSelectedSize] = useState("");
const [detailData, setDetailData] = useState<any>(null); const [detailData, setDetailData] = useState<any>(null);
@ -184,7 +184,7 @@ export default function FormVideo() {
} }
const filesWithPreview = acceptedFiles.map((file) => const filesWithPreview = acceptedFiles.map((file) =>
Object.assign(file, { preview: URL.createObjectURL(file) }) Object.assign(file, { preview: URL.createObjectURL(file) }),
); );
setFiles((prev) => { setFiles((prev) => {
@ -211,11 +211,11 @@ export default function FormVideo() {
.refine( .refine(
(files) => (files) =>
files.every((file: File) => ACCEPTED_FILE_TYPES.includes(file.type)), files.every((file: File) => ACCEPTED_FILE_TYPES.includes(file.type)),
{ message: "File harus berformat mp4 atau mov" } { message: "File harus berformat mp4 atau mov" },
) )
.refine( .refine(
(files) => files.every((file: File) => file.size <= MAX_FILE_SIZE), (files) => files.every((file: File) => file.size <= MAX_FILE_SIZE),
{ message: "Ukuran file maksimal 100 MB" } { message: "Ukuran file maksimal 100 MB" },
), ),
publishedFor: z publishedFor: z
.array(z.string()) .array(z.string())
@ -423,7 +423,7 @@ export default function FormVideo() {
const articleData = await waitForStatusUpdate(); const articleData = await waitForStatusUpdate();
const cleanArticleBody = articleData?.articleBody?.replace( const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g, /<img[^>]*>/g,
"" "",
); );
const articleImagesData = articleData?.imagesUrl?.split(","); const articleImagesData = articleData?.imagesUrl?.split(",");
setValue("description", cleanArticleBody || ""); setValue("description", cleanArticleBody || "");
@ -479,7 +479,7 @@ export default function FormVideo() {
if (scheduleId && scheduleType === "3") { if (scheduleId && scheduleType === "3") {
const findCategory = resCategory.find((o) => const findCategory = resCategory.find((o) =>
o.name.toLowerCase().includes("pers rilis") o.name.toLowerCase().includes("pers rilis"),
); );
if (findCategory) { if (findCategory) {
@ -502,7 +502,7 @@ export default function FormVideo() {
setPublishedFor( setPublishedFor(
options options
.filter((opt: any) => opt.id !== "all") .filter((opt: any) => opt.id !== "all")
.map((opt: any) => opt.id) .map((opt: any) => opt.id),
); );
} }
} else { } else {
@ -561,8 +561,8 @@ export default function FormVideo() {
translatedTitle && translatedTitle.trim() !== "" translatedTitle && translatedTitle.trim() !== ""
? translatedTitle ? translatedTitle
: isSwitchOn : isSwitchOn
? title ? title
: data.title; : data.title;
// Tentukan deskripsi final: // Tentukan deskripsi final:
// Jika ada hasil translate, kirim itu ke backend // Jika ada hasil translate, kirim itu ke backend
@ -570,10 +570,10 @@ export default function FormVideo() {
translatedContent && translatedContent.trim() !== "" translatedContent && translatedContent.trim() !== ""
? translatedContent ? translatedContent
: isSwitchOn : isSwitchOn
? data.description ? data.description
: selectedFileType === "rewrite" : selectedFileType === "rewrite"
? data.rewriteDescription ? data.rewriteDescription
: data.descriptionOri; : data.descriptionOri;
if (!finalDescription?.trim()) { if (!finalDescription?.trim()) {
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error"); MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
@ -695,7 +695,7 @@ export default function FormVideo() {
idx: number, idx: number,
id: string, id: string,
file: any, file: any,
duration: string duration: string,
) { ) {
console.log(idx, id, file, duration); console.log(idx, id, file, duration);
@ -731,7 +731,7 @@ export default function FormVideo() {
onChunkComplete: ( onChunkComplete: (
chunkSize: any, chunkSize: any,
bytesAccepted: any, bytesAccepted: any,
bytesTotal: any bytesTotal: any,
) => { ) => {
const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100); const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100);
progressInfo[idx].percentage = uploadPersen; progressInfo[idx].percentage = uploadPersen;
@ -791,8 +791,8 @@ export default function FormVideo() {
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]; const file = e.target.files?.[0];
if (file) { if (file) {
setThumbnail(file); setThumbnail(file);
setPreview(URL.createObjectURL(file)); setPreview(URL.createObjectURL(file));
console.log("Selected Thumbnail:", file); console.log("Selected Thumbnail:", file);
} }
}; };
@ -823,7 +823,7 @@ export default function FormVideo() {
<div <div
key={file.name} key={file.name}
className=" flex justify-between border px-3.5 py-3 my-6 rounded-md" className=" flex justify-between border px-3.5 py-3 my-6 rounded-md"
> >
<div className="flex gap-3 items-center"> <div className="flex gap-3 items-center">
{/* <div className="file-preview">{renderFilePreview(file)}</div> */} {/* <div className="file-preview">{renderFilePreview(file)}</div> */}
<svg <svg
@ -1732,7 +1732,7 @@ export default function FormVideo() {
type="button" type="button"
onClick={() => { onClick={() => {
const updatedTags = field.value.filter( const updatedTags = field.value.filter(
(_, i) => i !== index (_, i) => i !== index,
); );
field.onChange(updatedTags); field.onChange(updatedTags);
}} }}
@ -1825,7 +1825,7 @@ export default function FormVideo() {
{/* <Button type="submit" color="primary"> {/* <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> */} </Button> */}
{levelNumber !== "2" && levelNumber !== "3" && ( {levelNumber !== "2" && (
<Button type="submit" color="primary"> <Button type="submit" color="primary">
{t("submit", { defaultValue: "Submit" })} {t("submit", { defaultValue: "Submit" })}
</Button> </Button>

View File

@ -1 +1,2 @@
export const GoogleMapsAPI = "AIzaSyCuQHorDceMCzlSgrB9AEY5ns8KeriFsME"; // export const GoogleMapsAPI = "AIzaSyCuQHorDceMCzlSgrB9AEY5ns8KeriFsME";
export const GoogleMapsAPI = "AIzaSyA-Dci9RP4ZjyJCFfy74WvhtMZXSDLTPMQ";