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 { useTranslations } from "next-intl";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const BlogTable = () => {
|
const BlogTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -73,7 +74,7 @@ const BlogTable = () => {
|
||||||
);
|
);
|
||||||
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
||||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -17,155 +17,162 @@ import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { deleteBlog } from "@/service/blog/blog";
|
import { deleteBlog } from "@/service/blog/blog";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
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 formattedDate =
|
const columns: ColumnDef<any>[] = [
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
{
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
accessorKey: "no",
|
||||||
: "-";
|
header: t("no"),
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "tags",
|
header: t("title"),
|
||||||
header: "Tag",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
<span className="whitespace-normal">{row.getValue("title")}</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: "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;
|
||||||
|
|
||||||
{
|
const formattedDate =
|
||||||
id: "actions",
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
accessorKey: "action",
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
header: "Actions",
|
: "-";
|
||||||
enableHiding: false,
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
cell: ({ row }) => {
|
},
|
||||||
const router = useRouter();
|
},
|
||||||
const MySwal = withReactContent(Swal);
|
{
|
||||||
|
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) {
|
// Mengambil `statusName` dari data API
|
||||||
loading();
|
const status = row.getValue("statusName") as string;
|
||||||
const resDelete = await deleteBlog(id);
|
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||||
|
|
||||||
if (resDelete?.error) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(resDelete.message);
|
const statusStyles =
|
||||||
return false;
|
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() {
|
function success() {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Sukses",
|
title: "Sukses",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteBlog = (id: any) => {
|
const handleDeleteBlog = (id: any) => {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Hapus Data",
|
title: "Hapus Data",
|
||||||
text: "",
|
text: "",
|
||||||
icon: "warning",
|
icon: "warning",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
cancelButtonColor: "#3085d6",
|
cancelButtonColor: "#3085d6",
|
||||||
confirmButtonColor: "#d33",
|
confirmButtonColor: "#d33",
|
||||||
confirmButtonText: "Hapus",
|
confirmButtonText: "Hapus",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
deleteProcess(id);
|
deleteProcess(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
<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">
|
<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" />
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
View
|
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
</DropdownMenu>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 { deleteMedia } from "@/service/content/content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
accessorKey: "statusName",
|
header: t("source"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="whitespace-nowrap">
|
||||||
const statusColors: Record<string, string> = {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
diterima: "bg-green-100 text-green-600",
|
</span>
|
||||||
"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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(response.message);
|
const statusStyles =
|
||||||
return false;
|
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||||
}
|
|
||||||
success();
|
|
||||||
}
|
|
||||||
|
|
||||||
function success() {
|
return (
|
||||||
MySwal.fire({
|
<Badge
|
||||||
title: "Sukses",
|
className={cn(
|
||||||
icon: "success",
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
confirmButtonColor: "#3085d6",
|
statusStyles
|
||||||
confirmButtonText: "OK",
|
)}
|
||||||
}).then((result) => {
|
>
|
||||||
if (result.isConfirmed) {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
window.location.reload();
|
</Badge>
|
||||||
}
|
);
|
||||||
});
|
},
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableAudio = () => {
|
const TableAudio = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -99,7 +100,7 @@ const TableAudio = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
|
@ -19,213 +20,224 @@ import { deleteMedia } from "@/service/content/content";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const MySwal = withReactContent(Swal);
|
const useTableColumns = () => {
|
||||||
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
const columns: ColumnDef<any>[] = [
|
const MySwal = withReactContent(Swal);
|
||||||
{
|
const columns: ColumnDef<any>[] = [
|
||||||
accessorKey: "no",
|
{
|
||||||
header: "No",
|
accessorKey: "no",
|
||||||
cell: ({ row }) => (
|
header: t("no"),
|
||||||
<div className="flex items-center gap-5">
|
cell: ({ row }) => (
|
||||||
<div className="flex-1 text-start">
|
<div className="flex items-center gap-5">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex-1 text-start">
|
||||||
{row.getValue("no")}
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
</h4>
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
{
|
header: t("source"),
|
||||||
accessorKey: "statusName",
|
cell: ({ row }) => (
|
||||||
header: "Status",
|
<span className="whitespace-nowrap">
|
||||||
cell: ({ row }) => {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusColors: Record<string, string> = {
|
</span>
|
||||||
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: "publishedOn",
|
||||||
|
header: t("published"),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const isPublish = row.original.isPublish;
|
||||||
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
|
|
||||||
{
|
let displayText = "-";
|
||||||
id: "actions",
|
if (isPublish && !isPublishOnPolda) {
|
||||||
accessorKey: "action",
|
displayText = "Mabes";
|
||||||
header: "Actions",
|
} else if (isPublish && isPublishOnPolda) {
|
||||||
enableHiding: false,
|
displayText = "Mabes & Polda";
|
||||||
cell: ({ row }) => {
|
} else if (!isPublish && isPublishOnPolda) {
|
||||||
const router = useRouter();
|
displayText = "Polda";
|
||||||
const MySwal = withReactContent(Swal);
|
}
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
return (
|
||||||
// loading();
|
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||||
const data = {
|
{displayText}
|
||||||
id,
|
</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) {
|
return (
|
||||||
error(response.message);
|
<Badge
|
||||||
return false;
|
className={cn(
|
||||||
}
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
success();
|
statusStyles
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
function success() {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
MySwal.fire({
|
</Badge>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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 { Badge } from "@/components/ui/badge";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import TablePagination from "@/components/table/table-pagination";
|
import TablePagination from "@/components/table/table-pagination";
|
||||||
import columns from "./columns";
|
|
||||||
import {
|
import {
|
||||||
deleteMedia,
|
deleteMedia,
|
||||||
listDataImage,
|
listDataImage,
|
||||||
|
|
@ -66,6 +66,7 @@ import withReactContent from "sweetalert2-react-content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableImage = () => {
|
const TableImage = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -104,7 +105,7 @@ const TableImage = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -16,137 +16,146 @@ import {
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "contentTitle",
|
||||||
accessorKey: "contentTitle",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("contentTitle");
|
||||||
const title: string = row.getValue("contentTitle");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("contentCreatedGroupBy")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "contentTag",
|
|
||||||
header: "Tag",
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "contentType",
|
accessorKey: "isPublish",
|
||||||
header: "Tipe Konten ",
|
header: "Status",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => {
|
||||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
const isPublish = row.getValue<boolean>("isPublish");
|
||||||
),
|
return (
|
||||||
},
|
<div>
|
||||||
{
|
|
||||||
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}>
|
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="sm"
|
||||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
color={isPublish ? "success" : "warning"}
|
||||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
variant="outline"
|
||||||
}`}
|
className={`btn btn-sm ${
|
||||||
disabled={isDisabled} // Disable button if isPublish is true
|
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||||
|
} pill-btn ml-1`}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</div>
|
||||||
<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 ${
|
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" : ""
|
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" />
|
<span className="sr-only">Open menu</span>
|
||||||
Pindah Ke Mediahub
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</DropdownMenuItem>
|
</Button>
|
||||||
</Link>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuContent>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
</DropdownMenu>
|
<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 { Label } from "@/components/ui/label";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
// export type CompanyData = {
|
// export type CompanyData = {
|
||||||
// no: number;
|
// no: number;
|
||||||
|
|
@ -89,7 +90,7 @@ const TableSPIT = () => {
|
||||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: spitTable,
|
data: spitTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -17,212 +17,224 @@ import { error } from "@/lib/swal";
|
||||||
import { deleteMedia } from "@/service/content/content";
|
import { deleteMedia } from "@/service/content/content";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
{
|
header: t("source"),
|
||||||
accessorKey: "statusName",
|
cell: ({ row }) => (
|
||||||
header: "Status",
|
<span className="whitespace-nowrap">
|
||||||
cell: ({ row }) => {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusColors: Record<string, string> = {
|
</span>
|
||||||
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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(response.message);
|
const statusStyles =
|
||||||
return false;
|
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||||
}
|
|
||||||
success();
|
|
||||||
}
|
|
||||||
|
|
||||||
function success() {
|
return (
|
||||||
MySwal.fire({
|
<Badge
|
||||||
title: "Sukses",
|
className={cn(
|
||||||
icon: "success",
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
confirmButtonColor: "#3085d6",
|
statusStyles
|
||||||
confirmButtonText: "OK",
|
)}
|
||||||
}).then((result) => {
|
>
|
||||||
if (result.isConfirmed) {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
window.location.reload();
|
</Badge>
|
||||||
}
|
);
|
||||||
});
|
},
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableTeks = () => {
|
const TableTeks = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -98,7 +99,7 @@ const TableTeks = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -17,209 +17,223 @@ import { deleteMedia } from "@/service/content/content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
|
||||||
cell: ({ row }) => (
|
const columns: ColumnDef<any>[] = [
|
||||||
<div className="flex items-center gap-5">
|
{
|
||||||
<div className="flex-1 text-start">
|
accessorKey: "no",
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
header: t("no"),
|
||||||
{row.getValue("no")}
|
cell: ({ row }) => (
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
{
|
header: t("source"),
|
||||||
accessorKey: "statusName",
|
cell: ({ row }) => (
|
||||||
header: "Status",
|
<span className="whitespace-nowrap">
|
||||||
cell: ({ row }) => {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusColors: Record<string, string> = {
|
</span>
|
||||||
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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
return (
|
||||||
error(response.message);
|
<Badge
|
||||||
return false;
|
className={cn(
|
||||||
}
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
success();
|
statusStyles
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
function success() {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
MySwal.fire({
|
</Badge>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableVideo = () => {
|
const TableVideo = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -98,7 +99,7 @@ const TableVideo = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,105 +13,111 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => (
|
accessorKey: "no",
|
||||||
<div className="flex items-center gap-5">
|
header: t("no"),
|
||||||
<div className="flex-1 text-start">
|
cell: ({ row }) => (
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex items-center gap-5">
|
||||||
{row.getValue("no")}
|
<div className="flex-1 text-start">
|
||||||
</h4>
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<div className="flex items-center gap-5">
|
||||||
<div className="flex items-center gap-5">
|
<div className="flex-1 text-start">
|
||||||
<div className="flex-1 text-start">
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
{row.getValue("title")}
|
||||||
{row.getValue("title")}
|
</h4>
|
||||||
</h4>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "createdAt",
|
header: t("upload-date"),
|
||||||
header: "Tanggal Unggah ",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const createdAt = row.getValue("createdAt") as
|
||||||
const createdAt = row.getValue("createdAt") as
|
| string
|
||||||
| string
|
| number
|
||||||
| number
|
| undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "isActive",
|
||||||
accessorKey: "isActive",
|
header: "Status",
|
||||||
header: "Status",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const isActive = row.getValue<boolean>("isActive");
|
||||||
const isActive = row.getValue<boolean>("isActive");
|
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
return (
|
||||||
return (
|
<div>
|
||||||
<div>
|
{isActive ? (
|
||||||
{isActive ? (
|
<b className="text-blue-500">Terkirim</b>
|
||||||
<b className="text-blue-500">Terkirim</b>
|
) : (
|
||||||
) : (
|
<b className="text-danger">Belum Terkirim</b>
|
||||||
<b className="text-danger">Belum Terkirim</b>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
id: "actions",
|
||||||
id: "actions",
|
accessorKey: "action",
|
||||||
accessorKey: "action",
|
header: t("action"),
|
||||||
header: "Actions",
|
enableHiding: false,
|
||||||
enableHiding: false,
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
return (
|
||||||
return (
|
<DropdownMenu>
|
||||||
<DropdownMenu>
|
<DropdownMenuTrigger asChild>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button
|
size="icon"
|
||||||
size="icon"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
>
|
||||||
>
|
<span className="sr-only">Open menu</span>
|
||||||
<span className="sr-only">Open menu</span>
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</Button>
|
||||||
</Button>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuTrigger>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<Link
|
||||||
<Link
|
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||||
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">
|
||||||
<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" />
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<DropdownMenuItem
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const MediahubTable = () => {
|
const MediahubTable = () => {
|
||||||
const t = useTranslations("Planning");
|
const t = useTranslations("Planning");
|
||||||
|
|
@ -78,7 +79,7 @@ const MediahubTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,103 +13,109 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => (
|
accessorKey: "no",
|
||||||
<div className="flex items-center gap-5">
|
header: t("no"),
|
||||||
<div className="flex-1 text-start">
|
cell: ({ row }) => (
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex items-center gap-5">
|
||||||
{row.getValue("no")}
|
<div className="flex-1 text-start">
|
||||||
</h4>
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<div className="flex items-center gap-5">
|
||||||
<div className="flex items-center gap-5">
|
<div className="flex-1 text-start">
|
||||||
<div className="flex-1 text-start">
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
{row.getValue("title")}
|
||||||
{row.getValue("title")}
|
</h4>
|
||||||
</h4>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "createdAt",
|
header: t("upload-date"),
|
||||||
header: "Tanggal Unggah ",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const createdAt = row.getValue("createdAt") as
|
||||||
const createdAt = row.getValue("createdAt") as
|
| string
|
||||||
| string
|
| number
|
||||||
| number
|
| undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "isActive",
|
||||||
accessorKey: "isActive",
|
header: "Status",
|
||||||
header: "Status",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const isActive = row.getValue<boolean>("isActive");
|
||||||
const isActive = row.getValue<boolean>("isActive");
|
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
return (
|
||||||
return (
|
<div>
|
||||||
<div>
|
{isActive ? (
|
||||||
{isActive ? (
|
<b className="text-blue-500">Terkirim</b>
|
||||||
<b className="text-blue-500">Terkirim</b>
|
) : (
|
||||||
) : (
|
<b className="text-danger">Belum Terkirim</b>
|
||||||
<b className="text-danger">Belum Terkirim</b>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
id: "actions",
|
||||||
id: "actions",
|
accessorKey: "action",
|
||||||
accessorKey: "action",
|
header: t("action"),
|
||||||
header: "Actions",
|
enableHiding: false,
|
||||||
enableHiding: false,
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
return (
|
||||||
return (
|
<DropdownMenu>
|
||||||
<DropdownMenu>
|
<DropdownMenuTrigger asChild>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button
|
size="icon"
|
||||||
size="icon"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
>
|
||||||
>
|
<span className="sr-only">Open menu</span>
|
||||||
<span className="sr-only">Open menu</span>
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</Button>
|
||||||
</Button>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuTrigger>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<Link
|
||||||
<Link
|
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||||
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">
|
||||||
<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" />
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import columns from "./columns";
|
||||||
import { getPlanningSentPagination } from "@/service/planning/planning";
|
import { getPlanningSentPagination } from "@/service/planning/planning";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const MedsosTable = () => {
|
const MedsosTable = () => {
|
||||||
const t = useTranslations("Planning");
|
const t = useTranslations("Planning");
|
||||||
|
|
@ -77,7 +78,7 @@ const MedsosTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,171 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
View
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
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 { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const EventTable = () => {
|
const EventTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -55,7 +56,7 @@ const EventTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,172 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
Detail
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const PressConferenceTable = () => {
|
const PressConferenceTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -68,7 +69,7 @@ const PressConferenceTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,172 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
View
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const PressReleaseTable = () => {
|
const PressReleaseTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -69,7 +70,7 @@ const PressReleaseTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -20,187 +20,193 @@ import { deleteTask } from "@/service/task";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
accessorKey: "no",
|
||||||
},
|
header: t("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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "assignmentType",
|
header: t("title"),
|
||||||
header: "Category Task",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<div>
|
||||||
const type = row.getValue("assignmentType") as { name: string };
|
<span>{row.getValue("title")}</span>
|
||||||
return <span>{type?.name}</span>;
|
{row.original.isForward && (
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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>
|
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
variant={"outline"}
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
className="ml-3 rounded-xl"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
Forward
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
)}
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
</div>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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 { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TaskTable = () => {
|
const TaskTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -83,7 +84,7 @@ const TaskTable = () => {
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import {
|
||||||
getTicketingEscalationPagination,
|
getTicketingEscalationPagination,
|
||||||
listTicketingInternal,
|
listTicketingInternal,
|
||||||
} from "@/service/communication/communication";
|
} from "@/service/communication/communication";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const CollaborationTable = () => {
|
const CollaborationTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -88,7 +89,7 @@ const CollaborationTable = () => {
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,102 +13,113 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link, useRouter } from "@/i18n/routing";
|
import { Link, useRouter } from "@/i18n/routing";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
{
|
||||||
},
|
accessorKey: "no",
|
||||||
{
|
header: t("no"),
|
||||||
accessorKey: "title",
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "createdAt",
|
header: t("question"),
|
||||||
header: "Waktu",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
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: "commentFromUserName",
|
||||||
accessorKey: "isActive",
|
header: t("sender"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case">
|
||||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
{row.getValue("commentFromUserName")}
|
||||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
</span>
|
||||||
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: "Type",
|
||||||
{
|
header: t("type"),
|
||||||
id: "actions",
|
cell: ({ row }) => {
|
||||||
accessorKey: "action",
|
const type = row.original.type;
|
||||||
header: "Actions",
|
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||||
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: "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 { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
{
|
||||||
},
|
accessorKey: "no",
|
||||||
{
|
header: t("no"),
|
||||||
accessorKey: "title",
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "createdAt",
|
header: t("question"),
|
||||||
header: "Waktu",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
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: "commentFromUserName",
|
||||||
accessorKey: "isActive",
|
header: t("sender"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case">
|
||||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
{row.getValue("commentFromUserName")}
|
||||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
</span>
|
||||||
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: "type",
|
||||||
{
|
header: t("type"),
|
||||||
id: "actions",
|
cell: ({ row }) => {
|
||||||
accessorKey: "action",
|
const type = row.original.type; // Akses properti category
|
||||||
header: "Actions",
|
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||||
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: "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,
|
getTicketingEscalationPagination,
|
||||||
listTicketingInternal,
|
listTicketingInternal,
|
||||||
} from "@/service/communication/communication";
|
} from "@/service/communication/communication";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const EscalationTable = () => {
|
const EscalationTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -87,7 +88,7 @@ const EscalationTable = () => {
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,97 +13,104 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
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 formattedDate =
|
const columns: ColumnDef<any>[] = [
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
{
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
accessorKey: "no",
|
||||||
: "-";
|
header: t("no"),
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
id: "actions",
|
header: t("question"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => (
|
||||||
header: "Actions",
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
enableHiding: false,
|
),
|
||||||
cell: ({ row }) => {
|
},
|
||||||
return (
|
{
|
||||||
<DropdownMenu>
|
accessorKey: "createdBy",
|
||||||
<DropdownMenuTrigger asChild>
|
header: t("sender"),
|
||||||
<Button
|
cell: ({ row }) => {
|
||||||
size="icon"
|
const createdBy = row.original.createdBy; // Akses properti category
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
return (
|
||||||
>
|
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||||
<span className="sr-only">Open menu</span>
|
);
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
},
|
||||||
</Button>
|
},
|
||||||
</DropdownMenuTrigger>
|
{
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
accessorKey: "sendTo",
|
||||||
<Link
|
header: t("sendto"),
|
||||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
cell: ({ row }) => {
|
||||||
>
|
const sendTo = row.original.sendTo; // Akses properti category
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
},
|
||||||
View
|
},
|
||||||
|
{
|
||||||
|
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ import {
|
||||||
} from "@/service/content/content";
|
} from "@/service/content/content";
|
||||||
import { listTicketingInternal } from "@/service/communication/communication";
|
import { listTicketingInternal } from "@/service/communication/communication";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const InternalTable = () => {
|
const InternalTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -88,7 +89,7 @@ const InternalTable = () => {
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -18,200 +18,206 @@ import Swal from "sweetalert2";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import { deleteMedia } from "@/service/content/content";
|
import { deleteMedia } from "@/service/content/content";
|
||||||
import { publishContest } from "@/service/contest/contest";
|
import { publishContest } from "@/service/contest/contest";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
|
accessorKey: "hastagCode",
|
||||||
{
|
header: t("code"),
|
||||||
id: "actions",
|
cell: ({ row }) => (
|
||||||
accessorKey: "action",
|
<div className="flex items-center gap-5">
|
||||||
header: "Actions",
|
<div className="flex-1 text-start">
|
||||||
enableHiding: false,
|
<h4
|
||||||
cell: ({ row }) => {
|
className="text-sm font-bold
|
||||||
const MySwal = withReactContent(Swal);
|
text-default-600 whitespace-nowrap mb-1"
|
||||||
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"
|
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
{row.getValue("hastagCode")}
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</h4>
|
||||||
</Button>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</div>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
),
|
||||||
{((userRoleId == 11 || userRoleId == 12) &&
|
},
|
||||||
row?.original?.isPublishForMabes != true) ||
|
{
|
||||||
(userRoleId == 3 &&
|
accessorKey: "theme",
|
||||||
userLevelNumber == 1 &&
|
header: t("title"),
|
||||||
row?.original?.isPublishForAll != true) ? (
|
cell: ({ row }) => (
|
||||||
<DropdownMenuItem
|
<div className="flex items-center gap-5">
|
||||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
<div className="flex-1 text-start">
|
||||||
onClick={() => handlePublishContest(row.original.id)}
|
<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" />
|
<span className="sr-only">Open menu</span>
|
||||||
Publish
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</DropdownMenuItem>
|
</Button>
|
||||||
) : (
|
</DropdownMenuTrigger>
|
||||||
""
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
)}
|
{((userRoleId == 11 || userRoleId == 12) &&
|
||||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
row?.original?.isPublishForMabes != true) ||
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
(userRoleId == 3 &&
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
userLevelNumber == 1 &&
|
||||||
View
|
row?.original?.isPublishForAll != true) ? (
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem
|
||||||
</Link>
|
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||||
{/* <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" />
|
<SquarePen className="w-4 h-4 me-1.5" />
|
||||||
Edit
|
Edit
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
@ -219,11 +225,14 @@ const columns: ColumnDef<any>[] = [
|
||||||
<Trash2 className="w-4 h-4 me-1.5" />
|
<Trash2 className="w-4 h-4 me-1.5" />
|
||||||
Delete
|
Delete
|
||||||
</DropdownMenuItem> */}
|
</DropdownMenuItem> */}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</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 TablePagination from "@/components/table/table-pagination";
|
||||||
import columns from "./columns";
|
import columns from "./columns";
|
||||||
import { listContest } from "@/service/contest/contest";
|
import { listContest } from "@/service/contest/contest";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TaskTable = () => {
|
const TaskTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -63,7 +64,7 @@ const TaskTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -812,7 +812,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Label className="text-xl">Penempatan file</Label>
|
<Label className="text-xl">Penempatan file</Label>
|
||||||
</div>
|
</div>
|
||||||
{files.length > 1 && (
|
{files?.length > 1 && (
|
||||||
<div className="flex flex-wrap gap-2 mt-2">
|
<div className="flex flex-wrap gap-2 mt-2">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|
|
||||||
|
|
@ -607,5 +607,34 @@
|
||||||
},
|
},
|
||||||
"Curation": {
|
"Curation": {
|
||||||
"content-curation": "Content 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": {
|
"Curation": {
|
||||||
"content-curation": "Kurasi Konten"
|
"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