feat:language table approver
This commit is contained in:
parent
dbf0edb58e
commit
b842c63998
|
|
@ -45,6 +45,7 @@ import { listEnableCategory } from "@/service/content/content";
|
|||
import { useTranslations } from "next-intl";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const BlogTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -73,7 +74,7 @@ const BlogTable = () => {
|
|||
);
|
||||
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -17,155 +17,162 @@ import Swal from "sweetalert2";
|
|||
import withReactContent from "sweetalert2-react-content";
|
||||
import { deleteBlog } from "@/service/blog/blog";
|
||||
import { error, loading } from "@/lib/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-normal">{row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "tags",
|
||||
header: "Tag",
|
||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-normal">{row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category"),
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "tags",
|
||||
header: t("tag"),
|
||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteBlog(id);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteBlog(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteBlog = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
const handleDeleteBlog = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteBlog(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteBlog(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -17,211 +17,224 @@ import withReactContent from "sweetalert2-react-content";
|
|||
import { deleteMedia } from "@/service/content/content";
|
||||
import { error } from "@/lib/swal";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/audio/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/audio/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/audio/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/audio/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableAudio = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -99,7 +100,7 @@ const TableAudio = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
"use client";
|
||||
import * as React from "react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
|
|
@ -19,213 +20,224 @@ import { deleteMedia } from "@/service/content/content";
|
|||
import { error, loading } from "@/lib/swal";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
//
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
//
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/image/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/image/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/image/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/image/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ import { ticketingPagination } from "@/service/ticketing/ticketing";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
|
||||
import {
|
||||
deleteMedia,
|
||||
listDataImage,
|
||||
|
|
@ -66,6 +66,7 @@ import withReactContent from "sweetalert2-react-content";
|
|||
import { error } from "@/lib/swal";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableImage = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -104,7 +105,7 @@ const TableImage = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -16,137 +16,146 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTitle",
|
||||
header: "Judul",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("contentTitle");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTitle",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("contentTitle");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTag",
|
||||
header: t("tag"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentType",
|
||||
header: t("type-content"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentCreatedGroupBy",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("contentCreatedGroupBy")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTag",
|
||||
header: "Tag",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentType",
|
||||
header: "Tipe Konten ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentCreatedGroupBy",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("contentCreatedGroupBy")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "isPublish",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.getValue<boolean>("isPublish");
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="sm"
|
||||
color={isPublish ? "success" : "warning"}
|
||||
variant="outline"
|
||||
className={`btn btn-sm ${
|
||||
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||
} pill-btn ml-1`}
|
||||
>
|
||||
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentCreatedDate",
|
||||
header: "Tanggal Unggah",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("contentCreatedDate") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const isDisabled = row.original.isPublish; // Check the isPublish value
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild disabled={isDisabled}>
|
||||
{
|
||||
accessorKey: "isPublish",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.getValue<boolean>("isPublish");
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="icon"
|
||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable button if isPublish is true
|
||||
size="sm"
|
||||
color={isPublish ? "success" : "warning"}
|
||||
variant="outline"
|
||||
className={`btn btn-sm ${
|
||||
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||
} pill-btn ml-1`}
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/spit/convert/${row.original.contentId}`}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className={`p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none ${
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentCreatedDate",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("contentCreatedDate") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const isDisabled = row.original.isPublish; // Check the isPublish value
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild disabled={isDisabled}>
|
||||
<Button
|
||||
size="icon"
|
||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable dropdown item if isPublish is true
|
||||
disabled={isDisabled} // Disable button if isPublish is true
|
||||
>
|
||||
<MoveDownRight className="w-4 h-4 me-1.5" />
|
||||
Pindah Ke Mediahub
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/spit/convert/${row.original.contentId}`}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className={`p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable dropdown item if isPublish is true
|
||||
>
|
||||
<MoveDownRight className="w-4 h-4 me-1.5" />
|
||||
Pindah Ke Mediahub
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import {
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
// export type CompanyData = {
|
||||
// no: number;
|
||||
|
|
@ -89,7 +90,7 @@ const TableSPIT = () => {
|
|||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: spitTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -17,212 +17,224 @@ import { error } from "@/lib/swal";
|
|||
import { deleteMedia } from "@/service/content/content";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/teks/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/teks/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/teks/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/teks/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableTeks = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -98,7 +99,7 @@ const TableTeks = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -17,209 +17,223 @@ import { deleteMedia } from "@/service/content/content";
|
|||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { error } from "@/lib/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/video/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/video/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/video/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/video/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableVideo = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -98,7 +99,7 @@ const TableVideo = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,105 +13,111 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import { getPlanningSentPagination } from "@/service/planning/planning";
|
|||
import search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const MediahubTable = () => {
|
||||
const t = useTranslations("Planning");
|
||||
|
|
@ -78,7 +79,7 @@ const MediahubTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,103 +13,109 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import columns from "./columns";
|
|||
import { getPlanningSentPagination } from "@/service/planning/planning";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const MedsosTable = () => {
|
||||
const t = useTranslations("Planning");
|
||||
|
|
@ -77,7 +78,7 @@ const MedsosTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,171 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default columns;
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { useTranslations } from "next-intl";
|
|||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const EventTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -55,7 +56,7 @@ const EventTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,172 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
|||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const PressConferenceTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -68,7 +69,7 @@ const PressConferenceTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,172 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
|||
import { useTranslations } from "next-intl";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const PressReleaseTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -69,7 +70,7 @@ const PressReleaseTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -20,187 +20,193 @@ import { deleteTask } from "@/service/task";
|
|||
import { error, loading } from "@/lib/swal";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }) => (
|
||||
<div>
|
||||
<span>{row.getValue("title")}</span>
|
||||
{row.original.isForward && (
|
||||
<Button
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
size="sm"
|
||||
className="ml-3 rounded-xl"
|
||||
>
|
||||
Forward
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "uniqueCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => <span>{row.getValue("uniqueCode")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "assignmentMainType",
|
||||
header: "Type Task",
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentMainType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "assignmentType",
|
||||
header: "Category Task",
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.original.isActive;
|
||||
const isDone = row.original.isDone;
|
||||
|
||||
let statusText = "";
|
||||
if (isDone) {
|
||||
statusText = "Selesai";
|
||||
} else if (isActive) {
|
||||
statusText = "Aktif";
|
||||
} else {
|
||||
statusText = "Nonaktif";
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
Aktif: "bg-primary/20 text-primary",
|
||||
Selesai: "bg-success/20 text-success",
|
||||
Nonaktif: "bg-gray-200 text-gray-500",
|
||||
};
|
||||
|
||||
const statusStyles = statusColors[statusText] || "default";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{statusText}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteTask(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const TaskDelete = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div>
|
||||
<span>{row.getValue("title")}</span>
|
||||
{row.original.isForward && (
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
size="sm"
|
||||
className="ml-3 rounded-xl"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
Forward
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/task/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => TaskDelete(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
{
|
||||
accessorKey: "uniqueCode",
|
||||
header: t("code"),
|
||||
cell: ({ row }) => <span>{row.getValue("uniqueCode")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "assignmentMainType",
|
||||
header: t("type-task"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentMainType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "assignmentType",
|
||||
header: t("category-task"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.original.isActive;
|
||||
const isDone = row.original.isDone;
|
||||
|
||||
let statusText = "";
|
||||
if (isDone) {
|
||||
statusText = "Selesai";
|
||||
} else if (isActive) {
|
||||
statusText = "Aktif";
|
||||
} else {
|
||||
statusText = "Nonaktif";
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
Aktif: "bg-primary/20 text-primary",
|
||||
Selesai: "bg-success/20 text-success",
|
||||
Nonaktif: "bg-gray-200 text-gray-500",
|
||||
};
|
||||
|
||||
const statusStyles = statusColors[statusText] || "default";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{statusText}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteTask(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const TaskDelete = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/task/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => TaskDelete(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import { listTask } from "@/service/task";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TaskTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -83,7 +84,7 @@ const TaskTable = () => {
|
|||
const [limit, setLimit] = React.useState(10);
|
||||
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import {
|
|||
getTicketingEscalationPagination,
|
||||
listTicketingInternal,
|
||||
} from "@/service/communication/communication";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const CollaborationTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -88,7 +89,7 @@ const CollaborationTable = () => {
|
|||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,102 +13,113 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: "CreateBy",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("commentFromUserName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "Type",
|
||||
header: "Channel",
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type;
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>{status}</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">
|
||||
{row.getValue("commentFromUserName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/shared/communication/collaboration/detail/${row.original.id}`
|
||||
)
|
||||
}
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center"
|
||||
>
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
{
|
||||
accessorKey: "Type",
|
||||
header: t("type"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type;
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
export default columns;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/shared/communication/collaboration/detail/${row.original.id}`
|
||||
)
|
||||
}
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center"
|
||||
>
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -13,98 +13,108 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("commentFromUserName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type; // Akses properti category
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>{status}</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">
|
||||
{row.getValue("commentFromUserName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/escalation/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: t("type"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type; // Akses properti category
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
export default columns;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/escalation/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import {
|
|||
getTicketingEscalationPagination,
|
||||
listTicketingInternal,
|
||||
} from "@/service/communication/communication";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const EscalationTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -87,7 +88,7 @@ const EscalationTable = () => {
|
|||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,97 +13,104 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdBy",
|
||||
header: "Pengirim",
|
||||
cell: ({ row }) => {
|
||||
const createdBy = row.original.createdBy; // Akses properti category
|
||||
return (
|
||||
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sendTo",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => {
|
||||
const sendTo = row.original.sendTo; // Akses properti category
|
||||
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdBy",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => {
|
||||
const createdBy = row.original.createdBy; // Akses properti category
|
||||
return (
|
||||
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sendTo",
|
||||
header: t("sendto"),
|
||||
cell: ({ row }) => {
|
||||
const sendTo = row.original.sendTo; // Akses properti category
|
||||
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/shared/communication/internal/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/shared/communication/internal/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { listTicketingInternal } from "@/service/communication/communication";
|
||||
import { Link } from "@/components/navigation";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const InternalTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -88,7 +89,7 @@ const InternalTable = () => {
|
|||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -18,200 +18,206 @@ import Swal from "sweetalert2";
|
|||
import { error } from "@/lib/swal";
|
||||
import { deleteMedia } from "@/service/content/content";
|
||||
import { publishContest } from "@/service/contest/contest";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "hastagCode",
|
||||
header: "Kode",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4
|
||||
className="text-sm font-bold
|
||||
text-default-600 whitespace-nowrap mb-1"
|
||||
>
|
||||
{row.getValue("hastagCode")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "theme",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("theme")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: "Durasi ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("duration")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetOutput",
|
||||
header: "Target Output ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("targetOutput")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetParticipantTopLevel",
|
||||
header: "Target Participant ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetParticipantTopLevel")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "isPublishForAll", // Bisa menggunakan ini untuk membaca default data
|
||||
header: "Status",
|
||||
cell: ({
|
||||
row,
|
||||
}: {
|
||||
row: {
|
||||
original: { isPublishForAll?: boolean; isPublishForMabes?: boolean };
|
||||
};
|
||||
}) => {
|
||||
const userRoleId: number = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelNumber: number = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
const isPublishForAll: boolean = Boolean(row.original.isPublishForAll);
|
||||
const isPublishForMabes: boolean = Boolean(
|
||||
row.original.isPublishForMabes
|
||||
);
|
||||
|
||||
const isPending: boolean =
|
||||
(userRoleId === 3 && userLevelNumber === 1 && !isPublishForAll) ||
|
||||
((userRoleId === 11 || userRoleId === 12) && !isPublishForMabes);
|
||||
|
||||
const isTerkirim: boolean = isPublishForMabes && !isPublishForAll;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={`whitespace-nowrap px-2 py-1 rounded-full ${
|
||||
isPending
|
||||
? "bg-orange-100 text-orange-600" // Warna kuning untuk "Pending"
|
||||
: isTerkirim
|
||||
? "bg-blue-100 text-blue-600" // Warna biru untuk "Terkirim"
|
||||
: "bg-green-100 text-green-600" // Warna hijau untuk "Publish"
|
||||
}`}
|
||||
>
|
||||
{isPending ? "Pending" : isTerkirim ? "Terkirim" : "Publish"}
|
||||
</Badge>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const userRoleId = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||
const userLevelNumber = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
async function doPublish(id: any) {
|
||||
// loading();
|
||||
// const data = {
|
||||
// id,
|
||||
// };
|
||||
|
||||
const response = await publishContest(id);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handlePublishContest = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Apakah anda ingin publish Lomba?",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Ya",
|
||||
cancelButtonText: "Tidak",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doPublish(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
{
|
||||
accessorKey: "hastagCode",
|
||||
header: t("code"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4
|
||||
className="text-sm font-bold
|
||||
text-default-600 whitespace-nowrap mb-1"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
{((userRoleId == 11 || userRoleId == 12) &&
|
||||
row?.original?.isPublishForMabes != true) ||
|
||||
(userRoleId == 3 &&
|
||||
userLevelNumber == 1 &&
|
||||
row?.original?.isPublishForAll != true) ? (
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||
onClick={() => handlePublishContest(row.original.id)}
|
||||
{row.getValue("hastagCode")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "theme",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("theme")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: t("duration"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("duration")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetOutput",
|
||||
header: t("target-output"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetOutput")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetParticipantTopLevel",
|
||||
header: t("target-participant"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetParticipantTopLevel")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "isPublishForAll", // Bisa menggunakan ini untuk membaca default data
|
||||
header: "Status",
|
||||
cell: ({
|
||||
row,
|
||||
}: {
|
||||
row: {
|
||||
original: { isPublishForAll?: boolean; isPublishForMabes?: boolean };
|
||||
};
|
||||
}) => {
|
||||
const userRoleId: number = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelNumber: number = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
const isPublishForAll: boolean = Boolean(row.original.isPublishForAll);
|
||||
const isPublishForMabes: boolean = Boolean(
|
||||
row.original.isPublishForMabes
|
||||
);
|
||||
|
||||
const isPending: boolean =
|
||||
(userRoleId === 3 && userLevelNumber === 1 && !isPublishForAll) ||
|
||||
((userRoleId === 11 || userRoleId === 12) && !isPublishForMabes);
|
||||
|
||||
const isTerkirim: boolean = isPublishForMabes && !isPublishForAll;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={`whitespace-nowrap px-2 py-1 rounded-full ${
|
||||
isPending
|
||||
? "bg-orange-100 text-orange-600" // Warna kuning untuk "Pending"
|
||||
: isTerkirim
|
||||
? "bg-blue-100 text-blue-600" // Warna biru untuk "Terkirim"
|
||||
: "bg-green-100 text-green-600" // Warna hijau untuk "Publish"
|
||||
}`}
|
||||
>
|
||||
{isPending ? "Pending" : isTerkirim ? "Terkirim" : "Publish"}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const userRoleId = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||
const userLevelNumber = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
async function doPublish(id: any) {
|
||||
// loading();
|
||||
// const data = {
|
||||
// id,
|
||||
// };
|
||||
|
||||
const response = await publishContest(id);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handlePublishContest = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Apakah anda ingin publish Lomba?",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Ya",
|
||||
cancelButtonText: "Tidak",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doPublish(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<Upload className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/* <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
{((userRoleId == 11 || userRoleId == 12) &&
|
||||
row?.original?.isPublishForMabes != true) ||
|
||||
(userRoleId == 3 &&
|
||||
userLevelNumber == 1 &&
|
||||
row?.original?.isPublishForAll != true) ? (
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||
onClick={() => handlePublishContest(row.original.id)}
|
||||
>
|
||||
<Upload className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/* <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -219,11 +225,14 @@ const columns: ColumnDef<any>[] = [
|
|||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import { useRouter, useSearchParams } from "next/navigation";
|
|||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
import { listContest } from "@/service/contest/contest";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TaskTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -63,7 +64,7 @@ const TaskTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -812,7 +812,7 @@ export default function FormConvertSPIT() {
|
|||
<div className="mt-3">
|
||||
<Label className="text-xl">Penempatan file</Label>
|
||||
</div>
|
||||
{files.length > 1 && (
|
||||
{files?.length > 1 && (
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
|
|
|
|||
|
|
@ -607,5 +607,34 @@
|
|||
},
|
||||
"Curation": {
|
||||
"content-curation": "Content Curation"
|
||||
},
|
||||
"Table": {
|
||||
"no": "No",
|
||||
"title": "Title",
|
||||
"category-name": "Category Name",
|
||||
"upload-date": "Upload Date",
|
||||
"creator-group": "Creator Group",
|
||||
"source": "source",
|
||||
"published": "Published",
|
||||
"date": "Date",
|
||||
"category": "Category",
|
||||
"tag": "Tag",
|
||||
"type-content": "Content Type",
|
||||
"type-task": "Task Type",
|
||||
"category-task": "Category Task",
|
||||
"code": "Code",
|
||||
"start-date": "Start Date",
|
||||
"end-date": "End Date",
|
||||
"speaker": "Speaker",
|
||||
"time": "Time",
|
||||
"address": "Address",
|
||||
"question": "Question",
|
||||
"sender": "Created By",
|
||||
"sendto": "SendTo",
|
||||
"type": "Type",
|
||||
"duration": "Duration",
|
||||
"target-output": "Target Output",
|
||||
"target-participant": "Target Participant",
|
||||
"action": "Actions"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -608,5 +608,34 @@
|
|||
},
|
||||
"Curation": {
|
||||
"content-curation": "Kurasi Konten"
|
||||
},
|
||||
"Table": {
|
||||
"no": "Nomor",
|
||||
"title": "Judul",
|
||||
"category-name": "Nama Kategori",
|
||||
"upload-date": "Tanggal Upload",
|
||||
"creator-group": "Pembuat",
|
||||
"source": "Sumber",
|
||||
"published": "Diterbitkan",
|
||||
"date": "Tanggal",
|
||||
"category": "Kategori",
|
||||
"tag": "Tag",
|
||||
"type-content": "Tipe Konten",
|
||||
"type-task": "Tipen Penugasan",
|
||||
"category-task": "Kategori Penugasan",
|
||||
"code": "Kode",
|
||||
"start-date": "Tanggal Mulai",
|
||||
"end-date": "Tanggal Selesai",
|
||||
"speaker": "Disampaikan Oleh",
|
||||
"time": "Waktu",
|
||||
"address": "Alamat",
|
||||
"question": "Pertanyaan",
|
||||
"sender": "Pengirim",
|
||||
"sendto": "Penerima",
|
||||
"type": "Tipe",
|
||||
"duration": "Durasi",
|
||||
"target-output": "Target Output",
|
||||
"target-participant": "Target Peserta",
|
||||
"action": "Aksi"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue