fix: schedule live rport

This commit is contained in:
Sabda Yagra 2026-01-22 12:16:28 +07:00
commit bc1fe9f9eb
12 changed files with 1456 additions and 543 deletions

View File

@ -89,7 +89,8 @@ const columns: ColumnDef<any>[] = [
cell: ({ row, table }) => { cell: ({ row, table }) => {
const original = row.original; const original = row.original;
const isValid = original.isValid; // const isValid = original.isValid;
const isRelevant = original.isRelevant;
const link = original.link; const link = original.link;
const updateRow = (data: Partial<any>) => { const updateRow = (data: Partial<any>) => {
@ -99,10 +100,10 @@ const columns: ColumnDef<any>[] = [
const handleValid = async () => { const handleValid = async () => {
try { try {
await validateMediaLink(original.id, true); await validateMediaLink(original.id, true);
updateRow({ updateRow({
isValid: true, isRelevant: true,
}); });
table.options.meta?.refetchData?.();
} catch (err: any) { } catch (err: any) {
toast.error(err.message); toast.error(err.message);
} }
@ -113,8 +114,9 @@ const columns: ColumnDef<any>[] = [
await validateMediaLink(original.id, false); await validateMediaLink(original.id, false);
updateRow({ updateRow({
isValid: false, isRelevant: false,
}); });
table.options.meta?.refetchData?.();
} catch (err: any) { } catch (err: any) {
toast.error(err.message); toast.error(err.message);
} }
@ -124,24 +126,55 @@ const columns: ColumnDef<any>[] = [
return <span className="text-muted-foreground">-</span>; return <span className="text-muted-foreground">-</span>;
} }
if (isValid === true) { if (isRelevant === true) {
return ( return (
<Button <Button
size="sm" size="sm"
className="bg-green-600 hover:bg-green-700" className="bg-green-600 hover:bg-green-700"
disabled disabled
> >
Valid Relevan
</Button> </Button>
); );
} }
return ( return (
<div className="flex gap-2"> <div className="flex gap-2">
<Button size="sm" variant="outline" onClick={handleValid}> <Button
size="sm"
variant="outline"
onClick={handleValid}
className="flex items-center"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M18.7 7.2c-.4-.4-1-.4-1.4 0l-7.5 7.5l-3.1-3.1c-.4-.4-1-.4-1.4 0s-.4 1 0 1.4l3.8 3.8c.2.2.4.3.7.3s.5-.1.7-.3l8.2-8.2c.4-.4.4-1 0-1.4"
/>
</svg>
Relevan Relevan
</Button> </Button>
<Button size="sm" variant="outline" onClick={handleInvalid}> <Button size="sm" variant="outline" onClick={handleInvalid} className="flex text-center items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M6.758 17.243L12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243"
/>
</svg>
Tidak Relevan Tidak Relevan
</Button> </Button>
</div> </div>

View File

@ -124,6 +124,9 @@ const NewsDetailTable = () => {
) )
); );
}, },
refetchData: () => {
fetchData();
},
}, },
state: { state: {
sorting, sorting,
@ -163,7 +166,7 @@ const NewsDetailTable = () => {
pageIndex: 0, pageIndex: 0,
pageSize: Number(showData), pageSize: Number(showData),
}); });
}, [page, showData]); }, [page, showData, id]);
async function fetchData() { async function fetchData() {
try { try {

View File

@ -52,32 +52,34 @@ const columns: ColumnDef<any>[] = [
header: "Judul", header: "Judul",
cell: ({ row }) => <span>{row.getValue("title")}</span>, cell: ({ row }) => <span>{row.getValue("title")}</span>,
}, },
// { {
// accessorKey: "resultTotal", accessorKey: "resultTotal",
// header: () => <div className="text-center w-full">Jumlah Amplifikasi</div>, header: () => <div className="text-center w-full">Total Artikel</div>,
// cell: ({ row }) => { cell: ({ row }) => {
// const value = row.getValue("resultTotal") as number | string | null; const value = row.getValue("resultTotal") as number | string | null;
// const finalValue = const finalValue =
// value === null || value === undefined || value === "" value === null || value === undefined || value === ""
// ? 0 ? 0
// : Number(value); : Number(value);
// return <div className="text-center w-full">{finalValue}</div>; return <div className="text-center w-full">{finalValue}</div>;
// }, },
// }, },
{ {
accessorKey: "amplification", accessorKey: "amplification",
header: () => <div className="text-center w-full">Jumlah Amplifikasi</div>, header: () => <div className="text-center w-full">Jumlah Amplifikasi</div>,
cell: ({ row }) => { cell: ({ row }) => {
const totalRaw = row.getValue("amplification") as number | string | null; const raw = row.getValue("amplification") as string | null;
const total = let total = 0;
totalRaw === null || totalRaw === undefined || totalRaw === "" let invalidTotal = 0;
? 0
: Number(totalRaw);
const invalidTotal = 0; if (raw && typeof raw === "string") {
const parts = raw.split("/").map((v) => v.trim());
total = Number(parts[0]) || 0;
invalidTotal = Number(parts[1]) || 0;
}
return ( return (
<div className="text-center w-full font-medium"> <div className="text-center w-full font-medium">

View File

@ -891,7 +891,6 @@ const EventModal = ({
const resCsrf = await getCsrfToken(); const resCsrf = await getCsrfToken();
const csrfToken = resCsrf?.data?.token; const csrfToken = resCsrf?.data?.token;
// console.log("CSRF TOKEN : ", csrfToken);
const headers = { const headers = {
"X-XSRF-TOKEN": csrfToken, "X-XSRF-TOKEN": csrfToken,
}; };

View File

@ -22,7 +22,7 @@ import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
const useTableColumns = (activeTab: "ta" | "daily" | "special") => { const useTableColumns = (activeTab: "ta" | "daily" | "special" |"mabes-koor") => {
const t = useTranslations("Table"); const t = useTranslations("Table");
const columns: ColumnDef<any>[] = [ const columns: ColumnDef<any>[] = [
{ {

View File

@ -75,6 +75,7 @@ interface Detail {
youtubeUrl: string; youtubeUrl: string;
needApprovalFrom: number; needApprovalFrom: number;
uploadedById: number; uploadedById: number;
statusId?: number;
} }
export default function FormDetailLiveReport() { export default function FormDetailLiveReport() {
@ -176,21 +177,68 @@ export default function FormDetailLiveReport() {
statusId: Number(status), statusId: Number(status),
message: description, message: description,
isPublish: status === "2", isPublish: status === "2",
placements: schedulePlacements?.filter((val) => val != "all")?.join(","), placements: schedulePlacements?.filter((val) => val !== "all")?.join(","),
}; };
loading(); loading();
const response = await postApprovalSchedule(data); const response = await postApprovalSchedule(data);
close(); close();
setModalOpen(false); setModalOpen(false);
if (response?.error) { if (response?.error) {
error(response?.message); error(response?.message || "Gagal menyimpan data");
return false; return;
} }
initState();
return false; // ✅ update UI lokal (optimistic)
setDetail((prev) =>
prev
? {
...prev,
statusId: Number(status),
}
: prev,
);
Swal.fire({
icon: "success",
title: "Berhasil",
text:
status === "2"
? "Jadwal berhasil disetujui"
: status === "3"
? "Jadwal dikembalikan untuk revisi"
: "Jadwal berhasil ditolak",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
router.push("/contributor/schedule/live-report");
}
});
} }
// async function save() {
// const data = {
// scheduleId: Number(id),
// statusId: Number(status),
// message: description,
// isPublish: status === "2",
// placements: schedulePlacements?.filter((val) => val != "all")?.join(","),
// };
// loading();
// const response = await postApprovalSchedule(data);
// close();
// setModalOpen(false);
// if (response?.error) {
// error(response?.message);
// return false;
// }
// initState();
// return false;
// }
const [schedulePlacements, setSchedulePlacements] = useState<string[]>([]); const [schedulePlacements, setSchedulePlacements] = useState<string[]>([]);
const setupPlacement = (placement: string, checked: boolean) => { const setupPlacement = (placement: string, checked: boolean) => {
@ -224,6 +272,15 @@ export default function FormDetailLiveReport() {
setSchedulePlacements(temp); setSchedulePlacements(temp);
}; };
const isCreator = Number(detail?.uploadedById) === Number(userId);
const isApprover =
Number(detail?.needApprovalFrom) === Number(userLevelId) &&
Number(userLevelNumber) < 2;
const isAlreadyProcessed =
detail?.statusId === 2 || detail?.statusId === 3 || detail?.statusId === 4;
return ( return (
<div className="flex flex-col lg:flex-row gap-2"> <div className="flex flex-col lg:flex-row gap-2">
<Card className="w-full lg:w-9/12"> <Card className="w-full lg:w-9/12">
@ -284,7 +341,7 @@ export default function FormDetailLiveReport() {
variant={"outline"} variant={"outline"}
className={cn( className={cn(
"w-[280px] lg:w-[250px] justify-start text-left font-normal px-0 md:px-0 lg:px-4", "w-[280px] lg:w-[250px] justify-start text-left font-normal px-0 md:px-0 lg:px-4",
!date && "text-muted-foreground" !date && "text-muted-foreground",
)} )}
> >
<CalendarIcon size={15} className="mr-3" /> <CalendarIcon size={15} className="mr-3" />
@ -494,7 +551,38 @@ export default function FormDetailLiveReport() {
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>
{Number(detail?.needApprovalFrom) == Number(userLevelId) && {(isApprover || isCreator) && !isAlreadyProcessed && (
<div className="flex flex-col gap-2 p-3">
<Button
onClick={() => actionApproval("2")}
color="primary"
type="button"
>
<Icon icon="fa:check" className="mr-3" />
{t("accept", { defaultValue: "Accept" })}
</Button>
<Button
onClick={() => actionApproval("3")}
className="bg-orange-400 hover:bg-orange-300"
type="button"
>
<Icon icon="fa:comment-o" className="mr-3" />
{t("revision", { defaultValue: "Revision" })}
</Button>
<Button
onClick={() => actionApproval("4")}
color="destructive"
type="button"
>
<Icon icon="fa:times" className="mr-3" />
{t("reject", { defaultValue: "Reject" })}
</Button>
</div>
)}
{/* {Number(detail?.needApprovalFrom) == Number(userLevelId) &&
Number(userLevelNumber) < 2 ? ( Number(userLevelNumber) < 2 ? (
Number(detail?.uploadedById) == Number(userId) ? ( Number(detail?.uploadedById) == Number(userId) ? (
"" ""
@ -527,13 +615,15 @@ export default function FormDetailLiveReport() {
) )
) : ( ) : (
"" ""
)} )} */}
</Card> </Card>
<Dialog open={modalOpen} onOpenChange={setModalOpen}> <Dialog open={modalOpen} onOpenChange={setModalOpen}>
<DialogContent className="overflow-y-auto"> <DialogContent className="overflow-y-auto">
<DialogHeader> <DialogHeader>
<DialogTitle>{t("leave-comment", { defaultValue: "Leave Comment" })}</DialogTitle> <DialogTitle>
{t("leave-comment", { defaultValue: "Leave Comment" })}
</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="flex flex-col gap-1 text-sm"> <div className="flex flex-col gap-1 text-sm">
<p> <p>
@ -544,15 +634,15 @@ export default function FormDetailLiveReport() {
status === "2" status === "2"
? "text-primary" ? "text-primary"
: status === "3" : status === "3"
? "text-warning" ? "text-warning"
: "text-destructive" : "text-destructive"
} }
> >
{status === "2" {status === "2"
? "Disetujui" ? "Disetujui"
: status === "3" : status === "3"
? "Revisi" ? "Revisi"
: "Ditolak"} : "Ditolak"}
</span> </span>
</p> </p>
{status === "2" && ( {status === "2" && (

View File

@ -43,7 +43,7 @@ import { getCsrfToken } from "@/service/auth";
import { loading } from "@/lib/swal"; import { loading } from "@/lib/swal";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { cn } from "@/lib/utils"; import { cn, getCookiesDecrypt } from "@/lib/utils";
import { import {
Popover, Popover,
PopoverContent, PopoverContent,
@ -181,6 +181,33 @@ export default function FormTaskTa() {
mode: "all", mode: "all",
}); });
const [profile, setProfile] = useState<any>(null);
const userLevelId = Number(getCookiesDecrypt("ulie"));
const roleId = Number(getCookiesDecrypt("urie"));
const userId = Number(getCookiesDecrypt("uie"));
const MABES_LEVEL_ID = 216; // userLevelId Mabes Polri
const APPROVER_ROLE_ID = 3; // roleId Approver
const isMabes = userLevelId === MABES_LEVEL_ID;
const isApprover = roleId === APPROVER_ROLE_ID;
const isMabesApprover =
userLevelId === MABES_LEVEL_ID && roleId === APPROVER_ROLE_ID;
const shouldHideExpert = isMabes && isApprover;
useEffect(() => {
async function fetchUserLevel() {
try {
const res = await getUserLevelForAssignments();
setProfile(res?.data?.data);
} catch (e) {
console.error("Failed fetch user level", e);
}
}
fetchUserLevel();
}, []);
useEffect(() => { useEffect(() => {
getDataAdditional(); getDataAdditional();
}, []); }, []);
@ -352,55 +379,124 @@ export default function FormTaskTa() {
// // }); // // });
// }; // };
// const save = async (data: TaskSchema) => {
// const cleanedLinks = links
// .map((link) => link.trim())
// .filter((link) => link.startsWith("http"));
// const requestData = {
// ...data,
// // assignedToUsers: handleExpertChange(),
// assignedToUsers: isMabesApprover ? "464" : handleExpertChange(),
// assignmentType: taskType,
// assignmentTypeId: type,
// expertCompetencies: Array.from(selectedCompetencies).join(","),
// attachmentUrl: cleanedLinks,
// };
// console.log("FINAL ASSIGNED TO:", {
// isMabesApprover,
// assignedToUsers: isMabesApprover
// ? String(roleId)
// : handleExpertChange(),
// });
// const response = await createTaskTa(requestData);
// const id = String(response?.data?.data.id);
// // Set block table TA
// localStorage.setItem("TA_UPLOAD_IN_PROGRESS", "true");
// loading(); // SHOW SWAL LOADING
// // Kumpulkan semua upload
// const allUploads: Promise<any>[] = [];
// imageFiles.forEach((item, idx) =>
// allUploads.push(uploadResumableFile(idx, id, item, "1", "0"))
// );
// videoFiles.forEach((item, idx) =>
// allUploads.push(uploadResumableFile(idx, id, item, "2", "0"))
// );
// textFiles.forEach((item, idx) =>
// allUploads.push(uploadResumableFile(idx, id, item, "3", "0"))
// );
// audioFiles.forEach((item, idx) =>
// allUploads.push(uploadResumableFile(idx, id, item, "4", "0"))
// );
// // Tunggu upload selesai
// await Promise.all(allUploads);
// // Hapus flag
// localStorage.removeItem("TA_UPLOAD_IN_PROGRESS");
// // Close loading + redirect
// successSubmit("/in/contributor/task-ta");
// };
const save = async (data: TaskSchema) => { const save = async (data: TaskSchema) => {
const cleanedLinks = links try {
.map((link) => link.trim()) loading();
.filter((link) => link.startsWith("http"));
const requestData = { const cleanedLinks = links
...data, .map((link) => link.trim())
assignedToUsers: handleExpertChange(), .filter((link) => link.startsWith("http"));
assignmentType: taskType,
assignmentTypeId: type,
expertCompetencies: Array.from(selectedCompetencies).join(","),
attachmentUrl: cleanedLinks,
};
const response = await createTaskTa(requestData); const requestData = {
const id = String(response?.data?.data.id); ...data,
// assignedToUsers: isMabesApprover ? "464" : handleExpertChange(),
assignedToUsers: isMabesApprover ? "464" : handleExpertChange(),
assignmentType: taskType,
assignmentTypeId: type,
expertCompetencies: Array.from(selectedCompetencies).join(","),
attachmentUrl: cleanedLinks,
};
// Set block table TA const response = await createTaskTa(requestData);
localStorage.setItem("TA_UPLOAD_IN_PROGRESS", "true");
loading(); // SHOW SWAL LOADING if (!response?.data?.data?.id) {
throw new Error("Gagal membuat task");
}
// Kumpulkan semua upload const assignmentId = String(response.data.data.id);
const allUploads: Promise<any>[] = [];
imageFiles.forEach((item, idx) => const uploads: Promise<any>[] = [];
allUploads.push(uploadResumableFile(idx, id, item, "1", "0"))
);
videoFiles.forEach((item, idx) => imageFiles.forEach((file, i) =>
allUploads.push(uploadResumableFile(idx, id, item, "2", "0")) uploads.push(uploadResumableFile(i, assignmentId, file, "1", "0"))
); );
textFiles.forEach((item, idx) => videoFiles.forEach((file, i) =>
allUploads.push(uploadResumableFile(idx, id, item, "3", "0")) uploads.push(uploadResumableFile(i, assignmentId, file, "2", "0"))
); );
audioFiles.forEach((item, idx) => textFiles.forEach((file, i) =>
allUploads.push(uploadResumableFile(idx, id, item, "4", "0")) uploads.push(uploadResumableFile(i, assignmentId, file, "3", "0"))
); );
// Tunggu upload selesai audioFiles.forEach((file, i) =>
await Promise.all(allUploads); uploads.push(uploadResumableFile(i, assignmentId, file, "4", "0"))
);
// Hapus flag await Promise.all(uploads);
localStorage.removeItem("TA_UPLOAD_IN_PROGRESS");
// Close loading + redirect successSubmit("/in/contributor/task-ta");
successSubmit("/in/contributor/task-ta"); } catch (err: any) {
console.error("SUBMIT ERROR:", err);
Swal.fire({
icon: "error",
title: "Gagal",
text:
err?.response?.data?.message ||
err?.message ||
"Terjadi kesalahan, data tidak tersimpan",
});
}
}; };
const onSubmit = (data: TaskSchema) => { const onSubmit = (data: TaskSchema) => {
@ -543,46 +639,91 @@ export default function FormTaskTa() {
// upload.start(); // upload.start();
// } // }
// function uploadResumableFile(
// idx: number,
// id: string,
// file: any,
// fileTypeId: string,
// duration: string
// ) {
// return new Promise(async (resolve, reject) => {
// const resCsrf = await getCsrfToken();
// const csrfToken = resCsrf?.data?.token;
// const upload = new Upload(file, {
// endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`,
// headers: { "X-XSRF-TOKEN": csrfToken },
// retryDelays: [0, 3000, 6000, 12000],
// chunkSize: 20000,
// metadata: {
// assignmentId: id,
// filename: file.name,
// contentType: file.type,
// fileTypeId,
// duration,
// },
// onBeforeRequest(req) {
// req.getUnderlyingObject().withCredentials = true;
// },
// onError(err) {
// console.error("Upload error:", err);
// reject(err);
// },
// onSuccess() {
// console.log("Upload selesai:", file.name);
// resolve(true);
// },
// });
// upload.start();
// });
// }
function uploadResumableFile( function uploadResumableFile(
idx: number, idx: number,
id: string, id: string,
file: any, file: File,
fileTypeId: string, fileTypeId: string,
duration: string duration: string
) { ) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const resCsrf = await getCsrfToken(); try {
const csrfToken = resCsrf?.data?.token; const resCsrf = await getCsrfToken();
const csrfToken = resCsrf?.data?.token;
const upload = new Upload(file, { const upload = new Upload(file, {
endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`, endpoint: `${process.env.NEXT_PUBLIC_API}/assignment-expert/file/upload`,
headers: { "X-XSRF-TOKEN": csrfToken }, headers: { "X-XSRF-TOKEN": csrfToken },
retryDelays: [0, 3000, 6000, 12000], retryDelays: [0, 3000, 6000],
chunkSize: 20000, chunkSize: 20000,
metadata: { metadata: {
assignmentId: id, assignmentId: id,
filename: file.name, filename: file.name,
contentType: file.type, contentType: file.type,
fileTypeId, fileTypeId,
duration, duration,
}, },
onBeforeRequest(req) { onBeforeRequest(req) {
req.getUnderlyingObject().withCredentials = true; req.getUnderlyingObject().withCredentials = true;
}, },
onError(err) { onError(error) {
console.error("Upload error:", err); reject(error);
reject(err); },
},
onSuccess() { onSuccess() {
console.log("Upload selesai:", file.name); resolve(true);
resolve(true); },
}, });
});
upload.start(); upload.start();
} catch (err) {
reject(err);
}
}); });
} }
@ -718,101 +859,109 @@ export default function FormTaskTa() {
</PopoverContent> </PopoverContent>
</Popover> </Popover>
</div> </div>
<div className="mt-5 space-y-2"> {!isMabesApprover && (
<Label> <div className="mt-5 space-y-2">
{t("areas-expertise", { defaultValue: "Areas Expertise" })} <Label>
</Label> {t("areas-expertise", { defaultValue: "Areas Expertise" })}
<div className="flex flex-wrap gap-4"> </Label>
{userCompetencies?.map((item: any) => ( <div className="flex flex-wrap gap-4">
<div className="flex items-center gap-2" key={item.id}> {userCompetencies?.map((item: any) => (
<Checkbox <div className="flex items-center gap-2" key={item.id}>
id={`comp-${item.id}`} <Checkbox
checked={selectedCompetencies.has(item.id)} id={`comp-${item.id}`}
onCheckedChange={() => handleCompetencyChange(item.id)} checked={selectedCompetencies.has(item.id)}
/> onCheckedChange={() => handleCompetencyChange(item.id)}
<Label htmlFor={`comp-${item.id}`}>{item.name}</Label> />
</div> <Label htmlFor={`comp-${item.id}`}>{item.name}</Label>
))}
</div>
</div>
<div className="mt-5 space-y-2">
<Label>
{t("choose-expert", { defaultValue: "Choose Expert" })}
</Label>
<div className="flex flex-wrap gap-4">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[{"Pilih Tenaga Ahli"}]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>Daftar Tenaga Ahli</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listExpert?.map((expert: any) => (
<div key={expert.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(expert.id)}
onCheckedChange={() =>
handleCheckboxChange(expert.id)
}
className="mr-3"
/>
<div className="flex flex-col gap-2">
<div className="font-bold">{expert.fullname}</div>
<div className="italic">({expert.username})</div>
</div>
</Label>
</div>
))}
</div> </div>
</DialogContent> ))}
</Dialog>
</div>
{checkedLevels.size > 0 && (
<div className="mt-3">
<Label className="text-sm text-gray-600 mb-2 block">
Tenaga Ahli Terpilih ({checkedLevels.size})
</Label>
<div className="flex flex-wrap gap-2">
{Array.from(checkedLevels).map((expertId) => {
const expert = listExpert?.find(
(exp: any) => exp.id === expertId
);
return expert ? (
<div
key={expert.id}
className="inline-flex items-center gap-2 bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1.5 rounded-full border border-blue-200"
>
<span>{expert.fullname}</span>
<button
type="button"
onClick={() => handleCheckboxChange(expert.id)}
className="ml-1 text-blue-600 hover:text-blue-800 hover:bg-blue-200 rounded-full p-0.5 transition-colors"
title="Remove expert"
>
<svg
className="w-3 h-3"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
</div>
) : null;
})}
</div>
</div> </div>
)} </div>
</div> )}
{!isMabesApprover && (
<div className="mt-5 space-y-2">
<Label>
{t("choose-expert", { defaultValue: "Choose Expert" })}
</Label>
<div className="flex flex-wrap gap-4">
<Dialog>
<DialogTrigger asChild>
<Button variant="soft" size="sm" color="primary">
[{"Pilih Tenaga Ahli"}]
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px] md:max-w-[500px] lg:max-w-[1500px]">
<DialogHeader>
<DialogTitle>Daftar Tenaga Ahli</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
{listExpert?.map((expert: any) => (
<div key={expert.id} className="border p-2">
<Label className="flex items-center">
<Checkbox
checked={checkedLevels.has(expert.id)}
onCheckedChange={() =>
handleCheckboxChange(expert.id)
}
className="mr-3"
/>
<div className="flex flex-col gap-2">
<div className="font-bold">
{expert.fullname}
</div>
<div className="italic">
({expert.username})
</div>
</div>
</Label>
</div>
))}
</div>
</DialogContent>
</Dialog>
</div>
{checkedLevels.size > 0 && (
<div className="mt-3">
<Label className="text-sm text-gray-600 mb-2 block">
Tenaga Ahli Terpilih ({checkedLevels.size})
</Label>
<div className="flex flex-wrap gap-2">
{Array.from(checkedLevels).map((expertId) => {
const expert = listExpert?.find(
(exp: any) => exp.id === expertId
);
return expert ? (
<div
key={expert.id}
className="inline-flex items-center gap-2 bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1.5 rounded-full border border-blue-200"
>
<span>{expert.fullname}</span>
<button
type="button"
onClick={() => handleCheckboxChange(expert.id)}
className="ml-1 text-blue-600 hover:text-blue-800 hover:bg-blue-200 rounded-full p-0.5 transition-colors"
title="Remove expert"
>
<svg
className="w-3 h-3"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
</div>
) : null;
})}
</div>
</div>
)}
</div>
)}
<div className="mt-5 space-y-2"> <div className="mt-5 space-y-2">
<Label>{t("description", { defaultValue: "Description" })}</Label> <Label>{t("description", { defaultValue: "Description" })}</Label>
<Controller <Controller
@ -946,7 +1095,9 @@ export default function FormTaskTa() {
<Input <Input
type="url" type="url"
className="border rounded p-2 w-full" className="border rounded p-2 w-full"
placeholder={`Masukkan link berita ${index + 1}`} placeholder={`Masukkan link berita ${
index + 1
} | Contoh: https://www.detik.com`}
value={link} value={link}
onChange={(e) => onChange={(e) =>
handleLinkChange(index, e.target.value) handleLinkChange(index, e.target.value)

View File

@ -168,6 +168,13 @@ export function getMenuList(pathname: string, t: any): Group[] {
icon: "heroicons:shopping-cart", icon: "heroicons:shopping-cart",
children: [], children: [],
}, },
{
href: "/contributor/task-ta",
label: "penugasan TA",
active: pathname.includes("/contributor/task-ta"),
icon: "heroicons:shopping-cart",
children: [],
},
], ],
}, },
], ],

View File

@ -10,7 +10,7 @@ importers:
dependencies: dependencies:
'@ckeditor/ckeditor5-react': '@ckeditor/ckeditor5-react':
specifier: ^6.2.0 specifier: ^6.2.0
version: 6.3.0(@ckeditor/ckeditor5-core@46.0.0)(@ckeditor/ckeditor5-editor-multi-root@46.0.0)(@ckeditor/ckeditor5-engine@46.0.0)(@ckeditor/ckeditor5-utils@46.0.0)(@ckeditor/ckeditor5-watchdog@46.0.0)(react@18.3.1) version: 6.3.0(@ckeditor/ckeditor5-core@47.1.0)(@ckeditor/ckeditor5-editor-multi-root@47.1.0)(@ckeditor/ckeditor5-engine@47.1.0)(@ckeditor/ckeditor5-utils@47.1.0)(@ckeditor/ckeditor5-watchdog@47.1.0)(react@18.3.1)
'@dnd-kit/core': '@dnd-kit/core':
specifier: ^6.1.0 specifier: ^6.1.0
version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -223,7 +223,10 @@ importers:
version: 8.5.1(embla-carousel@8.5.1) version: 8.5.1(embla-carousel@8.5.1)
embla-carousel-react: embla-carousel-react:
specifier: ^8.1.3 specifier: ^8.1.3
version: 8.5.1(react@18.3.1) version: 8.6.0(react@18.3.1)
file-saver:
specifier: ^2.0.5
version: 2.0.5
framer-motion: framer-motion:
specifier: ^11.15.0 specifier: ^11.15.0
version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -394,7 +397,10 @@ importers:
version: 0.9.9(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 0.9.9(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
wavesurfer.js: wavesurfer.js:
specifier: ^7.8.16 specifier: ^7.8.16
version: 7.8.16 version: 7.11.0
xlsx:
specifier: ^0.18.5
version: 0.18.5
yup: yup:
specifier: ^1.6.1 specifier: ^1.6.1
version: 1.6.1 version: 1.6.1
@ -3061,8 +3067,12 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
agent-base@7.1.3: adler-32@1.3.1:
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
engines: {node: '>=0.8'}
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
ajv@6.12.6: ajv@6.12.6:
@ -3336,6 +3346,10 @@ packages:
ccount@2.0.1: ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
cfb@1.2.2:
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
engines: {node: '>=0.8'}
chalk@2.3.0: chalk@2.3.0:
resolution: {integrity: sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==} resolution: {integrity: sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3447,8 +3461,12 @@ packages:
code-block-writer@12.0.0: code-block-writer@12.0.0:
resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==}
collect-v8-coverage@1.0.2: codepage@1.15.0:
resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
engines: {node: '>=0.8'}
collect-v8-coverage@1.0.3:
resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==}
color-convert@1.9.3: color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@ -3548,6 +3566,11 @@ packages:
typescript: typescript:
optional: true optional: true
crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
hasBin: true
cross-env@7.0.3: cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
@ -4223,6 +4246,9 @@ packages:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0} engines: {node: ^10.12.0 || >=12.0.0}
file-saver@2.0.5:
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
file-selector@2.1.2: file-selector@2.1.2:
resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==}
engines: {node: '>= 12'} engines: {node: '>= 12'}
@ -4283,8 +4309,16 @@ packages:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'} engines: {node: '>=12.20.0'}
framer-motion@11.15.0: forwarded@0.2.0:
resolution: {integrity: sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==} resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
frac@1.1.2:
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
engines: {node: '>=0.8'}
framer-motion@11.18.2:
resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==}
peerDependencies: peerDependencies:
'@emotion/is-prop-valid': '*' '@emotion/is-prop-valid': '*'
react: ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0
@ -6707,8 +6741,12 @@ packages:
sprintf-js@1.0.3: sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
stable-hash@0.0.4: ssf@0.11.2:
resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
engines: {node: '>=0.8'}
stable-hash@0.0.5:
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
stack-utils@2.0.6: stack-utils@2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
@ -7330,10 +7368,22 @@ packages:
engines: {node: '>= 8'} engines: {node: '>= 8'}
hasBin: true hasBin: true
wmf@1.0.2:
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
engines: {node: '>=0.8'}
word-wrap@1.2.5: word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
word@0.3.0:
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
engines: {node: '>=0.8'}
wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
wrap-ansi@7.0.0: wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -7373,6 +7423,11 @@ packages:
utf-8-validate: utf-8-validate:
optional: true optional: true
xlsx@0.18.5:
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
engines: {node: '>=0.8'}
hasBin: true
xml-name-validator@5.0.0: xml-name-validator@5.0.0:
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -7855,9 +7910,9 @@ snapshots:
'@ckeditor/ckeditor5-adapter-ckfinder@46.0.0': '@ckeditor/ckeditor5-adapter-ckfinder@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-upload': 46.0.0 '@ckeditor/ckeditor5-upload': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
'@ckeditor/ckeditor5-alignment@41.3.1': '@ckeditor/ckeditor5-alignment@41.3.1':
dependencies: dependencies:
@ -7918,15 +7973,13 @@ snapshots:
'@ckeditor/ckeditor5-block-quote@46.0.0': '@ckeditor/ckeditor5-block-quote@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-enter': 46.0.0 '@ckeditor/ckeditor5-enter': 47.1.0
'@ckeditor/ckeditor5-icons': 46.0.0 '@ckeditor/ckeditor5-icons': 47.1.0
'@ckeditor/ckeditor5-typing': 46.0.0 '@ckeditor/ckeditor5-typing': 47.1.0
'@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-bookmark@46.0.0': '@ckeditor/ckeditor5-bookmark@46.0.0':
dependencies: dependencies:
@ -7991,11 +8044,9 @@ snapshots:
'@ckeditor/ckeditor5-cloud-services@46.0.0': '@ckeditor/ckeditor5-cloud-services@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-code-block@41.3.1': '@ckeditor/ckeditor5-code-block@41.3.1':
dependencies: dependencies:
@ -8062,8 +8113,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0
ckeditor5: 46.0.0 ckeditor5: 46.0.0
es-toolkit: 1.39.5 es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-editor-decoupled@46.0.0': '@ckeditor/ckeditor5-editor-decoupled@46.0.0':
dependencies: dependencies:
@ -8091,18 +8140,36 @@ snapshots:
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0
ckeditor5: 46.0.0 ckeditor5: 46.0.0
es-toolkit: 1.39.5 es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-emoji@46.0.0': '@ckeditor/ckeditor5-emoji@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-icons': 46.0.0 '@ckeditor/ckeditor5-engine': 47.1.0
'@ckeditor/ckeditor5-mention': 46.0.0 '@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-typing': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
'@ckeditor/ckeditor5-ui': 46.0.0 ckeditor5: 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 es-toolkit: 1.39.5
ckeditor5: 46.0.0
'@ckeditor/ckeditor5-editor-multi-root@47.1.0':
dependencies:
'@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-engine': 47.1.0
'@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 47.1.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-emoji@47.1.0':
dependencies:
'@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-icons': 47.1.0
'@ckeditor/ckeditor5-mention': 47.1.0
'@ckeditor/ckeditor5-typing': 47.1.0
'@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 47.1.0
es-toolkit: 1.39.5 es-toolkit: 1.39.5
fuzzysort: 3.1.0 fuzzysort: 3.1.0
transitivePeerDependencies: transitivePeerDependencies:
@ -8369,18 +8436,16 @@ snapshots:
'@ckeditor/ckeditor5-media-embed@46.0.0': '@ckeditor/ckeditor5-media-embed@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-clipboard': 46.0.0 '@ckeditor/ckeditor5-clipboard': 47.1.0
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-engine': 46.0.0 '@ckeditor/ckeditor5-engine': 47.1.0
'@ckeditor/ckeditor5-icons': 46.0.0 '@ckeditor/ckeditor5-icons': 47.1.0
'@ckeditor/ckeditor5-typing': 46.0.0 '@ckeditor/ckeditor5-typing': 47.1.0
'@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-undo': 46.0.0 '@ckeditor/ckeditor5-undo': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
'@ckeditor/ckeditor5-widget': 46.0.0 '@ckeditor/ckeditor5-widget': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-mention@46.0.0': '@ckeditor/ckeditor5-mention@46.0.0':
dependencies: dependencies:
@ -8439,25 +8504,23 @@ snapshots:
'@ckeditor/ckeditor5-engine': 46.0.0 '@ckeditor/ckeditor5-engine': 46.0.0
ckeditor5: 46.0.0 ckeditor5: 46.0.0
'@ckeditor/ckeditor5-react@6.3.0(@ckeditor/ckeditor5-core@46.0.0)(@ckeditor/ckeditor5-editor-multi-root@46.0.0)(@ckeditor/ckeditor5-engine@46.0.0)(@ckeditor/ckeditor5-utils@46.0.0)(@ckeditor/ckeditor5-watchdog@46.0.0)(react@18.3.1)': '@ckeditor/ckeditor5-react@6.3.0(@ckeditor/ckeditor5-core@47.1.0)(@ckeditor/ckeditor5-editor-multi-root@47.1.0)(@ckeditor/ckeditor5-engine@47.1.0)(@ckeditor/ckeditor5-utils@47.1.0)(@ckeditor/ckeditor5-watchdog@47.1.0)(react@18.3.1)':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-editor-multi-root': 46.0.0 '@ckeditor/ckeditor5-editor-multi-root': 47.1.0
'@ckeditor/ckeditor5-engine': 46.0.0 '@ckeditor/ckeditor5-engine': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
'@ckeditor/ckeditor5-watchdog': 46.0.0 '@ckeditor/ckeditor5-watchdog': 47.1.0
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
'@ckeditor/ckeditor5-remove-format@46.0.0': '@ckeditor/ckeditor5-remove-format@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-icons': 46.0.0 '@ckeditor/ckeditor5-icons': 47.1.0
'@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-restricted-editing@46.0.0': '@ckeditor/ckeditor5-restricted-editing@46.0.0':
dependencies: dependencies:
@ -8499,12 +8562,12 @@ snapshots:
'@ckeditor/ckeditor5-source-editing@46.0.0': '@ckeditor/ckeditor5-source-editing@46.0.0':
dependencies: dependencies:
'@ckeditor/ckeditor5-core': 46.0.0 '@ckeditor/ckeditor5-core': 47.1.0
'@ckeditor/ckeditor5-icons': 46.0.0 '@ckeditor/ckeditor5-icons': 47.1.0
'@ckeditor/ckeditor5-theme-lark': 46.0.0 '@ckeditor/ckeditor5-theme-lark': 47.1.0
'@ckeditor/ckeditor5-ui': 46.0.0 '@ckeditor/ckeditor5-ui': 47.1.0
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 47.1.0
ckeditor5: 46.0.0 ckeditor5: 47.1.0
'@ckeditor/ckeditor5-special-characters@46.0.0': '@ckeditor/ckeditor5-special-characters@46.0.0':
dependencies: dependencies:
@ -8671,8 +8734,6 @@ snapshots:
'@ckeditor/ckeditor5-utils': 46.0.0 '@ckeditor/ckeditor5-utils': 46.0.0
ckeditor5: 46.0.0 ckeditor5: 46.0.0
es-toolkit: 1.39.5 es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@csstools/color-helpers@5.0.2': {} '@csstools/color-helpers@5.0.2': {}
@ -10730,7 +10791,9 @@ snapshots:
acorn@8.14.0: {} acorn@8.14.0: {}
agent-base@7.1.3: {} adler-32@1.3.1: {}
agent-base@7.1.4: {}
ajv@6.12.6: ajv@6.12.6:
dependencies: dependencies:
@ -11054,6 +11117,11 @@ snapshots:
ccount@2.0.1: {} ccount@2.0.1: {}
cfb@1.2.2:
dependencies:
adler-32: 1.3.1
crc-32: 1.2.2
chalk@2.3.0: chalk@2.3.0:
dependencies: dependencies:
ansi-styles: 3.2.1 ansi-styles: 3.2.1
@ -11260,7 +11328,9 @@ snapshots:
code-block-writer@12.0.0: {} code-block-writer@12.0.0: {}
collect-v8-coverage@1.0.2: {} codepage@1.15.0: {}
collect-v8-coverage@1.0.3: {}
color-convert@1.9.3: color-convert@1.9.3:
dependencies: dependencies:
@ -11353,6 +11423,8 @@ snapshots:
optionalDependencies: optionalDependencies:
typescript: 5.7.2 typescript: 5.7.2
crc-32@1.2.2: {}
cross-env@7.0.3: cross-env@7.0.3:
dependencies: dependencies:
cross-spawn: 7.0.6 cross-spawn: 7.0.6
@ -11884,8 +11956,8 @@ snapshots:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/parser': 7.2.0(eslint@8.57.1)(typescript@5.7.2)
eslint: 8.57.1 eslint: 8.57.1
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.3(eslint@8.57.1) eslint-plugin-react: 7.37.3(eslint@8.57.1)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1)
@ -11916,7 +11988,7 @@ snapshots:
is-glob: 4.0.3 is-glob: 4.0.3
stable-hash: 0.0.4 stable-hash: 0.0.4
optionalDependencies: optionalDependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -11931,7 +12003,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
dependencies: dependencies:
'@rtsao/scc': 1.1.0 '@rtsao/scc': 1.1.0
array-includes: 3.1.8 array-includes: 3.1.8
@ -12198,6 +12270,8 @@ snapshots:
dependencies: dependencies:
flat-cache: 3.2.0 flat-cache: 3.2.0
file-saver@2.0.5: {}
file-selector@2.1.2: file-selector@2.1.2:
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@ -12253,7 +12327,11 @@ snapshots:
dependencies: dependencies:
fetch-blob: 3.2.0 fetch-blob: 3.2.0
framer-motion@11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): forwarded@0.2.0: {}
frac@1.1.2: {}
framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
motion-dom: 11.14.3 motion-dom: 11.14.3
motion-utils: 11.14.3 motion-utils: 11.14.3
@ -15619,7 +15697,15 @@ snapshots:
sprintf-js@1.0.3: {} sprintf-js@1.0.3: {}
<<<<<<< HEAD
stable-hash@0.0.4: {} stable-hash@0.0.4: {}
=======
ssf@0.11.2:
dependencies:
frac: 1.1.2
stable-hash@0.0.5: {}
>>>>>>> e5e32496aba520aed62e3a73e9e0bcc42eaca928
stack-utils@2.0.6: stack-utils@2.0.6:
dependencies: dependencies:
@ -16398,8 +16484,21 @@ snapshots:
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0
wmf@1.0.2: {}
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
<<<<<<< HEAD
=======
word@0.3.0: {}
wrap-ansi@6.2.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
>>>>>>> e5e32496aba520aed62e3a73e9e0bcc42eaca928
wrap-ansi@7.0.0: wrap-ansi@7.0.0:
dependencies: dependencies:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
@ -16423,6 +16522,16 @@ snapshots:
ws@8.18.3: {} ws@8.18.3: {}
xlsx@0.18.5:
dependencies:
adler-32: 1.3.1
cfb: 1.2.2
codepage: 1.15.0
crc-32: 1.2.2
ssf: 0.11.2
wmf: 1.0.2
word: 0.3.0
xml-name-validator@5.0.0: {} xml-name-validator@5.0.0: {}
xmlchars@2.2.0: {} xmlchars@2.2.0: {}

View File

@ -2,6 +2,7 @@ import api from "@/src/lib/api";
import { import {
httpGetInterceptor, httpGetInterceptor,
httpPostInterceptor, httpPostInterceptor,
httpPutInterceptor,
} from "../http-config/http-interceptor-service"; } from "../http-config/http-interceptor-service";
export async function getMediaTrackingMonitoring(page: number, size: number) { export async function getMediaTrackingMonitoring(page: number, size: number) {
@ -63,31 +64,41 @@ export async function listDataTracking(
); );
} }
export async function listDataAllNonPagination(search: string) { export async function listDataAllNonPagination(search: string) {
return await httpGetInterceptor( return await httpGetInterceptor(
`media/public/list?enablePage=0&sort=desc&title=${search || ""}` `media/public/list?enablePage=0&sort=desc&title=${search || ""}`
); );
} }
export const validateMediaLink = async ( export async function validateMediaLink(resultId: number, isRelevant: boolean) {
resultId: number, const url = "media/tracking/monitoring/results/relevant";
isRelevant: boolean
) => {
try {
const res = await api.put(
"/media/tracking/monitoring/results/relevant",
{
resultId,
isRelevant,
}
);
return res.data; const payload = {
} catch (error: any) { resultId,
throw new Error( isRelevant,
error?.response?.data?.messages?.[0] || };
"Gagal memperbarui status relevansi"
); return httpPutInterceptor(url, payload);
} }
};
// export const validateMediaLink = async (
// resultId: number,
// isRelevant: boolean
// ) => {
// try {
// const res = await api.put(
// "/media/tracking/monitoring/results/relevant",
// {
// resultId,
// isRelevant,
// }
// );
// return res.data;
// } catch (error: any) {
// throw new Error(
// error?.response?.data?.messages?.[0] ||
// "Gagal memperbarui status relevansi"
// );
// }
// };

View File

@ -4,5 +4,6 @@ import "@tanstack/react-table";
declare module "@tanstack/react-table" { declare module "@tanstack/react-table" {
interface TableMeta<TData> { interface TableMeta<TData> {
updateData: (rowIndex: number, value: Partial<TData>) => void; updateData: (rowIndex: number, value: Partial<TData>) => void;
refetchData?: () => void;
} }
} }