fix: media tracking table, and update task TA

This commit is contained in:
Sabda Yagra 2025-12-03 13:11:27 +07:00
parent 33f88feb60
commit 6f2eff48a1
3 changed files with 199 additions and 60 deletions

View File

@ -40,7 +40,7 @@ export default function TrackingBeritaCard() {
const initFecth = async () => {
loading();
const response = await listDataTracking(showData, page - 1);
const response = await listDataTracking(Number(showData), page - 1, search);
const data = response?.data?.data;
const newData = data?.content;
setTotalPage(data?.totalPages || 1);
@ -56,23 +56,82 @@ export default function TrackingBeritaCard() {
setContent(response?.data?.data?.content || []);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setSearch(value);
if (value.trim() === "") {
initFecth();
} else {
fecthAll(value);
}
const response = await listDataTracking(Number(showData), 0, value);
setContent(response?.data?.data?.content || []);
};
// const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// const value = e.target.value;
// setSearch(value);
// if (value.trim() === "") {
// initFecth();
// } else {
// fecthAll(value);
// }
// };
const handleSelect = (id: number) => {
setSelectedItems((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
);
};
const doSave = async () => {
if (selectedItems.length === 0) {
MySwal.fire(
"Peringatan",
"Pilih minimal 1 berita untuk disimpan.",
"warning"
);
return;
}
try {
loading();
const promises = selectedItems.map(async (id) => {
const res = await mediaTrackingSave({
mediaUploadId: id,
duration: 24,
scrapingPeriod: 3,
});
// cek pesan API
if (!res?.data?.success) {
throw new Error(res?.data?.message || "Limit media tracking per hari sudah tercapai. Maksimal 5 tracking per hari.");
}
return res;
});
await Promise.all(promises);
close();
await MySwal.fire({
icon: "success",
title: "Berhasil!",
text: "Tracking berita berhasil ditambahkan.",
confirmButtonColor: "#2563eb",
});
setSelectedItems([]);
initFecth();
} catch (err: any) {
close();
MySwal.fire({
icon: "error",
title: "Gagal!",
text: err?.message || "Terjadi kesalahan saat menyimpan data.",
confirmButtonColor: "#dc2626",
});
}
};
// const doSave = async () => {
// if (selectedItems.length === 0) {
// toast("Pilih minimal 1 berita untuk disimpan.");
@ -99,48 +158,63 @@ export default function TrackingBeritaCard() {
// }
// };
const doSave = async () => {
if (selectedItems.length === 0) {
MySwal.fire(
"Peringatan",
"Pilih minimal 1 berita untuk disimpan.",
"warning"
);
return;
}
// const doSave = async () => {
// if (selectedItems.length === 0) {
// MySwal.fire(
// "Peringatan",
// "Pilih minimal 1 berita untuk disimpan.",
// "warning"
// );
// return;
// }
try {
loading();
// try {
// loading();
const promises = selectedItems.map((id) =>
mediaTrackingSave({
mediaUploadId: id,
duration: 24,
scrapingPeriod: 3,
})
);
await Promise.all(promises);
// const promises = selectedItems.map((id) =>
// mediaTrackingSave({
// mediaUploadId: id,
// duration: 24,
// scrapingPeriod: 3,
// })
// );
// await Promise.all(promises);
close();
// close();
await MySwal.fire({
icon: "success",
title: "Berhasil!",
text: "Tracking berita berhasil ditambahkan.",
confirmButtonColor: "#2563eb",
});
// await MySwal.fire({
// icon: "success",
// title: "Berhasil!",
// text: "Tracking berita berhasil ditambahkan.",
// confirmButtonColor: "#2563eb",
// });
setSelectedItems([]);
initFecth();
} catch (err: any) {
close();
MySwal.fire({
icon: "error",
title: "Gagal!",
text: err?.message || "Terjadi kesalahan saat menyimpan data.",
confirmButtonColor: "#dc2626",
});
}
// setSelectedItems([]);
// initFecth();
// } catch (err: any) {
// close();
// MySwal.fire({
// icon: "error",
// title: "Gagal!",
// text: err?.message || "Terjadi kesalahan saat menyimpan data.",
// confirmButtonColor: "#dc2626",
// });
// }
// };
const slugify = (text: string) => {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/(^-|-$)+/g, "");
};
const goToDetail = (item: any) => {
const type = item.type || "image";
const slug = slugify(item.title || "");
const url = `/in/${type}/detail/${item.id}-${slug}`;
window.location.href = url;
};
return (
@ -188,7 +262,7 @@ export default function TrackingBeritaCard() {
<div className="text-sm text-blue-600 font-medium">
{selectedItems.length} Item Terpilih{" "}
<span className="text-black">
/ Tracking Berita tersisa {29 - selectedItems.length}
/ Tracking Berita tersisa {5 - selectedItems.length}
</span>
</div>
<Button className="bg-blue-600 text-white" onClick={doSave}>
@ -198,6 +272,48 @@ export default function TrackingBeritaCard() {
)}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{content?.length > 0 &&
content.map((item: any) => (
<Card
key={item.id}
className="relative overflow-hidden shadow-sm border rounded-lg"
>
{/* KLIK GAMBAR = CHECKLIST */}
<div
className="cursor-pointer"
onClick={() => handleSelect(item.id)}
>
<img
src={item.thumbnailLink}
alt={item.title}
className="w-full h-[300px] object-cover"
/>
{/* CHECKBOX */}
<div className="absolute top-2 left-2">
<div className="w-5 h-5 border-2 border-white bg-white rounded-sm flex items-center justify-center">
{selectedItems.includes(item.id) && (
<div className="w-3 h-3 bg-blue-600 rounded-sm" />
)}
</div>
</div>
</div>
{/* KLIK JUDUL = DETAIL */}
<p
className="p-2 text-sm font-medium hover:underline cursor-pointer"
onClick={(e) => {
e.stopPropagation();
goToDetail(item);
}}
>
{item.title}
</p>
</Card>
))}
</div>
{/* <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{content?.length > 1 &&
content.map((item: any) => (
<Card
@ -222,7 +338,7 @@ export default function TrackingBeritaCard() {
</p>
</Card>
))}
</div>
</div> */}
<div className="mt-3">
{content && content?.length > 0 ? (
<CustomPagination

View File

@ -58,10 +58,8 @@ import { getListCompetencies } from "@/service/management-user/management-user";
const taskSchema = z.object({
// uniqueCode: z.string().min(1, { message: "Judul diperlukan" }),
title: z.string().min(1, { message: "Judul diperlukan" }),
naration: z.string().min(2, {
message: "Narasi Penugasan harus lebih dari 2 karakter.",
}),
title: z.string().optional(),
naration: z.string().optional(),
});
export type taskDetail = {
@ -585,9 +583,11 @@ export default function FormTaskTaEdit() {
assignedToRole: selectedTarget,
assignmentType: taskType,
assignmentTypeId: type,
narration: data.naration,
// narration: data.naration,
narration: data.naration ?? detail?.narration ?? "",
expertCompetencies: Array.from(selectedCompetencies).join(","),
title: data.title,
// title: data.title,
title: data.title ?? detail?.title ?? "",
attachmentUrl: urlInputs
.map((url: any) => url.attachmentUrl || "")
.filter((url: string) => url.trim() !== ""),
@ -844,7 +844,7 @@ export default function FormTaskTaEdit() {
const handleLinkChange = (index: number, value: string) => {
setUrlInputs((prev: any) =>
prev.map((url: any, idx: any) =>
prev.map((url: any, idx: any) =>
idx === index ? { ...url, attachmentUrl: value } : url
)
);
@ -886,7 +886,9 @@ export default function FormTaskTaEdit() {
)}
</div>
<div className="mt-5 space-y-2">
<Label>{t("areas-expertise", { defaultValue: "Areas Expertise" })}</Label>
<Label>
{t("areas-expertise", { defaultValue: "Areas Expertise" })}
</Label>
<div className="flex flex-wrap gap-4">
{userCompetencies?.map((item: any) => (
<div className="flex items-center gap-2" key={item.id}>
@ -901,7 +903,9 @@ export default function FormTaskTaEdit() {
</div>
</div>
<div className="mt-5 space-y-2">
<Label>{t("choose-expert", { defaultValue: "Choose Expert" })}</Label>
<Label>
{t("choose-expert", { defaultValue: "Choose Expert" })}
</Label>
<div className="flex flex-wrap gap-4">
<Dialog>
<DialogTrigger asChild>
@ -982,7 +986,9 @@ export default function FormTaskTaEdit() {
</div>
<div className="mt-5 space-y-2">
<Label>{t("description", { defaultValue: "Description" })}</Label>
<Label>
{t("description", { defaultValue: "Description" })}
</Label>
<Controller
control={control}
name="naration"
@ -1000,10 +1006,14 @@ export default function FormTaskTaEdit() {
)}
</div>
<div className="space-y-2.5 mt-5">
<Label htmlFor="attachments">{t("attachment", { defaultValue: "Attachment" })}</Label>
<Label htmlFor="attachments">
{t("attachment", { defaultValue: "Attachment" })}
</Label>
<div className="space-y-3">
<div className="space-y-2">
<Label>{t("audio-visual", { defaultValue: "Audio Visual" })}</Label>
<Label>
{t("audio-visual", { defaultValue: "Audio Visual" })}
</Label>
<FileUploader
accept={{
"mp4/*": [],

View File

@ -44,12 +44,25 @@ export async function getMediaTrackingResult(data: any) {
return httpGetInterceptor(url);
}
export async function listDataTracking(size: any, page: any) {
// export async function listDataTracking(size: any, page: any) {
// return await httpGetInterceptor(
// `media/public/list?enablePage=1&sort=desc&size=${size}&page=${page}`
// );
// }
export async function listDataTracking(
size: number,
page: number,
keyword = "",
categoryFilter = "",
statusFilter = ""
) {
return await httpGetInterceptor(
`media/public/list?enablePage=1&sort=desc&size=${size}&page=${page}`
`media/list?isForAdmin=true&title=${keyword}&enablePage=1&sortBy=createdAt&sort=desc&size=${size}&page=${page}&categoryId=${categoryFilter}&statusId=${statusFilter}`
);
}
export async function listDataAllNonPagination(search: string) {
return await httpGetInterceptor(
`media/public/list?enablePage=0&sort=desc&title=${search || ""}`