fix: satker section all and maps
This commit is contained in:
parent
44c6cc6d9d
commit
740d73d689
|
|
@ -115,7 +115,7 @@ const ViewEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/view-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
interface Destination {
|
||||
|
|
@ -198,6 +198,12 @@ export default function FormAudioDetail() {
|
|||
satker: boolean;
|
||||
}>
|
||||
>([]);
|
||||
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const isContentFromSatker = creatorLevelNumber === 3;
|
||||
const isContentFromMabesOrPolda =
|
||||
creatorLevelNumber === 1 || creatorLevelNumber === 2;
|
||||
|
||||
useEffect(() => {
|
||||
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||
|
|
@ -209,7 +215,7 @@ export default function FormAudioDetail() {
|
|||
const handleFileUnitChange = (
|
||||
fileIndex: number,
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
setFileUnitSelections((prev) => {
|
||||
const newSelections = [...prev];
|
||||
|
|
@ -229,7 +235,7 @@ export default function FormAudioDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[fileIndex] || new Set()
|
||||
newArray[fileIndex] || new Set(),
|
||||
);
|
||||
|
||||
if (value) {
|
||||
|
|
@ -260,12 +266,12 @@ export default function FormAudioDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
currentFileCheckedLevels.has(Number(item.id))
|
||||
currentFileCheckedLevels.has(Number(item.id)),
|
||||
);
|
||||
|
||||
if (!hasSelectedPolda) {
|
||||
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
|
||||
}
|
||||
|
|
@ -302,7 +308,7 @@ export default function FormAudioDetail() {
|
|||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
detail.assignedToTopLevel.split(",").map(Number),
|
||||
);
|
||||
setUnitSelection({
|
||||
semua: outputSet.has(0),
|
||||
|
|
@ -327,7 +333,7 @@ export default function FormAudioDetail() {
|
|||
acc[polda.id] = false;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
setExpandedPolda(initialExpandedState);
|
||||
console.log("polres", initialExpandedState);
|
||||
|
|
@ -362,7 +368,7 @@ export default function FormAudioDetail() {
|
|||
|
||||
const handleUnitChange = (
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
if (key === "semua") {
|
||||
const newState = {
|
||||
|
|
@ -472,7 +478,7 @@ export default function FormAudioDetail() {
|
|||
|
||||
const handleCheckboxChange = (id: number) => {
|
||||
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") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -542,6 +548,9 @@ export default function FormAudioDetail() {
|
|||
const details = response?.data?.data;
|
||||
setFiles(details?.files);
|
||||
setDetail(details);
|
||||
if (details?.uploadedBy?.userLevel?.levelNumber) {
|
||||
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
|
||||
}
|
||||
setMain({
|
||||
type: details?.fileType.name,
|
||||
url: details?.files[0]?.url,
|
||||
|
|
@ -552,14 +561,14 @@ export default function FormAudioDetail() {
|
|||
|
||||
if (details?.assignedToLevel) {
|
||||
const levels = new Set(
|
||||
details.assignedToLevel.split(",").map(Number)
|
||||
details.assignedToLevel.split(",").map(Number),
|
||||
);
|
||||
setCheckedLevels(levels);
|
||||
}
|
||||
|
||||
if (details?.publishedForObject) {
|
||||
const publisherIds = details?.publishedForObject.map(
|
||||
(obj: any) => obj.id
|
||||
(obj: any) => obj.id,
|
||||
);
|
||||
setSelectedPublishers(publisherIds);
|
||||
}
|
||||
|
|
@ -709,7 +718,7 @@ export default function FormAudioDetail() {
|
|||
const setupPlacement = (
|
||||
index: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
let temp = [...filePlacements];
|
||||
if (checked) {
|
||||
|
|
@ -720,7 +729,7 @@ export default function FormAudioDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Checklist semua item di modal
|
||||
|
|
@ -770,7 +779,7 @@ export default function FormAudioDetail() {
|
|||
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
||||
// JANGAN include satker dalam perhitungan auto "all"
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
||||
now.push("all");
|
||||
|
|
@ -785,7 +794,7 @@ export default function FormAudioDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Unchecklist semua item di modal
|
||||
|
|
@ -819,7 +828,7 @@ export default function FormAudioDetail() {
|
|||
// Hapus "all" jika tidak semua item ter-checklist
|
||||
if (now.includes("all")) {
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length < 3) {
|
||||
const newData = now.filter((b) => b !== "all");
|
||||
|
|
@ -838,7 +847,7 @@ export default function FormAudioDetail() {
|
|||
type: string,
|
||||
url: string,
|
||||
names: string,
|
||||
format: string
|
||||
format: string,
|
||||
) => {
|
||||
console.log("Test 3 :", type, url, names, format);
|
||||
setMain({
|
||||
|
|
@ -873,7 +882,7 @@ export default function FormAudioDetail() {
|
|||
const updateModalChecklistLevels = (
|
||||
fileIndex: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
if (!listDest || listDest.length === 0) return;
|
||||
|
||||
|
|
@ -906,7 +915,7 @@ export default function FormAudioDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.add(Number(satkerItem.id));
|
||||
|
|
@ -942,7 +951,7 @@ export default function FormAudioDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.delete(Number(satkerItem.id));
|
||||
|
|
@ -975,7 +984,7 @@ export default function FormAudioDetail() {
|
|||
// Fungsi untuk mengupdate checklist levels untuk file tertentu
|
||||
const handleFileCheckboxChangePlacement = (
|
||||
fileIndex: number,
|
||||
levelId: number
|
||||
levelId: number,
|
||||
) => {
|
||||
setFileCheckedLevels((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
|
||||
const poldaItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (
|
||||
poldaItem &&
|
||||
|
|
@ -1010,7 +1019,7 @@ export default function FormAudioDetail() {
|
|||
|
||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||
// 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)
|
||||
const totalPoldaCount = listDest.filter(
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI",
|
||||
).length;
|
||||
|
||||
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
||||
|
|
@ -1068,7 +1077,7 @@ export default function FormAudioDetail() {
|
|||
}
|
||||
return total;
|
||||
},
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
// Hitung berapa banyak POLRES yang ter-checklist
|
||||
|
|
@ -1078,7 +1087,7 @@ export default function FormAudioDetail() {
|
|||
return (
|
||||
total +
|
||||
item.subDestination.filter((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
@ -1087,7 +1096,7 @@ export default function FormAudioDetail() {
|
|||
|
||||
// Cek apakah SATKER POLRI ter-checklist
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
const isSatkerChecked =
|
||||
satkerItem && currentFileLevels.has(Number(satkerItem.id));
|
||||
|
|
@ -1121,7 +1130,7 @@ export default function FormAudioDetail() {
|
|||
|
||||
// Cek apakah semua sub-items sudah ter-checklist
|
||||
const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
);
|
||||
|
||||
if (allSubItemsChecked) {
|
||||
|
|
@ -1204,7 +1213,7 @@ export default function FormAudioDetail() {
|
|||
{detail &&
|
||||
!categories.find(
|
||||
(cat) =>
|
||||
String(cat.id) === String(detail.category.id)
|
||||
String(cat.id) === String(detail.category.id),
|
||||
) && (
|
||||
<SelectItem
|
||||
key={String(detail.category.id)}
|
||||
|
|
@ -1464,7 +1473,7 @@ export default function FormAudioDetail() {
|
|||
Tingkat Distribusi:
|
||||
</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{/* {[
|
||||
{ key: "semua", label: "Semua" },
|
||||
{ key: "nasional", label: "Nasional" },
|
||||
{ key: "wilayah", label: "Wilayah" },
|
||||
|
|
@ -1472,6 +1481,39 @@ export default function FormAudioDetail() {
|
|||
key: "international",
|
||||
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) => (
|
||||
<div
|
||||
key={item.key}
|
||||
|
|
@ -1488,12 +1530,12 @@ export default function FormAudioDetail() {
|
|||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -1509,251 +1551,262 @@ export default function FormAudioDetail() {
|
|||
</div>
|
||||
|
||||
{/* Detail Wilayah */}
|
||||
{fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
{/* {fileUnitSelections[index]?.wilayah && ( */}
|
||||
{!isContentFromSatker &&
|
||||
fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
{item.label}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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>
|
||||
{item.label}
|
||||
</Label>
|
||||
</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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
)
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
polda
|
||||
)
|
||||
}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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>
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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,
|
||||
);
|
||||
})()}
|
||||
</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={
|
||||
}}
|
||||
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 */}
|
||||
{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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
) || false
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleFileCheckboxChangePlacement(
|
||||
sub.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
polda,
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="text-gray-700">
|
||||
{sub.name}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
)}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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 className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
defaultValue: "Simpan",
|
||||
})} */}
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -1832,7 +1885,7 @@ export default function FormAudioDetail() {
|
|||
>
|
||||
{template}
|
||||
</Button>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1806,7 +1806,7 @@ export default function FormAudio() {
|
|||
</Card>
|
||||
<div className="flex flex-row justify-end gap-3">
|
||||
<div className="mt-4">
|
||||
{levelNumber !== "2" && levelNumber !== "3" && (
|
||||
{levelNumber !== "2" && (
|
||||
<Button type="submit" color="primary">
|
||||
{t("submit", { defaultValue: "Submit" })}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ const ViewEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/view-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
interface Destination {
|
||||
|
|
@ -172,6 +172,12 @@ export default function FormImageDetail() {
|
|||
satker: boolean;
|
||||
}>
|
||||
>([]);
|
||||
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const isContentFromSatker = creatorLevelNumber === 3;
|
||||
const isContentFromMabesOrPolda =
|
||||
creatorLevelNumber === 1 || creatorLevelNumber === 2;
|
||||
|
||||
useEffect(() => {
|
||||
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||
|
|
@ -200,7 +206,7 @@ export default function FormImageDetail() {
|
|||
const [files, setFiles] = useState<FileType[]>([]);
|
||||
const [rejectedFiles, setRejectedFiles] = useState<number[]>([]);
|
||||
const [expandedPolda, setExpandedPolda] = useState<Record<number, boolean>>(
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
// State untuk melacak apakah perubahan berasal dari checkbox utama
|
||||
|
|
@ -231,7 +237,7 @@ export default function FormImageDetail() {
|
|||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
detail.assignedToTopLevel.split(",").map(Number),
|
||||
);
|
||||
setUnitSelection({
|
||||
semua: outputSet.has(0),
|
||||
|
|
@ -260,7 +266,7 @@ export default function FormImageDetail() {
|
|||
acc[polda.id] = false;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
setExpandedPolda(initialExpandedState);
|
||||
console.log("polres", initialExpandedState);
|
||||
|
|
@ -299,7 +305,7 @@ export default function FormImageDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
checkedLevels.has(Number(item.id))
|
||||
checkedLevels.has(Number(item.id)),
|
||||
).length;
|
||||
|
||||
const checkedPolresCount = listDest.reduce((total: number, item: any) => {
|
||||
|
|
@ -308,7 +314,7 @@ export default function FormImageDetail() {
|
|||
return (
|
||||
total +
|
||||
item.subDestination.filter((sub: any) =>
|
||||
checkedLevels.has(Number(sub.id))
|
||||
checkedLevels.has(Number(sub.id)),
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
@ -316,12 +322,12 @@ export default function FormImageDetail() {
|
|||
}, 0);
|
||||
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
const checkedSatkerCount = satkerItem
|
||||
? (checkedLevels.has(Number(satkerItem.id)) ? 1 : 0) +
|
||||
(satkerItem.subDestination?.filter((sub: any) =>
|
||||
checkedLevels.has(Number(sub.id))
|
||||
checkedLevels.has(Number(sub.id)),
|
||||
).length || 0)
|
||||
: 0;
|
||||
|
||||
|
|
@ -391,7 +397,7 @@ export default function FormImageDetail() {
|
|||
} else if (mainCheckboxChangeType === "satker_checked") {
|
||||
// Checklist satker
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
newCheckedLevels.add(Number(satkerItem.id));
|
||||
|
|
@ -439,7 +445,7 @@ export default function FormImageDetail() {
|
|||
} else if (mainCheckboxChangeType === "satker_unchecked") {
|
||||
// Clear satker dan semua sub-item di bawahnya dari checkedLevels
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
newCheckedLevels.delete(Number(satkerItem.id));
|
||||
|
|
@ -466,7 +472,7 @@ export default function FormImageDetail() {
|
|||
const handleFileUnitChange = (
|
||||
fileIndex: number,
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
setFileUnitSelections((prev) => {
|
||||
const newSelections = [...prev];
|
||||
|
|
@ -486,7 +492,7 @@ export default function FormImageDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[fileIndex] || new Set()
|
||||
newArray[fileIndex] || new Set(),
|
||||
);
|
||||
|
||||
if (value) {
|
||||
|
|
@ -517,12 +523,12 @@ export default function FormImageDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
currentFileCheckedLevels.has(Number(item.id))
|
||||
currentFileCheckedLevels.has(Number(item.id)),
|
||||
);
|
||||
|
||||
if (!hasSelectedPolda) {
|
||||
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
|
||||
}
|
||||
|
|
@ -552,7 +558,7 @@ export default function FormImageDetail() {
|
|||
// Fungsi lama untuk kompatibilitas (akan dihapus nanti)
|
||||
const handleUnitChange = (
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
// Set flag bahwa perubahan berasal dari checkbox utama
|
||||
setIsUpdatingFromMainCheckbox(true);
|
||||
|
|
@ -578,13 +584,13 @@ export default function FormImageDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
checkedLevels.has(Number(item.id))
|
||||
checkedLevels.has(Number(item.id)),
|
||||
);
|
||||
|
||||
if (!hasSelectedPolda) {
|
||||
// Jika tidak ada POLDA yang dipilih, tampilkan peringatan dan batalkan
|
||||
alert(
|
||||
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES."
|
||||
"Harap pilih POLDA di Modal terlebih dahulu sebelum mengaktifkan checkbox POLRES.",
|
||||
);
|
||||
// Reset flag karena perubahan dibatalkan
|
||||
setIsUpdatingFromMainCheckbox(false);
|
||||
|
|
@ -640,14 +646,14 @@ export default function FormImageDetail() {
|
|||
|
||||
const handleCheckboxChange = (id: number) => {
|
||||
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
|
||||
const handleFileCheckboxChangePlacement = (
|
||||
fileIndex: number,
|
||||
levelId: number
|
||||
levelId: number,
|
||||
) => {
|
||||
setFileCheckedLevels((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
|
||||
const poldaItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (
|
||||
poldaItem &&
|
||||
|
|
@ -682,7 +688,7 @@ export default function FormImageDetail() {
|
|||
|
||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||
// 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
|
||||
const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
);
|
||||
|
||||
if (allSubItemsChecked) {
|
||||
|
|
@ -750,7 +756,7 @@ export default function FormImageDetail() {
|
|||
|
||||
// Hitung total POLDA yang ada (bukan SATKER POLRI)
|
||||
const totalPoldaCount = listDest.filter(
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI",
|
||||
).length;
|
||||
|
||||
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
||||
|
|
@ -777,7 +783,7 @@ export default function FormImageDetail() {
|
|||
}
|
||||
return total;
|
||||
},
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
// Hitung berapa banyak POLRES yang ter-checklist
|
||||
|
|
@ -787,7 +793,7 @@ export default function FormImageDetail() {
|
|||
return (
|
||||
total +
|
||||
item.subDestination.filter((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
@ -796,7 +802,7 @@ export default function FormImageDetail() {
|
|||
|
||||
// Cek apakah SATKER POLRI ter-checklist
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
const isSatkerChecked =
|
||||
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
|
||||
const poldaItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (
|
||||
poldaItem &&
|
||||
|
|
@ -856,7 +862,7 @@ export default function FormImageDetail() {
|
|||
|
||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||
// Checklist semua sub-item di bawah SATKER POLRI (bukan POLRES)
|
||||
|
|
@ -887,7 +893,7 @@ export default function FormImageDetail() {
|
|||
|
||||
if (scheduleId && scheduleType === "3") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -936,6 +942,11 @@ export default function FormImageDetail() {
|
|||
console.log("detail", details);
|
||||
setFiles(details?.files);
|
||||
setDetail(details);
|
||||
|
||||
if (details?.uploadedBy?.userLevel?.levelNumber) {
|
||||
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
|
||||
}
|
||||
|
||||
setMain({
|
||||
type: details?.fileType.name,
|
||||
url: details?.files[0]?.url,
|
||||
|
|
@ -946,14 +957,14 @@ export default function FormImageDetail() {
|
|||
|
||||
if (details?.assignedToLevel) {
|
||||
const levels = new Set<number>(
|
||||
details.assignedToLevel.split(",").map(Number)
|
||||
details.assignedToLevel.split(",").map(Number),
|
||||
);
|
||||
setCheckedLevels(levels);
|
||||
}
|
||||
|
||||
if (details?.publishedForObject) {
|
||||
const publisherIds = details?.publishedForObject?.map(
|
||||
(obj: any) => obj.id
|
||||
(obj: any) => obj.id,
|
||||
);
|
||||
setSelectedPublishers(publisherIds);
|
||||
}
|
||||
|
|
@ -963,7 +974,7 @@ export default function FormImageDetail() {
|
|||
|
||||
const filesData = details.files || [];
|
||||
const fileUrls = filesData.map((file: { thumbnailFileUrl: string }) =>
|
||||
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg"
|
||||
file.thumbnailFileUrl ? file.thumbnailFileUrl : "default-image.jpg",
|
||||
);
|
||||
setDetailThumb(fileUrls);
|
||||
|
||||
|
|
@ -1083,7 +1094,7 @@ export default function FormImageDetail() {
|
|||
const setupPlacement = (
|
||||
index: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
let temp = [...filePlacements];
|
||||
if (checked) {
|
||||
|
|
@ -1094,7 +1105,7 @@ export default function FormImageDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Checklist semua item di modal
|
||||
|
|
@ -1144,7 +1155,7 @@ export default function FormImageDetail() {
|
|||
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
||||
// JANGAN include satker dalam perhitungan auto "all"
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
||||
now.push("all");
|
||||
|
|
@ -1159,7 +1170,7 @@ export default function FormImageDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Unchecklist semua item di modal
|
||||
|
|
@ -1193,7 +1204,7 @@ export default function FormImageDetail() {
|
|||
// Hapus "all" jika tidak semua item ter-checklist
|
||||
if (now.includes("all")) {
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length < 3) {
|
||||
const newData = now.filter((b) => b !== "all");
|
||||
|
|
@ -1212,7 +1223,7 @@ export default function FormImageDetail() {
|
|||
const updateModalChecklistLevels = (
|
||||
fileIndex: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
if (!listDest || listDest.length === 0) return;
|
||||
|
||||
|
|
@ -1245,7 +1256,7 @@ export default function FormImageDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.add(Number(satkerItem.id));
|
||||
|
|
@ -1281,7 +1292,7 @@ export default function FormImageDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.delete(Number(satkerItem.id));
|
||||
|
|
@ -1311,7 +1322,7 @@ export default function FormImageDetail() {
|
|||
type: string,
|
||||
url: string,
|
||||
names: string,
|
||||
format: string
|
||||
format: string,
|
||||
) => {
|
||||
console.log("Test 3 :", type, url, names, format);
|
||||
setMain({
|
||||
|
|
@ -1411,7 +1422,7 @@ export default function FormImageDetail() {
|
|||
{detail &&
|
||||
!categories.find(
|
||||
(cat) =>
|
||||
String(cat.id) === String(detail.category.id)
|
||||
String(cat.id) === String(detail.category.id),
|
||||
) && (
|
||||
<SelectItem
|
||||
key={String(detail.category.id)}
|
||||
|
|
@ -1732,7 +1743,7 @@ export default function FormImageDetail() {
|
|||
Tingkat Distribusi:
|
||||
</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{/* {[
|
||||
{ key: "semua", label: "Semua" },
|
||||
{ key: "nasional", label: "Nasional" },
|
||||
{ key: "wilayah", label: "Wilayah" },
|
||||
|
|
@ -1740,6 +1751,39 @@ export default function FormImageDetail() {
|
|||
key: "international",
|
||||
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) => (
|
||||
<div
|
||||
key={item.key}
|
||||
|
|
@ -1756,12 +1800,12 @@ export default function FormImageDetail() {
|
|||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -1777,246 +1821,257 @@ export default function FormImageDetail() {
|
|||
</div>
|
||||
|
||||
{/* Detail Wilayah */}
|
||||
{fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
{/* {fileUnitSelections[index]?.wilayah && ( */}
|
||||
{!isContentFromSatker &&
|
||||
fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
{item.label}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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>
|
||||
{item.label}
|
||||
</Label>
|
||||
</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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
)
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
polda
|
||||
)
|
||||
}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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>
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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,
|
||||
);
|
||||
})()}
|
||||
</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={
|
||||
}}
|
||||
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 */}
|
||||
{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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
) || false
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleFileCheckboxChangePlacement(
|
||||
sub.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
polda,
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="text-gray-700">
|
||||
{sub.name}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
)}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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 className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>Simpan</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>Simpan</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -2095,7 +2150,7 @@ export default function FormImageDetail() {
|
|||
>
|
||||
{template}
|
||||
</Button>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ const CustomEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/custom-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
export default function FormImage() {
|
||||
|
|
@ -117,7 +117,7 @@ export default function FormImage() {
|
|||
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
||||
const [articleBody, setArticleBody] = useState<string>("");
|
||||
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||
|
|
@ -183,17 +183,17 @@ export default function FormImage() {
|
|||
.filter(
|
||||
(file) =>
|
||||
["image/jpeg", "image/png", "image/jpg"].includes(file.type) &&
|
||||
file.size <= MAX_FILE_SIZE
|
||||
file.size <= MAX_FILE_SIZE,
|
||||
)
|
||||
.map((file) =>
|
||||
Object.assign(file, {
|
||||
preview: URL.createObjectURL(file),
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (validFiles.length === 0) {
|
||||
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;
|
||||
}
|
||||
|
|
@ -227,12 +227,12 @@ export default function FormImage() {
|
|||
files.every(
|
||||
(file: File) =>
|
||||
["image/jpeg", "image/png", "image/jpg"].includes(file.type) &&
|
||||
file.size <= 100 * 1024 * 1024
|
||||
file.size <= 100 * 1024 * 1024,
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Hanya file .jpg, .jpeg, .png, maksimal 100MB yang diperbolehkan.",
|
||||
}
|
||||
},
|
||||
),
|
||||
categoryId: z.string().min(1, { message: "Kategori wajib dipilih." }),
|
||||
tags: z
|
||||
|
|
@ -454,7 +454,7 @@ export default function FormImage() {
|
|||
const articleData = await waitForStatusUpdate();
|
||||
const cleanArticleBody = articleData?.articleBody?.replace(
|
||||
/<img[^>]*>/g,
|
||||
""
|
||||
"",
|
||||
);
|
||||
const articleImagesData = articleData?.imagesUrl?.split(",");
|
||||
setArticleBody(cleanArticleBody || "");
|
||||
|
|
@ -507,7 +507,7 @@ export default function FormImage() {
|
|||
|
||||
if (scheduleId && scheduleType === "3") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -530,7 +530,7 @@ export default function FormImage() {
|
|||
setPublishedFor(
|
||||
options
|
||||
.filter((opt: any) => opt.id !== "all")
|
||||
.map((opt: any) => opt.id)
|
||||
.map((opt: any) => opt.id),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -594,11 +594,16 @@ export default function FormImage() {
|
|||
} else if (data.rewriteDescription && selectedFileType === "rewrite") {
|
||||
finalDescription = data.rewriteDescription;
|
||||
console.log("📤 Upload versi rewrite");
|
||||
} else {
|
||||
// fallback: gunakan versi Indonesia original
|
||||
finalDescription = data.descriptionOri ?? "";
|
||||
console.log("📤 Upload versi Indonesia (original)");
|
||||
} else if (data.description?.trim()) {
|
||||
finalDescription = data.description;
|
||||
} else if (data.descriptionOri?.trim()) {
|
||||
finalDescription = data.descriptionOri;
|
||||
}
|
||||
// else {
|
||||
// // fallback: gunakan versi Indonesia original
|
||||
// finalDescription = data.descriptionOri ?? "";
|
||||
// console.log("📤 Upload versi Indonesia (original)");
|
||||
// }
|
||||
|
||||
if (!finalDescription?.trim()) {
|
||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||
|
|
@ -690,7 +695,7 @@ export default function FormImage() {
|
|||
index,
|
||||
String(id),
|
||||
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,
|
||||
id: string,
|
||||
file: any,
|
||||
duration: string
|
||||
duration: string,
|
||||
) {
|
||||
console.log(idx, id, file, duration);
|
||||
|
||||
|
|
@ -753,7 +758,7 @@ export default function FormImage() {
|
|||
onChunkComplete: (
|
||||
chunkSize: any,
|
||||
bytesAccepted: any,
|
||||
bytesTotal: any
|
||||
bytesTotal: any,
|
||||
) => {
|
||||
const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100);
|
||||
progressInfo[idx].percentage = uploadPersen;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ const ViewEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/view-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
interface Destination {
|
||||
|
|
@ -191,6 +191,12 @@ export default function FormTeksDetail() {
|
|||
satker: boolean;
|
||||
}>
|
||||
>([]);
|
||||
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const isContentFromSatker = creatorLevelNumber === 3;
|
||||
const isContentFromMabesOrPolda =
|
||||
creatorLevelNumber === 1 || creatorLevelNumber === 2;
|
||||
|
||||
useEffect(() => {
|
||||
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||
|
|
@ -202,7 +208,7 @@ export default function FormTeksDetail() {
|
|||
const handleFileUnitChange = (
|
||||
fileIndex: number,
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
setFileUnitSelections((prev) => {
|
||||
const newSelections = [...prev];
|
||||
|
|
@ -222,7 +228,7 @@ export default function FormTeksDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[fileIndex] || new Set()
|
||||
newArray[fileIndex] || new Set(),
|
||||
);
|
||||
|
||||
if (value) {
|
||||
|
|
@ -253,12 +259,12 @@ export default function FormTeksDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
currentFileCheckedLevels.has(Number(item.id))
|
||||
currentFileCheckedLevels.has(Number(item.id)),
|
||||
);
|
||||
|
||||
if (!hasSelectedPolda) {
|
||||
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
|
||||
}
|
||||
|
|
@ -297,7 +303,7 @@ export default function FormTeksDetail() {
|
|||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
detail.assignedToTopLevel.split(",").map(Number),
|
||||
);
|
||||
setUnitSelection({
|
||||
semua: outputSet.has(0),
|
||||
|
|
@ -322,7 +328,7 @@ export default function FormTeksDetail() {
|
|||
acc[polda.id] = false;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
setExpandedPolda(initialExpandedState);
|
||||
console.log("polres", initialExpandedState);
|
||||
|
|
@ -357,7 +363,7 @@ export default function FormTeksDetail() {
|
|||
|
||||
const handleUnitChange = (
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
if (key === "semua") {
|
||||
const newState = {
|
||||
|
|
@ -436,7 +442,7 @@ export default function FormTeksDetail() {
|
|||
|
||||
const handleCheckboxChange = (id: number) => {
|
||||
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") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -507,6 +513,9 @@ export default function FormTeksDetail() {
|
|||
console.log("detail", details);
|
||||
setFiles(details?.files);
|
||||
setDetail(details);
|
||||
if (details?.uploadedBy?.userLevel?.levelNumber) {
|
||||
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
|
||||
}
|
||||
setMain({
|
||||
type: details?.fileType.name,
|
||||
url: details?.files[0]?.url,
|
||||
|
|
@ -517,14 +526,14 @@ export default function FormTeksDetail() {
|
|||
|
||||
if (details?.assignedToLevel) {
|
||||
const levels = new Set(
|
||||
details.assignedToLevel.split(",").map(Number)
|
||||
details.assignedToLevel.split(",").map(Number),
|
||||
);
|
||||
setCheckedLevels(levels);
|
||||
}
|
||||
|
||||
if (details?.publishedForObject) {
|
||||
const publisherIds = details?.publishedForObject?.map(
|
||||
(obj: any) => obj.id
|
||||
(obj: any) => obj.id,
|
||||
);
|
||||
setSelectedPublishers(publisherIds);
|
||||
}
|
||||
|
|
@ -696,7 +705,7 @@ export default function FormTeksDetail() {
|
|||
type: string,
|
||||
url: string,
|
||||
names: string,
|
||||
format: string
|
||||
format: string,
|
||||
) => {
|
||||
console.log("Test 3 :", type, url, names, format);
|
||||
setMain({
|
||||
|
|
@ -723,7 +732,7 @@ export default function FormTeksDetail() {
|
|||
const setupPlacement = (
|
||||
index: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
let temp = [...filePlacements];
|
||||
if (checked) {
|
||||
|
|
@ -734,7 +743,7 @@ export default function FormTeksDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Checklist semua item di modal
|
||||
|
|
@ -784,7 +793,7 @@ export default function FormTeksDetail() {
|
|||
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
||||
// JANGAN include satker dalam perhitungan auto "all"
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
||||
now.push("all");
|
||||
|
|
@ -799,7 +808,7 @@ export default function FormTeksDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Unchecklist semua item di modal
|
||||
|
|
@ -833,7 +842,7 @@ export default function FormTeksDetail() {
|
|||
// Hapus "all" jika tidak semua item ter-checklist
|
||||
if (now.includes("all")) {
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length < 3) {
|
||||
const newData = now.filter((b) => b !== "all");
|
||||
|
|
@ -851,7 +860,7 @@ export default function FormTeksDetail() {
|
|||
const updateModalChecklistLevels = (
|
||||
fileIndex: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
if (!listDest || listDest.length === 0) return;
|
||||
|
||||
|
|
@ -884,7 +893,7 @@ export default function FormTeksDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.add(Number(satkerItem.id));
|
||||
|
|
@ -920,7 +929,7 @@ export default function FormTeksDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.delete(Number(satkerItem.id));
|
||||
|
|
@ -953,7 +962,7 @@ export default function FormTeksDetail() {
|
|||
// Fungsi untuk mengupdate checklist levels untuk file tertentu
|
||||
const handleFileCheckboxChangePlacement = (
|
||||
fileIndex: number,
|
||||
levelId: number
|
||||
levelId: number,
|
||||
) => {
|
||||
setFileCheckedLevels((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
|
||||
const poldaItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (
|
||||
poldaItem &&
|
||||
|
|
@ -988,7 +997,7 @@ export default function FormTeksDetail() {
|
|||
|
||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||
// 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)
|
||||
const totalPoldaCount = listDest.filter(
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI",
|
||||
).length;
|
||||
|
||||
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
||||
|
|
@ -1046,7 +1055,7 @@ export default function FormTeksDetail() {
|
|||
}
|
||||
return total;
|
||||
},
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
// Hitung berapa banyak POLRES yang ter-checklist
|
||||
|
|
@ -1056,7 +1065,7 @@ export default function FormTeksDetail() {
|
|||
return (
|
||||
total +
|
||||
item.subDestination.filter((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
@ -1065,7 +1074,7 @@ export default function FormTeksDetail() {
|
|||
|
||||
// Cek apakah SATKER POLRI ter-checklist
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
const isSatkerChecked =
|
||||
satkerItem && currentFileLevels.has(Number(satkerItem.id));
|
||||
|
|
@ -1099,7 +1108,7 @@ export default function FormTeksDetail() {
|
|||
|
||||
// Cek apakah semua sub-items sudah ter-checklist
|
||||
const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
);
|
||||
|
||||
if (allSubItemsChecked) {
|
||||
|
|
@ -1182,7 +1191,7 @@ export default function FormTeksDetail() {
|
|||
{detail &&
|
||||
!categories.find(
|
||||
(cat) =>
|
||||
String(cat.id) === String(detail.category.id)
|
||||
String(cat.id) === String(detail.category.id),
|
||||
) && (
|
||||
<SelectItem
|
||||
key={String(detail.category.id)}
|
||||
|
|
@ -1465,7 +1474,7 @@ export default function FormTeksDetail() {
|
|||
Tingkat Distribusi:
|
||||
</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{/* {[
|
||||
{ key: "semua", label: "Semua" },
|
||||
{ key: "nasional", label: "Nasional" },
|
||||
{ key: "wilayah", label: "Wilayah" },
|
||||
|
|
@ -1473,6 +1482,39 @@ export default function FormTeksDetail() {
|
|||
key: "international",
|
||||
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) => (
|
||||
<div
|
||||
key={item.key}
|
||||
|
|
@ -1489,12 +1531,12 @@ export default function FormTeksDetail() {
|
|||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -1510,251 +1552,262 @@ export default function FormTeksDetail() {
|
|||
</div>
|
||||
|
||||
{/* Detail Wilayah */}
|
||||
{fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
{/* {fileUnitSelections[index]?.wilayah && ( */}
|
||||
{!isContentFromSatker &&
|
||||
fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
{item.label}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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>
|
||||
{item.label}
|
||||
</Label>
|
||||
</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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
)
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
polda
|
||||
)
|
||||
}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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>
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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,
|
||||
);
|
||||
})()}
|
||||
</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={
|
||||
}}
|
||||
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 */}
|
||||
{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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
) || false
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleFileCheckboxChangePlacement(
|
||||
sub.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
polda,
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="text-gray-700">
|
||||
{sub.name}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
)}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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 className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
defaultValue: "Simpan",
|
||||
})} */}
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -1833,7 +1886,7 @@ export default function FormTeksDetail() {
|
|||
>
|
||||
{template}
|
||||
</Button>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1776,7 +1776,7 @@ export default function FormTeks() {
|
|||
{/* <Button type="submit" color="primary">
|
||||
{t("submit", { defaultValue: "Submit" })}
|
||||
</Button> */}
|
||||
{levelNumber !== "2" && levelNumber !== "3" && (
|
||||
{levelNumber !== "2" && (
|
||||
<Button type="submit" color="primary">
|
||||
{t("submit", { defaultValue: "Submit" })}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ const ViewEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/view-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
interface Destination {
|
||||
|
|
@ -190,6 +190,12 @@ export default function FormVideoDetail() {
|
|||
satker: boolean;
|
||||
}>
|
||||
>([]);
|
||||
const [creatorLevelNumber, setCreatorLevelNumber] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const isContentFromSatker = creatorLevelNumber === 3;
|
||||
const isContentFromMabesOrPolda =
|
||||
creatorLevelNumber === 1 || creatorLevelNumber === 2;
|
||||
|
||||
useEffect(() => {
|
||||
if (Number(userLevelId) === 216 && Number(roleId) === 3) {
|
||||
|
|
@ -201,7 +207,7 @@ export default function FormVideoDetail() {
|
|||
const handleFileUnitChange = (
|
||||
fileIndex: number,
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
setFileUnitSelections((prev) => {
|
||||
const newSelections = [...prev];
|
||||
|
|
@ -221,7 +227,7 @@ export default function FormVideoDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[fileIndex] || new Set()
|
||||
newArray[fileIndex] || new Set(),
|
||||
);
|
||||
|
||||
if (value) {
|
||||
|
|
@ -252,12 +258,12 @@ export default function FormVideoDetail() {
|
|||
(item: any) =>
|
||||
item.levelNumber === 2 &&
|
||||
item.name !== "SATKER POLRI" &&
|
||||
currentFileCheckedLevels.has(Number(item.id))
|
||||
currentFileCheckedLevels.has(Number(item.id)),
|
||||
);
|
||||
|
||||
if (!hasSelectedPolda) {
|
||||
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
|
||||
}
|
||||
|
|
@ -296,7 +302,7 @@ export default function FormVideoDetail() {
|
|||
useEffect(() => {
|
||||
if (detail?.assignedToTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.assignedToTopLevel.split(",").map(Number)
|
||||
detail.assignedToTopLevel.split(",").map(Number),
|
||||
);
|
||||
setUnitSelection({
|
||||
semua: outputSet.has(0),
|
||||
|
|
@ -321,7 +327,7 @@ export default function FormVideoDetail() {
|
|||
acc[polda.id] = false;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
setExpandedPolda(initialExpandedState);
|
||||
console.log("polres", initialExpandedState);
|
||||
|
|
@ -356,7 +362,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
const handleUnitChange = (
|
||||
key: keyof typeof unitSelection,
|
||||
value: boolean
|
||||
value: boolean,
|
||||
) => {
|
||||
if (key === "semua") {
|
||||
const newState = {
|
||||
|
|
@ -435,7 +441,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
const handleCheckboxChange = (id: number) => {
|
||||
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") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -480,6 +486,10 @@ export default function FormVideoDetail() {
|
|||
console.log("detail", details);
|
||||
setFiles(details?.files);
|
||||
setDetail(details);
|
||||
if (details?.uploadedBy?.userLevel?.levelNumber) {
|
||||
setCreatorLevelNumber(details.uploadedBy.userLevel.levelNumber);
|
||||
}
|
||||
|
||||
setMain({
|
||||
type: details?.fileType.name,
|
||||
url: details?.files[0]?.url,
|
||||
|
|
@ -489,14 +499,14 @@ export default function FormVideoDetail() {
|
|||
|
||||
if (details?.assignedToLevel) {
|
||||
const levels = new Set(
|
||||
details.assignedToLevel.split(",").map(Number)
|
||||
details.assignedToLevel.split(",").map(Number),
|
||||
);
|
||||
setCheckedLevels(levels);
|
||||
}
|
||||
|
||||
if (details?.publishedForObject) {
|
||||
const publisherIds = details?.publishedForObject?.map(
|
||||
(obj: any) => obj.id
|
||||
(obj: any) => obj.id,
|
||||
);
|
||||
setSelectedPublishers(publisherIds);
|
||||
}
|
||||
|
|
@ -506,7 +516,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
const filesData = details?.files || [];
|
||||
const fileUrls = filesData.map((files: { url: string }) =>
|
||||
files.url ? files.url : "default-image.jpg"
|
||||
files.url ? files.url : "default-image.jpg",
|
||||
);
|
||||
setDetailVideo(fileUrls);
|
||||
|
||||
|
|
@ -684,7 +694,7 @@ export default function FormVideoDetail() {
|
|||
const setupPlacement = (
|
||||
index: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
let temp = [...filePlacements];
|
||||
if (checked) {
|
||||
|
|
@ -695,7 +705,7 @@ export default function FormVideoDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Checklist semua item di modal
|
||||
|
|
@ -745,7 +755,7 @@ export default function FormVideoDetail() {
|
|||
// Hanya auto-checklist "all" jika polda, polres, dan mabes ter-checklist
|
||||
// JANGAN include satker dalam perhitungan auto "all"
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length === 3 && !now.includes("all")) {
|
||||
now.push("all");
|
||||
|
|
@ -760,7 +770,7 @@ export default function FormVideoDetail() {
|
|||
setFileCheckedLevels((prevLevels) => {
|
||||
const newArray = [...prevLevels];
|
||||
const currentFileLevels = new Set<number>(
|
||||
newArray[index] || new Set()
|
||||
newArray[index] || new Set(),
|
||||
);
|
||||
|
||||
// Unchecklist semua item di modal
|
||||
|
|
@ -794,7 +804,7 @@ export default function FormVideoDetail() {
|
|||
// Hapus "all" jika tidak semua item ter-checklist
|
||||
if (now.includes("all")) {
|
||||
const nonSatkerItems = now.filter(
|
||||
(item) => item !== "satker" && item !== "all"
|
||||
(item) => item !== "satker" && item !== "all",
|
||||
);
|
||||
if (nonSatkerItems.length < 3) {
|
||||
const newData = now.filter((b) => b !== "all");
|
||||
|
|
@ -812,7 +822,7 @@ export default function FormVideoDetail() {
|
|||
const updateModalChecklistLevels = (
|
||||
fileIndex: number,
|
||||
placement: string,
|
||||
checked: boolean
|
||||
checked: boolean,
|
||||
) => {
|
||||
if (!listDest || listDest.length === 0) return;
|
||||
|
||||
|
|
@ -845,7 +855,7 @@ export default function FormVideoDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Checklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.add(Number(satkerItem.id));
|
||||
|
|
@ -881,7 +891,7 @@ export default function FormVideoDetail() {
|
|||
} else if (placement === "satker") {
|
||||
// Unchecklist SATKER POLRI dan semua sub-item di bawahnya
|
||||
const satkerItem: any = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
if (satkerItem) {
|
||||
currentFileLevels.delete(Number(satkerItem.id));
|
||||
|
|
@ -910,7 +920,7 @@ export default function FormVideoDetail() {
|
|||
type: string,
|
||||
url: string,
|
||||
names: string,
|
||||
format: string
|
||||
format: string,
|
||||
) => {
|
||||
console.log("Test 3 :", type, url, names, format);
|
||||
setMain({
|
||||
|
|
@ -951,7 +961,7 @@ export default function FormVideoDetail() {
|
|||
// Fungsi untuk mengupdate checklist levels untuk file tertentu
|
||||
const handleFileCheckboxChangePlacement = (
|
||||
fileIndex: number,
|
||||
levelId: number
|
||||
levelId: number,
|
||||
) => {
|
||||
setFileCheckedLevels((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
|
||||
const poldaItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (
|
||||
poldaItem &&
|
||||
|
|
@ -986,7 +996,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
// Jika ini adalah SATKER POLRI yang di-checklist, checklist juga semua sub-item di bawahnya
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => Number(item.id) === levelId
|
||||
(item: any) => Number(item.id) === levelId,
|
||||
) as any;
|
||||
if (satkerItem && satkerItem.name === "SATKER POLRI") {
|
||||
// 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)
|
||||
const totalPoldaCount = listDest.filter(
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI"
|
||||
(item: any) => item.levelNumber === 2 && item.name !== "SATKER POLRI",
|
||||
).length;
|
||||
|
||||
// Hitung berapa banyak POLDA yang ter-checklist (bukan SATKER POLRI)
|
||||
|
|
@ -1044,7 +1054,7 @@ export default function FormVideoDetail() {
|
|||
}
|
||||
return total;
|
||||
},
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
// Hitung berapa banyak POLRES yang ter-checklist
|
||||
|
|
@ -1054,7 +1064,7 @@ export default function FormVideoDetail() {
|
|||
return (
|
||||
total +
|
||||
item.subDestination.filter((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
@ -1063,7 +1073,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
// Cek apakah SATKER POLRI ter-checklist
|
||||
const satkerItem = listDest.find(
|
||||
(item: any) => item.name === "SATKER POLRI"
|
||||
(item: any) => item.name === "SATKER POLRI",
|
||||
);
|
||||
const isSatkerChecked =
|
||||
satkerItem && currentFileLevels.has(Number(satkerItem.id));
|
||||
|
|
@ -1097,7 +1107,7 @@ export default function FormVideoDetail() {
|
|||
|
||||
// Cek apakah semua sub-items sudah ter-checklist
|
||||
const allSubItemsChecked = polda.subDestination?.every((sub: any) =>
|
||||
currentFileLevels.has(Number(sub.id))
|
||||
currentFileLevels.has(Number(sub.id)),
|
||||
);
|
||||
|
||||
if (allSubItemsChecked) {
|
||||
|
|
@ -1180,7 +1190,7 @@ export default function FormVideoDetail() {
|
|||
{detail &&
|
||||
!categories.find(
|
||||
(cat) =>
|
||||
String(cat.id) === String(detail.category.id)
|
||||
String(cat.id) === String(detail.category.id),
|
||||
) && (
|
||||
<SelectItem
|
||||
key={String(detail.category.id)}
|
||||
|
|
@ -1465,7 +1475,7 @@ export default function FormVideoDetail() {
|
|||
Tingkat Distribusi:
|
||||
</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{/* {[
|
||||
{ key: "semua", label: "Semua" },
|
||||
{ key: "nasional", label: "Nasional" },
|
||||
{ key: "wilayah", label: "Wilayah" },
|
||||
|
|
@ -1473,6 +1483,39 @@ export default function FormVideoDetail() {
|
|||
key: "international",
|
||||
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) => (
|
||||
<div
|
||||
key={item.key}
|
||||
|
|
@ -1489,12 +1532,12 @@ export default function FormVideoDetail() {
|
|||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -1510,251 +1553,262 @@ export default function FormVideoDetail() {
|
|||
</div>
|
||||
|
||||
{/* Detail Wilayah */}
|
||||
{fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
{/* {fileUnitSelections[index]?.wilayah && ( */}
|
||||
{!isContentFromSatker &&
|
||||
fileUnitSelections[index]?.wilayah && (
|
||||
<div className="border-t border-gray-200 pt-2">
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">
|
||||
Detail Wilayah:
|
||||
</p>
|
||||
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
{[
|
||||
{ key: "polda", label: "POLDA" },
|
||||
{ key: "polres", label: "POLRES" },
|
||||
{ key: "satker", label: "SATKER" },
|
||||
].map((item, idx) => (
|
||||
<div
|
||||
key={item.key}
|
||||
className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
{item.label}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
<Checkbox
|
||||
id={`${item.key}-${index}`}
|
||||
checked={
|
||||
fileUnitSelections[index]?.[
|
||||
item.key as keyof typeof unitSelection
|
||||
] || false
|
||||
}
|
||||
onCheckedChange={(value) => {
|
||||
handleFileUnitChange(
|
||||
index,
|
||||
item.key as keyof typeof unitSelection,
|
||||
value as boolean,
|
||||
);
|
||||
setupPlacement(
|
||||
index,
|
||||
item.key,
|
||||
Boolean(value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`${item.key}-${index}`}
|
||||
className="text-sm font-medium cursor-pointer"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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>
|
||||
{item.label}
|
||||
</Label>
|
||||
</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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
)
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
polda
|
||||
)
|
||||
}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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>
|
||||
{/* Tombol Kustom sejajar dengan checkbox */}
|
||||
<div className="flex items-center justify-center p-3">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2"
|
||||
>
|
||||
<Icon
|
||||
icon="material-symbols:tune"
|
||||
width={16}
|
||||
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,
|
||||
);
|
||||
})()}
|
||||
</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={
|
||||
}}
|
||||
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 */}
|
||||
{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[
|
||||
index
|
||||
]?.has(
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
) || false
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleFileCheckboxChangePlacement(
|
||||
sub.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs h-6 px-2"
|
||||
onClick={() =>
|
||||
handleSelectAllSubItems(
|
||||
index,
|
||||
Number(
|
||||
sub.id
|
||||
)
|
||||
polda,
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="text-gray-700">
|
||||
{sub.name}
|
||||
</span>
|
||||
</Label>
|
||||
)
|
||||
)}
|
||||
>
|
||||
{allSubItemsChecked ? (
|
||||
<>
|
||||
<Icon
|
||||
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 className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end gap-3 border-t border-gray-200 pt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">
|
||||
{t("cancel", {
|
||||
defaultValue: "Batal",
|
||||
})}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button>
|
||||
{/* {t("save", {
|
||||
defaultValue: "Simpan",
|
||||
})} */}
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
Simpan
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -1833,7 +1887,7 @@ export default function FormVideoDetail() {
|
|||
>
|
||||
{template}
|
||||
</Button>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const CustomEditor = dynamic(
|
|||
() => {
|
||||
return import("@/components/editor/custom-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
interface FileWithPreview extends File {
|
||||
|
|
@ -111,11 +111,11 @@ export default function FormVideo() {
|
|||
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
||||
const [articleBody, setArticleBody] = useState<string>("");
|
||||
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||
const [publishedForError, setPublishedForError] = useState<string | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
const [selectedSize, setSelectedSize] = useState("");
|
||||
const [detailData, setDetailData] = useState<any>(null);
|
||||
|
|
@ -184,7 +184,7 @@ export default function FormVideo() {
|
|||
}
|
||||
|
||||
const filesWithPreview = acceptedFiles.map((file) =>
|
||||
Object.assign(file, { preview: URL.createObjectURL(file) })
|
||||
Object.assign(file, { preview: URL.createObjectURL(file) }),
|
||||
);
|
||||
|
||||
setFiles((prev) => {
|
||||
|
|
@ -211,11 +211,11 @@ export default function FormVideo() {
|
|||
.refine(
|
||||
(files) =>
|
||||
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(
|
||||
(files) => files.every((file: File) => file.size <= MAX_FILE_SIZE),
|
||||
{ message: "Ukuran file maksimal 100 MB" }
|
||||
{ message: "Ukuran file maksimal 100 MB" },
|
||||
),
|
||||
publishedFor: z
|
||||
.array(z.string())
|
||||
|
|
@ -423,7 +423,7 @@ export default function FormVideo() {
|
|||
const articleData = await waitForStatusUpdate();
|
||||
const cleanArticleBody = articleData?.articleBody?.replace(
|
||||
/<img[^>]*>/g,
|
||||
""
|
||||
"",
|
||||
);
|
||||
const articleImagesData = articleData?.imagesUrl?.split(",");
|
||||
setValue("description", cleanArticleBody || "");
|
||||
|
|
@ -479,7 +479,7 @@ export default function FormVideo() {
|
|||
|
||||
if (scheduleId && scheduleType === "3") {
|
||||
const findCategory = resCategory.find((o) =>
|
||||
o.name.toLowerCase().includes("pers rilis")
|
||||
o.name.toLowerCase().includes("pers rilis"),
|
||||
);
|
||||
|
||||
if (findCategory) {
|
||||
|
|
@ -502,7 +502,7 @@ export default function FormVideo() {
|
|||
setPublishedFor(
|
||||
options
|
||||
.filter((opt: any) => opt.id !== "all")
|
||||
.map((opt: any) => opt.id)
|
||||
.map((opt: any) => opt.id),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -561,8 +561,8 @@ export default function FormVideo() {
|
|||
translatedTitle && translatedTitle.trim() !== ""
|
||||
? translatedTitle
|
||||
: isSwitchOn
|
||||
? title
|
||||
: data.title;
|
||||
? title
|
||||
: data.title;
|
||||
|
||||
// Tentukan deskripsi final:
|
||||
// Jika ada hasil translate, kirim itu ke backend
|
||||
|
|
@ -570,10 +570,10 @@ export default function FormVideo() {
|
|||
translatedContent && translatedContent.trim() !== ""
|
||||
? translatedContent
|
||||
: isSwitchOn
|
||||
? data.description
|
||||
: selectedFileType === "rewrite"
|
||||
? data.rewriteDescription
|
||||
: data.descriptionOri;
|
||||
? data.description
|
||||
: selectedFileType === "rewrite"
|
||||
? data.rewriteDescription
|
||||
: data.descriptionOri;
|
||||
|
||||
if (!finalDescription?.trim()) {
|
||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||
|
|
@ -695,7 +695,7 @@ export default function FormVideo() {
|
|||
idx: number,
|
||||
id: string,
|
||||
file: any,
|
||||
duration: string
|
||||
duration: string,
|
||||
) {
|
||||
console.log(idx, id, file, duration);
|
||||
|
||||
|
|
@ -731,7 +731,7 @@ export default function FormVideo() {
|
|||
onChunkComplete: (
|
||||
chunkSize: any,
|
||||
bytesAccepted: any,
|
||||
bytesTotal: any
|
||||
bytesTotal: any,
|
||||
) => {
|
||||
const uploadPersen = Math.floor((bytesAccepted / bytesTotal) * 100);
|
||||
progressInfo[idx].percentage = uploadPersen;
|
||||
|
|
@ -791,8 +791,8 @@ export default function FormVideo() {
|
|||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
setThumbnail(file);
|
||||
setPreview(URL.createObjectURL(file));
|
||||
setThumbnail(file);
|
||||
setPreview(URL.createObjectURL(file));
|
||||
console.log("Selected Thumbnail:", file);
|
||||
}
|
||||
};
|
||||
|
|
@ -823,7 +823,7 @@ export default function FormVideo() {
|
|||
<div
|
||||
key={file.name}
|
||||
className=" flex justify-between border px-3.5 py-3 my-6 rounded-md"
|
||||
>
|
||||
>
|
||||
<div className="flex gap-3 items-center">
|
||||
{/* <div className="file-preview">{renderFilePreview(file)}</div> */}
|
||||
<svg
|
||||
|
|
@ -1732,7 +1732,7 @@ export default function FormVideo() {
|
|||
type="button"
|
||||
onClick={() => {
|
||||
const updatedTags = field.value.filter(
|
||||
(_, i) => i !== index
|
||||
(_, i) => i !== index,
|
||||
);
|
||||
field.onChange(updatedTags);
|
||||
}}
|
||||
|
|
@ -1825,7 +1825,7 @@ export default function FormVideo() {
|
|||
{/* <Button type="submit" color="primary">
|
||||
{t("submit", { defaultValue: "Submit" })}
|
||||
</Button> */}
|
||||
{levelNumber !== "2" && levelNumber !== "3" && (
|
||||
{levelNumber !== "2" && (
|
||||
<Button type="submit" color="primary">
|
||||
{t("submit", { defaultValue: "Submit" })}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export const GoogleMapsAPI = "AIzaSyCuQHorDceMCzlSgrB9AEY5ns8KeriFsME";
|
||||
// export const GoogleMapsAPI = "AIzaSyCuQHorDceMCzlSgrB9AEY5ns8KeriFsME";
|
||||
export const GoogleMapsAPI = "AIzaSyA-Dci9RP4ZjyJCFfy74WvhtMZXSDLTPMQ";
|
||||
|
|
|
|||
Loading…
Reference in New Issue