fix: adjust coloumns media tracking

This commit is contained in:
Sabda Yagra 2026-01-06 11:22:13 +07:00
parent 1a0d53bb11
commit 280ea508e9
6 changed files with 134 additions and 24 deletions

View File

@ -31,6 +31,7 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
import { validateMediaLink } from "@/service/media-tracking/media-tracking";
const columns: ColumnDef<any>[] = [
{
@ -52,12 +53,85 @@ const columns: ColumnDef<any>[] = [
<span className="normal-case">{row.getValue("title")}</span>
),
},
// {
// accessorKey: "link",
// header: "Link Berita",
// cell: ({ row }) => (
// <span className="normal-case">{row.getValue("link")}</span>
// ),
// },
{
accessorKey: "link",
header: "Link Berita",
cell: ({ row }) => (
<span className="normal-case">{row.getValue("link")}</span>
),
cell: ({ row }) => {
const link = row.getValue<string>("link");
if (!link) {
return <span className="text-muted-foreground">-</span>;
}
return (
<Link
href={link}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline hover:text-blue-800 break-all"
>
{link}
</Link>
);
},
},
{
id: "validation",
header: "Validasi",
cell: ({ row, table }) => {
const original = row.original;
const isValid = original.isValid;
const link = original.link;
const updateRow = (data: Partial<any>) => {
table.options.meta?.updateData(row.index, data);
};
const handleValid = async () => {
await validateMediaLink(original.id, true);
updateRow({ isValid: true });
};
const handleInvalid = async () => {
await validateMediaLink(original.id, false);
updateRow({ isValid: false, link: undefined });
};
if (!link) {
return <span className="text-muted-foreground">-</span>;
}
if (isValid === true) {
return (
<Button size="sm" className="bg-green-600 hover:bg-green-700">
Valid
</Button>
);
}
return (
<div className="flex gap-2">
<Button size="sm" variant="outline" onClick={handleValid}>
Valid
</Button>
<Button
size="sm"
variant="outline"
onClick={handleInvalid}
>
Tidak Valid
</Button>
</div>
);
},
},
];

View File

@ -253,7 +253,7 @@ const NewsDetailTable = () => {
totalData={totalData}
totalPage={totalPage}
/>
</div>
</div>
);
};

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { DownloadIcon, Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
@ -141,13 +141,17 @@ const columns: ColumnDef<any>[] = [
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<Link href={`/admin/media-tracking/detail/${row.original.id}`}>
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground items-center rounded-none">
<DropdownMenuItem className="p-2 border-b cursor-pointer text-default-700 group focus:bg-default focus:text-primary-foreground items-center rounded-none">
<Eye className="w-4 h-4 me-1.5" />
View&nbsp;
{row.original.mediaUpload.fileType.secondaryName &&
row.original.mediaUpload.fileType.secondaryName.toLowerCase()}
</DropdownMenuItem>
</Link>
<DropdownMenuItem className="p-2 border-b cursor-pointer text-default-700 group focus:bg-default focus:text-primary-foreground items-center rounded-none">
<DownloadIcon className="w-4 h-4 me-1.5"/>
<p>Download</p>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);

View File

@ -80,7 +80,8 @@
// };
// export default AdvertisementPlacements;
import { listDataAdvertisements } from "@/service/broadcast/broadcast";
"use client";
import { useEffect, useState } from "react";
import * as React from "react";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
@ -93,35 +94,40 @@ interface Advertisement {
[key: string]: any;
}
const AdvertisementPlacements = (props: {
interface AdvertisementPlacementsProps {
placement: string;
data: Advertisement[];
data?: Advertisement[]; // ⬅️ PENTING: optional
loading: boolean;
}) => {
const [ads, setAds] = useState<Advertisement[] | undefined[]>([]);
}
const AdvertisementPlacements = ({
placement,
data = [], // ⬅️ DEFAULT VALUE (KUNCI UTAMA)
loading,
}: AdvertisementPlacementsProps) => {
const [ads, setAds] = useState<(Advertisement | undefined)[]>([]);
useEffect(() => {
if (!props.loading && props.data.length > 0) {
const filtered = props.data.filter((a) =>
a.placements.includes(props.placement)
);
if (loading || data.length === 0) return;
let temps: Advertisement[] | undefined[] = [];
temps[0] = filtered.find((b) => b.placements.includes("top"));
temps[1] = filtered.find((b) => b.placements.includes("bottom"));
setAds(temps);
}
}, [props.data, props.loading, props.placement]);
const filtered = data.filter((a) => a.placements?.includes(placement));
const temps: (Advertisement | undefined)[] = [];
temps[0] = filtered.find((b) => b.placements?.includes("top"));
temps[1] = filtered.find((b) => b.placements?.includes("bottom"));
setAds(temps);
}, [data, loading, placement]);
return (
<div
className={`sticky top-0 space-y-4 ${
props.placement === "left" ? "ml-14" : "mr-14"
placement === "left" ? "ml-14" : "mr-14"
}`}
>
{props.loading && <p className="text-sm text-gray-500">Loading...</p>}
{loading && <p className="text-sm text-gray-500">Loading...</p>}
{ads?.map(
{ads.map(
(ad) =>
ad && (
<Dialog key={ad.id}>
@ -132,6 +138,7 @@ const AdvertisementPlacements = (props: {
className="w-full cursor-pointer rounded-lg shadow-md hover:opacity-90 transition"
/>
</DialogTrigger>
<DialogContent className="max-w-4xl p-0 bg-transparent border-0 shadow-none">
<img
src={ad.contentFileUrl || ad.imageUrl}

View File

@ -67,3 +67,20 @@ export async function listDataAllNonPagination(search: string) {
`media/public/list?enablePage=0&sort=desc&title=${search || ""}`
);
}
// service/media-validation.ts
export const validateMediaLink = async (
id: string | number,
isValid: boolean
) => {
console.log("API DUMMY:", { id, isValid });
return new Promise((resolve) => {
setTimeout(() => {
resolve({
success: true,
isValid,
});
}, 600);
});
};

8
src/types/react-table.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
// src/types/react-table.d.ts
import "@tanstack/react-table";
declare module "@tanstack/react-table" {
interface TableMeta<TData> {
updateData: (rowIndex: number, value: Partial<TData>) => void;
}
}