fix:table blog,task,planning,content,schedule,communication

This commit is contained in:
Anang Yusman 2024-12-12 01:28:57 +07:00
parent c1b645e80b
commit a2c1269bdd
83 changed files with 5242 additions and 6680 deletions

View File

@ -0,0 +1,188 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
const BlogTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await paginationBlog(limit, page - 1, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default BlogTable;

View File

@ -0,0 +1,117 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => <span>{row.getValue("no")}</span>,
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }) => (
<span className="whitespace-normal">{row.getValue("title")}</span>
),
},
{
accessorKey: "categoryName",
header: "Category",
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
: "-";
return <span className="whitespace-nowrap">{formattedDate}</span>;
},
},
{
accessorKey: "tags",
header: "Tag",
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
},
{
accessorKey: "statusName",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
diterima: "bg-green-100 text-green-600",
"menunggu review": "bg-orange-100 text-orange-600",
};
// Mengambil `statusName` dari data API
const status = row.getValue("statusName") as string;
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
// Gunakan `statusName` untuk pencocokan
const statusStyles =
statusColors[statusName] || "bg-gray-100 text-gray-600";
return (
<Badge className={cn("rounded-full px-5", statusStyles)}>
{status} {/* Tetap tampilkan nilai asli */}
</Badge>
);
},
},
{
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">
<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 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>
<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;

View File

@ -1,28 +1,30 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import BlogTable from "./components/blog-table";
import { Plus } from "lucide-react";
import { Button } from "@/components/ui/button";
import { UploadIcon } from "lucide-react";
import BlogTable from "./table/blog-table";
const BlogPage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Table Indeks
</div>
<div>
<Button color="primary" className="text-white">
<UploadIcon />
Tambah Indeks
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Table Indeks
</div>
<div className="flex-none">
<Button fullWidth size="md">
<Plus className="w-6 h-6 me-1.5" />
Add Index
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<BlogTable />
</CardContent>

View File

@ -1,338 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
category: string;
createdAt: string;
tags: string;
statusName: string;
};
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "categoryName",
header: "Kategori ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah ",
cell: ({ row }) => (
<span className="whitespace-nowrap">
{" "}
{`${new Date(row.getValue("createdAt")).getDate()}/${
new Date(row.getValue("createdAt")).getMonth() + 1
}/${new Date(row.getValue("createdAt")).getFullYear()} ${new Date(
row.getValue("createdAt")
).getHours()}:${new Date(row.getValue("createdAt")).getMinutes()}`}
</span>
),
},
{
accessorKey: "tags",
header: "Tag ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("tags")}</span>
),
},
{
accessorKey: "statusName",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("statusName")}
</span>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const BlogTable = () => {
const [blogTable, setBlogTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: blogTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await paginationBlog(limit, page);
const data = res.data.data.content
.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
categoryName: item.categoryName,
tags: item.tags,
assignmentType: item.assignmentType?.name || "-",
createdAt: item.createdAt,
statusName: item.statusName,
}))
.sort(
(a: CompanyData, b: CompanyData) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
); // Mengurutkan dari terbaru ke terlama berdasarkan `createdAt`
setBlogTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default BlogTable;

View File

@ -0,0 +1,230 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import {
listDataAudio,
listDataImage,
listDataVideo,
} from "@/service/content/content";
import {
getTicketingCollaborationPagination,
getTicketingEscalationPagination,
listTicketingInternal,
} from "@/service/communication/communication";
const EscalationTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await getTicketingCollaborationPagination(
page - 1,
limit,
""
);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default EscalationTable;

View File

@ -0,0 +1,133 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Question",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "commentFromUserName",
header: "CreateBy",
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("commentFromUserName")}
</h4>
</div>
</div>
),
},
{
accessorKey: "Type",
header: "SendTo",
cell: ({ row }) => {
const type = row.original.type; // Akses properti category
return <span className="whitespace-nowrap">{type?.name || "N/A"}</span>;
},
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
: "-";
return <span className="whitespace-nowrap">{formattedDate}</span>;
},
},
{
accessorKey: "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: "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">
<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 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>
<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;

View File

@ -1,298 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
UploadIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
title: string;
commentFromUserName: string;
type: string;
date: string;
status: string;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { Link } from "@/components/navigation";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "title",
header: "Pertanyaan",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "commentFromUserName",
header: "Pengirim ",
cell: ({ row }) => (
<span className="whitespace-nowrap">
{row.getValue("commentFromUserName")}
</span>
),
},
{
accessorKey: "type",
header: "Channel",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("type")}</span>
),
},
{
accessorKey: "date",
header: "Waktu ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("date")}</span>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("status")}
</span>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const CollaborationTable = () => {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 6,
});
const table = useReactTable({
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div className="flex flex-row items-center gap-3">
<div>
<Link href={"/communication/collaboration/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Kolaborasi Baru
</Button>
</Link>
</div>
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default CollaborationTable;

View File

@ -1,16 +0,0 @@
export const data = [
{
title: "Pertanyaan Terkait Jadwal",
commentFromUserName: "usertest-spv",
type: "Konten Media Hub",
date: "15/10/2024 9:11",
status: "Open",
},
{
title: "Pertanyaan Terkait Jadwal",
commentFromUserName: "usertest-journalist",
type: "Konten Media Hub",
date: "15/10/2024 9:11",
status: "Open",
},
];

View File

@ -0,0 +1,133 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Question",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "commentFromUserName",
header: "CreateBY",
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("commentFromUserName")}
</h4>
</div>
</div>
),
},
{
accessorKey: "type",
header: "SendTo",
cell: ({ row }) => {
const type = row.original.type; // Akses properti category
return <span className="whitespace-nowrap">{type?.name || "N/A"}</span>;
},
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
: "-";
return <span className="whitespace-nowrap">{formattedDate}</span>;
},
},
{
accessorKey: "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: "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">
<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 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>
<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;

View File

@ -1,16 +0,0 @@
export const data = [
{
title: "Pertanyaan Terkait Jadwal",
commentFromUserName: "usertest-spv",
type: "Konten Media Hub",
date: "15/10/2024 9:11",
status: "Open",
},
{
title: "Pertanyaan Terkait Jadwal",
commentFromUserName: "usertest-journalist",
type: "Konten Media Hub",
date: "15/10/2024 9:11",
status: "Open",
},
];

View File

@ -26,7 +26,6 @@ import {
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
@ -36,113 +35,38 @@ import {
Trash2,
TrendingDown,
TrendingUp,
UploadIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
title: string;
commentFromUserName: string;
type: string;
date: string;
status: string;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "title",
header: "Pertanyaan",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "commentFromUserName",
header: "Pengirim ",
cell: ({ row }) => (
<span className="whitespace-nowrap">
{row.getValue("commentFromUserName")}
</span>
),
},
{
accessorKey: "type",
header: "Channel",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("type")}</span>
),
},
{
accessorKey: "date",
header: "Waktu ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("date")}</span>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("status")}
</span>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import {
listDataAudio,
listDataImage,
listDataVideo,
} from "@/service/content/content";
import {
getTicketingEscalationPagination,
listTicketingInternal,
} from "@/service/communication/communication";
const EscalationTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
@ -152,11 +76,27 @@ const EscalationTable = () => {
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 6,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data,
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
@ -176,9 +116,37 @@ const EscalationTable = () => {
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await getTicketingEscalationPagination(page - 1, limit, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
@ -191,7 +159,6 @@ const EscalationTable = () => {
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
@ -205,7 +172,7 @@ const EscalationTable = () => {
/>
</div>
</div>
<Table className="overflow-hidden">
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
@ -246,41 +213,11 @@ const EscalationTable = () => {
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};

View File

@ -0,0 +1,118 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Question",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdBy",
header: "CreateBy",
cell: ({ row }) => {
const createdBy = row.original.createdBy; // Akses properti category
return (
<span className="whitespace-nowrap">
{createdBy?.fullname || "N/A"}
</span>
);
},
},
{
accessorKey: "sendTo",
header: "SendTo",
cell: ({ row }) => {
const sendTo = row.original.sendTo; // Akses properti category
return (
<span className="whitespace-nowrap">{sendTo?.fullname || "N/A"}</span>
);
},
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
: "-";
return <span className="whitespace-nowrap">{formattedDate}</span>;
},
},
{
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">
<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 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>
<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;

View File

@ -0,0 +1,224 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import {
listDataAudio,
listDataImage,
listDataVideo,
} from "@/service/content/content";
import { listTicketingInternal } from "@/service/communication/communication";
const TableAudio = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await listTicketingInternal(page - 1, limit, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableAudio;

View File

@ -1,14 +0,0 @@
export const data = [
{
title: "Pertanyaan Terkait Jadwal",
createBy: "usertest-spv",
sendTo: "Mabes Polri - approver",
date: "15/10/2024 9:11",
},
{
title: "Pertanyaan Terkait Jadwal",
createBy: "usertest-spv",
sendTo: "Mabes Polri - approver",
date: "15/10/2024 9:11",
},
];

View File

@ -1,325 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
UploadIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
createdBy: string;
commentToUserName: string;
createdAt: string;
};
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { listTicketingInternal } from "@/service/communication/communication";
import { Link } from "@/components/navigation";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Pertanyaan",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdBy",
header: "Pengirim ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdBy")}</span>
),
},
{
accessorKey: "sendTo",
header: "Penerima",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("sendTo")}</span>
),
},
{
accessorKey: "createdAt",
header: "Waktu ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const InternalTable = () => {
const [internalTable, setInternalTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: internalTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await listTicketingInternal(limit, page);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
commentFromUserName: item.commentFromUserName,
commentToUserName: item.commentToUserName,
createdAt: item.createdAt,
}));
setInternalTable(data);
setTotalPage(res.data.totalPages);
console.log(res?.data?.data);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div className="flex flex-row items-center gap-3">
<div>
<Link href={"/communication/internal/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Pertanyaan Baru
</Button>
</Link>
</div>
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default InternalTable;

View File

@ -2,10 +2,11 @@ import { StatisticsBlock } from "@/components/blocks/statistics-block";
import DashboardDropdown from "@/components/dashboard-dropdown";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import InternalTable from "./internal/table-internal/internal-table";
import InternalTable from "./internal/components/internal-table";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import CollaborationTable from "./collaboration/components/collabroation-table";
import EscalationTable from "./escalation/table-escalation/escalation-table";
import CollaborationTable from "./collaboration/table-collaboration/collabroation-table";
const CommunicationPage = async () => {
return (

View File

@ -0,0 +1,159 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "categoryName",
header: "Category Name",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
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: "creatorGroup",
header: "Creator Group",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "creatorName",
header: "Sumber",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorName")}</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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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;

View File

@ -0,0 +1,235 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { listDataImage, listDataVideo } from "@/service/content/content";
const TableImage = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataVideo(
limit,
page - 1,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString,
""
);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableImage;

View File

@ -1,11 +1,11 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import TableImage from "./table-video";
import TableImage from "./components/table-video";
import { UploadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Icon } from "@iconify/react/dist/iconify.js";
import TableVideo from "./table-video";
import TableVideo from "./components/table-video";
import { Link } from "@/components/navigation";
const ReactTableVideoPage = () => {
@ -50,26 +50,28 @@ const ReactTableVideoPage = () => {
</div>
</div>
</Card>
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Video
</div>
<div>
<Link href={"/content/audio-visual/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Video
</Button>
</Link>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Video Dengan AI
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Video
</div>
<div className="flex-none">
<Link href={"/content/audio-visual/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Video
</Button>
</Link>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Video Dengan AI
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TableVideo />
</CardContent>

View File

@ -1,382 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Trash2,
} from "lucide-react";
import { title } from "process";
import { getCookiesDecrypt } from "@/lib/utils";
import { listDataVideo } from "@/service/content/content";
export type CompanyData = {
no: number;
title: string;
categoryName: string;
createdAt: string;
creatorGroup: string;
publishedOn: string;
isPublish: any;
isPublishOnPolda: any;
isDone: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "categoryName",
header: "Kategori",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah",
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: "creatorGroup",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "publishedOn",
header: "Penempatan File",
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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TableVideo = () => {
const [videoTable, setVideoTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0, // Halaman pertama
pageSize: 10, // Jumlah baris per halaman
});
const [page, setPage] = React.useState(1); // Halaman aktif
const [totalPage, setTotalPage] = React.useState(1); // Total halaman
const [limit, setLimit] = React.useState(6); // Jumlah baris per halaman
const [search, setSearch] = React.useState(title);
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: videoTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataVideo(
limit,
page,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString
);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
categoryName: item.categoryName,
creatorGroup: item.creatorGroup,
assignmentType: item.assignmentType?.name || "-",
createdAt: item.createdAt,
isDone: item.isDone,
publishedOn: item.publishedOn,
isPublish: item.isPublish,
isPublishOnPolda: item.isPublishOnPolda,
}));
setVideoTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full">
<div className="flex items-center py-4 px-5">
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TableVideo;

View File

@ -0,0 +1,159 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "categoryName",
header: "Category Name",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
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: "creatorGroup",
header: "Creator Group",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "creatorName",
header: "Sumber",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorName")}</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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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;

View File

@ -0,0 +1,239 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import {
listDataAudio,
listDataImage,
listDataVideo,
} from "@/service/content/content";
const TableAudio = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataAudio(
limit,
page - 1,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString,
""
);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableAudio;

View File

@ -1,10 +1,11 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { UploadIcon } from "lucide-react";
import { Link, UploadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Icon } from "@iconify/react/dist/iconify.js";
import TableAudio from "./table-audio";
import TableAudio from "./components/table-audio";
import TableVideo from "../audio-visual/components/table-video";
const ReactTableAudioPage = () => {
return (
@ -48,24 +49,26 @@ const ReactTableAudioPage = () => {
</div>
</div>
</Card>
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Audio
</div>
<div>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Audio
</Button>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Audio Dengan AI
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Audio
</div>
<div className="flex-none">
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Audio
</Button>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Audio Dengan AI
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TableAudio />
</CardContent>

View File

@ -1,180 +0,0 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
export type DataProps = {
id: string | number;
order: string;
customer: {
name: string;
};
date: string;
quantity: number;
amount: string;
status: "paid" | "due" | "canceled";
action: React.ReactNode;
};
export const columns: ColumnDef<DataProps>[] = [
// {
// id: "select",
// header: ({ table }) => (
// <Checkbox
// checked={
// table.getIsAllPageRowsSelected() ||
// (table.getIsSomePageRowsSelected() && "indeterminate")
// }
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
// aria-label="Select all"
// />
// ),
// cell: ({ row }) => (
// <div className="xl:w-16">
// <Checkbox
// checked={row.getIsSelected()}
// onCheckedChange={(value) => row.toggleSelected(!!value)}
// aria-label="Select row"
// />
// </div>
// ),
// enableSorting: false,
// enableHiding: false,
// },
{
accessorKey: "id",
header: "No",
cell: ({ row }) => <span>{row.getValue("id")}</span>,
},
{
accessorKey: "order",
header: "Judul",
cell: ({ row }) => (
<div className="w-52">
<span>{row.getValue("order")}</span>,
</div>
),
},
{
accessorKey: "customer",
header: "Kategory",
cell: ({ row }) => {
const user = row.original.customer;
return (
<div className="font-medium text-card-foreground/80">
<div className="flex gap-3 items-center">
<span className="text-sm text-default-600 whitespace-nowrap">
{user?.name ?? "Unknown User"}
</span>
</div>
</div>
);
},
},
{
accessorKey: "date",
header: "Tanggal unggah",
cell: ({ row }) => {
return <span>{row.getValue("date")}</span>;
},
},
{
accessorKey: "quantity",
header: "Kreator",
cell: ({ row }) => {
return <span>{row.getValue("quantity")}</span>;
},
},
{
accessorKey: "amount",
header: "Sumber",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Penempatan File",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
paid: "bg-success/20 text-success",
due: "bg-warning/20 text-warning",
canceled: "bg-destructive/20 text-destructive",
};
const status = row.getValue<string>("status");
const statusStyles = statusColors[status] || "default";
return (
<Badge className={cn("rounded-full px-5", statusStyles)}>
{status}{" "}
</Badge>
);
},
},
{
accessorKey: "amount",
header: "Kurasi Konten",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Saran",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];

View File

@ -1,184 +0,0 @@
import { DataProps } from "./columns";
export const data: DataProps[] = [
{
id: 1,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "3/26/2022",
quantity: 13,
amount: "$1779.53",
status: "paid",
action: null,
},
{
id: 2,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "2/6/2022",
quantity: 13,
amount: "$2215.78",
status: "due",
action: null,
},
{
id: 3,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "9/6/2021",
quantity: 1,
amount: "$3183.60",
status: "due",
action: null,
},
{
id: 4,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "11/7/2021",
quantity: 13,
amount: "$2587.86",
status: "canceled",
action: null,
},
{
id: 5,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Rachel Brown",
},
date: "5/6/2022",
quantity: 12,
amount: "$3840.73",
status: "paid",
action: null,
},
{
id: 6,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Megan Taylor",
},
date: "2/14/2022",
quantity: 12,
amount: "$4764.18",
status: "canceled",
action: null,
},
{
id: 7,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Sophie Clark",
},
date: "7/30/2022",
quantity: 6,
amount: "$2875.05",
status: "paid",
action: null,
},
{
id: 8,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Natalie Martin",
},
date: "6/30/2022",
quantity: 9,
amount: "$2491.02",
status: "due",
action: null,
},
{
id: 9,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Hannah Lewis",
},
date: "8/9/2022",
quantity: 8,
amount: "$3006.95",
status: "due",
action: null,
},
{
id: 10,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Lisa White",
},
date: "8/4/2022",
quantity: 12,
amount: "$2160.32",
status: "paid",
action: null,
},
{
id: 11,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Emma Walker",
},
date: "4/5/2022",
quantity: 8,
amount: "$1272.66",
status: "paid",
action: null,
},
{
id: 12,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "8/9/2022",
quantity: 2,
amount: "$4327.86",
status: "canceled",
action: null,
},
{
id: 13,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 11,
amount: "$3671.81",
status: "canceled",
action: null,
},
{
id: 14,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 2,
amount: "$3401.82",
status: "paid",
action: null,
},
{
id: 15,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "5/20/2022",
quantity: 4,
amount: "$2387.49",
status: "canceled",
action: null,
},
];

View File

@ -1,382 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Trash2,
} from "lucide-react";
import { title } from "process";
import { getCookiesDecrypt } from "@/lib/utils";
import { listDataAudio } from "@/service/content/content";
export type CompanyData = {
no: number;
title: string;
categoryName: string;
createdAt: string;
creatorGroup: string;
publishedOn: string;
isPublish: any;
isPublishOnPolda: any;
isDone: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "categoryName",
header: "Kategori",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah",
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: "creatorGroup",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "publishedOn",
header: "Penempatan File",
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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TableAudio = () => {
const [videoTable, setVideoTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0, // Halaman pertama
pageSize: 10, // Jumlah baris per halaman
});
const [page, setPage] = React.useState(1); // Halaman aktif
const [totalPage, setTotalPage] = React.useState(1); // Total halaman
const [limit, setLimit] = React.useState(6); // Jumlah baris per halaman
const [search, setSearch] = React.useState(title);
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: videoTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataAudio(
limit,
page,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString
);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
categoryName: item.categoryName,
creatorGroup: item.creatorGroup,
assignmentType: item.assignmentType?.name || "-",
createdAt: item.createdAt,
isDone: item.isDone,
publishedOn: item.publishedOn,
isPublish: item.isPublish,
isPublishOnPolda: item.isPublishOnPolda,
}));
setVideoTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full">
<div className="flex items-center py-4 px-5">
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TableAudio;

View File

@ -1,52 +0,0 @@
import { Button } from '@/components/ui/button';
import { Table } from '@tanstack/react-table';
import { ChevronLeft, ChevronRight } from 'lucide-react';
interface DataTablePaginationProps {
table: Table<any>;
}
const TablePagination = ({ table }: DataTablePaginationProps) => {
return (
<div className="flex items-center justify-end py-4 px-10">
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex items-center gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className='w-8 h-8'
>
<ChevronLeft className='w-4 h-4' />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className='w-8 h-8'
>
<ChevronRight className='w-4 h-4' />
</Button>
</div>
</div>
);
};
export default TablePagination;

View File

@ -0,0 +1,159 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "categoryName",
header: "Category Name",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
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: "creatorGroup",
header: "Creator Group",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "creatorName",
header: "Sumber",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorName")}</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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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;

View File

@ -0,0 +1,235 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { listDataImage } from "@/service/content/content";
const TableImage = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataImage(
limit,
page - 1,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString,
""
);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableImage;

View File

@ -1,11 +1,12 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import TableImage from "./table-image";
import TableImage from "./components/table-image";
import { UploadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Link } from "@/components/navigation";
import TicketingTable from "../../ticketing/components/table";
const ReactTableImagePage = () => {
return (
@ -49,26 +50,28 @@ const ReactTableImagePage = () => {
</div>
</div>
</Card>
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Foto
</div>
<div>
<Link href={"/content/image/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Foto
</Button>
</Link>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Foto Dengan AI
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Foto
</div>
<div className="flex-none">
<Link href={"/content/image/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Foto
</Button>
</Link>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Foto Dengan AI
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TableImage />
</CardContent>

View File

@ -1,394 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Trash2,
} from "lucide-react";
import { title } from "process";
import { getCookiesDecrypt } from "@/lib/utils";
import { listDataImage } from "@/service/content/content";
import page from "../page";
export type CompanyData = {
no: number;
title: string;
categoryName: string;
createdAt: string;
creatorGroup: string;
publishedOn: string;
isPublish: any;
isPublishOnPolda: any;
isDone: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "categoryName",
header: "Kategori",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah",
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: "creatorGroup",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "publishedOn",
header: "Penempatan File",
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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TableImage = () => {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [imageTable, setImageTable] = React.useState<CompanyData[]>([]);
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0, // Halaman pertama
pageSize: 10, // Jumlah baris per halaman
});
const [totalPage, setTotalPage] = React.useState<number>(10);
const [limit, setLimit] = React.useState<number>(10); // Jumlah baris per halaman
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: imageTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});
React.useEffect(() => {
initState();
}, [limit]);
async function initState() {
try {
const isForSelf = Number(roleId) === 4;
const res = await listDataImage(
pagination.pageSize, // Ambil nilai dari pagination.pageSize
pagination.pageIndex + 1, // API sering menggunakan page 1-based
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString
);
setupData(res.data?.data);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
function setupData(rawData: {
content: any[];
totalPages: number;
totalElements: number;
}) {
if (rawData?.content) {
const data: CompanyData[] = rawData.content.map((item, index) => ({
no: pagination.pageIndex * pagination.pageSize + index + 1,
title: item.title,
categoryName: item.categoryName,
creatorGroup: item.creatorGroup,
createdAt: item.createdAt,
isDone: item.isDone,
publishedOn: item.publishedOn,
isPublish: item.isPublish,
isPublishOnPolda: item.isPublishOnPolda,
}));
setImageTable(data);
setTotalPage(rawData.totalPages);
console.log(data, "dataImage");
}
}
return (
<div className="w-full">
<div className="flex items-center py-4 px-5">
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TableImage;

View File

@ -0,0 +1,108 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
interface Category {
id: number;
name: string;
description: string;
}
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "contentTag",
header: "Tag",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
),
},
{
accessorKey: "contentType",
header: "Content Type",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
),
},
{
accessorKey: "category",
header: "Kategori",
cell: ({ row }) => {
const category = row.original.category; // Akses properti category
return (
<span className="whitespace-nowrap">{category?.name || "N/A"}</span>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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;

View File

@ -0,0 +1,224 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import {
listDataImage,
listDataTeks,
listNulisAI,
} from "@/service/content/content";
const TableTeks = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listNulisAI(limit, page - 1, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableTeks;

View File

@ -1,11 +1,12 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import TableImage from "./table-nulis";
import TableImage from "./components/table-nulis";
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Icon } from "@iconify/react/dist/iconify.js";
import TableNulis from "./table-nulis";
import TableNulis from "./components/table-nulis";
import TableAudio from "../audio/components/table-audio";
const ReactTableNulisPage = () => {
return (
@ -49,20 +50,22 @@ const ReactTableNulisPage = () => {
</div>
</div>
</Card>
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Nulis Ai
</div>
<div>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Nulis AI
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Nulis Ai
</div>
<div>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Nulis AI
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TableNulis />
</CardContent>

View File

@ -1,180 +0,0 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
export type DataProps = {
id: string | number;
order: string;
customer: {
name: string;
};
date: string;
quantity: number;
amount: string;
status: "paid" | "due" | "canceled";
action: React.ReactNode;
};
export const columns: ColumnDef<DataProps>[] = [
// {
// id: "select",
// header: ({ table }) => (
// <Checkbox
// checked={
// table.getIsAllPageRowsSelected() ||
// (table.getIsSomePageRowsSelected() && "indeterminate")
// }
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
// aria-label="Select all"
// />
// ),
// cell: ({ row }) => (
// <div className="xl:w-16">
// <Checkbox
// checked={row.getIsSelected()}
// onCheckedChange={(value) => row.toggleSelected(!!value)}
// aria-label="Select row"
// />
// </div>
// ),
// enableSorting: false,
// enableHiding: false,
// },
{
accessorKey: "id",
header: "No",
cell: ({ row }) => <span>{row.getValue("id")}</span>,
},
{
accessorKey: "order",
header: "Judul",
cell: ({ row }) => (
<div className="w-52">
<span>{row.getValue("order")}</span>,
</div>
),
},
{
accessorKey: "customer",
header: "Kategory",
cell: ({ row }) => {
const user = row.original.customer;
return (
<div className="font-medium text-card-foreground/80">
<div className="flex gap-3 items-center">
<span className="text-sm text-default-600 whitespace-nowrap">
{user?.name ?? "Unknown User"}
</span>
</div>
</div>
);
},
},
{
accessorKey: "date",
header: "Tanggal unggah",
cell: ({ row }) => {
return <span>{row.getValue("date")}</span>;
},
},
{
accessorKey: "quantity",
header: "Kreator",
cell: ({ row }) => {
return <span>{row.getValue("quantity")}</span>;
},
},
{
accessorKey: "amount",
header: "Sumber",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Penempatan File",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
paid: "bg-success/20 text-success",
due: "bg-warning/20 text-warning",
canceled: "bg-destructive/20 text-destructive",
};
const status = row.getValue<string>("status");
const statusStyles = statusColors[status] || "default";
return (
<Badge className={cn("rounded-full px-5", statusStyles)}>
{status}{" "}
</Badge>
);
},
},
{
accessorKey: "amount",
header: "Kurasi Konten",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Saran",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];

View File

@ -1,184 +0,0 @@
import { DataProps } from "./columns";
export const data: DataProps[] = [
{
id: 1,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "3/26/2022",
quantity: 13,
amount: "$1779.53",
status: "paid",
action: null,
},
{
id: 2,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "2/6/2022",
quantity: 13,
amount: "$2215.78",
status: "due",
action: null,
},
{
id: 3,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "9/6/2021",
quantity: 1,
amount: "$3183.60",
status: "due",
action: null,
},
{
id: 4,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "11/7/2021",
quantity: 13,
amount: "$2587.86",
status: "canceled",
action: null,
},
{
id: 5,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Rachel Brown",
},
date: "5/6/2022",
quantity: 12,
amount: "$3840.73",
status: "paid",
action: null,
},
{
id: 6,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Megan Taylor",
},
date: "2/14/2022",
quantity: 12,
amount: "$4764.18",
status: "canceled",
action: null,
},
{
id: 7,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Sophie Clark",
},
date: "7/30/2022",
quantity: 6,
amount: "$2875.05",
status: "paid",
action: null,
},
{
id: 8,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Natalie Martin",
},
date: "6/30/2022",
quantity: 9,
amount: "$2491.02",
status: "due",
action: null,
},
{
id: 9,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Hannah Lewis",
},
date: "8/9/2022",
quantity: 8,
amount: "$3006.95",
status: "due",
action: null,
},
{
id: 10,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Lisa White",
},
date: "8/4/2022",
quantity: 12,
amount: "$2160.32",
status: "paid",
action: null,
},
{
id: 11,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Emma Walker",
},
date: "4/5/2022",
quantity: 8,
amount: "$1272.66",
status: "paid",
action: null,
},
{
id: 12,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "8/9/2022",
quantity: 2,
amount: "$4327.86",
status: "canceled",
action: null,
},
{
id: 13,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 11,
amount: "$3671.81",
status: "canceled",
action: null,
},
{
id: 14,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 2,
amount: "$3401.82",
status: "paid",
action: null,
},
{
id: 15,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "5/20/2022",
quantity: 4,
amount: "$2387.49",
status: "canceled",
action: null,
},
];

View File

@ -1,328 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { data } from "./data";
import TablePagination from "./table-pagination";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Trash2,
} from "lucide-react";
import { title } from "process";
import { getCookiesDecrypt } from "@/lib/utils";
import { listDataImage, listNulisAI } from "@/service/content/content";
import page from "../page";
export type CompanyData = {
no: number;
title: string;
description: string;
tags: string;
category: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "description",
header: "Deskripsi",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("description")}</span>
),
},
{
accessorKey: "tags",
header: "Tag",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("tags")}</span>
),
},
{
accessorKey: "category",
header: "Kategori",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("category")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TableNulis = () => {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [nulisTable, setNulisTable] = React.useState<CompanyData[]>([]);
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0, // Halaman pertama
pageSize: 10, // Jumlah baris per halaman
});
const [totalPage, setTotalPage] = React.useState<number>(10);
const [limit, setLimit] = React.useState<number>(10); // Jumlah baris per halaman
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: nulisTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});
React.useEffect(() => {
initState();
}, [limit]);
async function initState() {
try {
const isForSelf = Number(roleId) === 4;
const res = await listNulisAI(
pagination.pageSize,
pagination.pageIndex + 1
);
setupData(res.data?.data);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
function setupData(rawData: {
content: any[];
totalPages: number;
totalElements: number;
}) {
if (rawData?.content) {
const data: CompanyData[] = rawData.content.map((item, index) => ({
no: pagination.pageIndex * pagination.pageSize + index + 1,
title: item.title,
description: item.description,
tags: item.tags,
category: item.category.name,
isDone: item.isDone,
publishedOn: item.publishedOn,
isPublish: item.isPublish,
isPublishOnPolda: item.isPublishOnPolda,
}));
setNulisTable(data);
setTotalPage(rawData.totalPages);
console.log(data, "dataImage");
}
}
return (
<div className="w-full">
<div className="flex items-center py-4 px-5">
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TableNulis;

View File

@ -1,52 +0,0 @@
import { Button } from '@/components/ui/button';
import { Table } from '@tanstack/react-table';
import { ChevronLeft, ChevronRight } from 'lucide-react';
interface DataTablePaginationProps {
table: Table<any>;
}
const TablePagination = ({ table }: DataTablePaginationProps) => {
return (
<div className="flex items-center justify-end py-4 px-10">
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex items-center gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className='w-8 h-8'
>
<ChevronLeft className='w-4 h-4' />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className='w-8 h-8'
>
<ChevronRight className='w-4 h-4' />
</Button>
</div>
</div>
);
};
export default TablePagination;

View File

@ -0,0 +1,159 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "categoryName",
header: "Category Name",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Upload Date",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
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: "creatorGroup",
header: "Creator Group",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "creatorName",
header: "Sumber",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorName")}</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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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;

View File

@ -0,0 +1,235 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn, getCookiesDecrypt } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { listDataImage, listDataTeks } from "@/service/content/content";
const TableTeks = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const isForSelf = Number(roleId) == 4;
const res = await listDataTeks(
limit,
page - 1,
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString,
""
);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TableTeks;

View File

@ -1,11 +1,11 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import TableImage from "./table-teks";
import TableImage from "./components/table-teks";
import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Icon } from "@iconify/react/dist/iconify.js";
import TableTeks from "./table-teks";
import TableTeks from "./components/table-teks";
const ReactTableTeksPage = () => {
return (
@ -49,24 +49,26 @@ const ReactTableTeksPage = () => {
</div>
</div>
</Card>
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Teks
</div>
<div>
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Teks
</Button>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Teks Dengan AI
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Konten Teks
</div>
<div className="flex-none">
<Button color="primary" className="text-white">
<UploadIcon />
Unggah Teks
</Button>
<Button color="primary" className="text-white ml-3">
<UploadIcon />
Unggah Teks Dengan AI
</Button>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TableTeks />
</CardContent>

View File

@ -1,180 +0,0 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
export type DataProps = {
id: string | number;
order: string;
customer: {
name: string;
};
date: string;
quantity: number;
amount: string;
status: "paid" | "due" | "canceled";
action: React.ReactNode;
};
export const columns: ColumnDef<DataProps>[] = [
// {
// id: "select",
// header: ({ table }) => (
// <Checkbox
// checked={
// table.getIsAllPageRowsSelected() ||
// (table.getIsSomePageRowsSelected() && "indeterminate")
// }
// onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
// aria-label="Select all"
// />
// ),
// cell: ({ row }) => (
// <div className="xl:w-16">
// <Checkbox
// checked={row.getIsSelected()}
// onCheckedChange={(value) => row.toggleSelected(!!value)}
// aria-label="Select row"
// />
// </div>
// ),
// enableSorting: false,
// enableHiding: false,
// },
{
accessorKey: "id",
header: "No",
cell: ({ row }) => <span>{row.getValue("id")}</span>,
},
{
accessorKey: "order",
header: "Judul",
cell: ({ row }) => (
<div className="w-52">
<span>{row.getValue("order")}</span>,
</div>
),
},
{
accessorKey: "customer",
header: "Kategory",
cell: ({ row }) => {
const user = row.original.customer;
return (
<div className="font-medium text-card-foreground/80">
<div className="flex gap-3 items-center">
<span className="text-sm text-default-600 whitespace-nowrap">
{user?.name ?? "Unknown User"}
</span>
</div>
</div>
);
},
},
{
accessorKey: "date",
header: "Tanggal unggah",
cell: ({ row }) => {
return <span>{row.getValue("date")}</span>;
},
},
{
accessorKey: "quantity",
header: "Kreator",
cell: ({ row }) => {
return <span>{row.getValue("quantity")}</span>;
},
},
{
accessorKey: "amount",
header: "Sumber",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Penempatan File",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
paid: "bg-success/20 text-success",
due: "bg-warning/20 text-warning",
canceled: "bg-destructive/20 text-destructive",
};
const status = row.getValue<string>("status");
const statusStyles = statusColors[status] || "default";
return (
<Badge className={cn("rounded-full px-5", statusStyles)}>
{status}{" "}
</Badge>
);
},
},
{
accessorKey: "amount",
header: "Kurasi Konten",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
accessorKey: "amount",
header: "Saran",
cell: ({ row }) => {
return <span>{row.getValue("amount")}</span>;
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];

View File

@ -1,184 +0,0 @@
import { DataProps } from "./columns";
export const data: DataProps[] = [
{
id: 1,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "3/26/2022",
quantity: 13,
amount: "$1779.53",
status: "paid",
action: null,
},
{
id: 2,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "2/6/2022",
quantity: 13,
amount: "$2215.78",
status: "due",
action: null,
},
{
id: 3,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "9/6/2021",
quantity: 1,
amount: "$3183.60",
status: "due",
action: null,
},
{
id: 4,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Liputan Kegiatan",
},
date: "11/7/2021",
quantity: 13,
amount: "$2587.86",
status: "canceled",
action: null,
},
{
id: 5,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Rachel Brown",
},
date: "5/6/2022",
quantity: 12,
amount: "$3840.73",
status: "paid",
action: null,
},
{
id: 6,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Megan Taylor",
},
date: "2/14/2022",
quantity: 12,
amount: "$4764.18",
status: "canceled",
action: null,
},
{
id: 7,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Sophie Clark",
},
date: "7/30/2022",
quantity: 6,
amount: "$2875.05",
status: "paid",
action: null,
},
{
id: 8,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Natalie Martin",
},
date: "6/30/2022",
quantity: 9,
amount: "$2491.02",
status: "due",
action: null,
},
{
id: 9,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Hannah Lewis",
},
date: "8/9/2022",
quantity: 8,
amount: "$3006.95",
status: "due",
action: null,
},
{
id: 10,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Lisa White",
},
date: "8/4/2022",
quantity: 12,
amount: "$2160.32",
status: "paid",
action: null,
},
{
id: 11,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Emma Walker",
},
date: "4/5/2022",
quantity: 8,
amount: "$1272.66",
status: "paid",
action: null,
},
{
id: 12,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "8/9/2022",
quantity: 2,
amount: "$4327.86",
status: "canceled",
action: null,
},
{
id: 13,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 11,
amount: "$3671.81",
status: "canceled",
action: null,
},
{
id: 14,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "2/10/2022",
quantity: 2,
amount: "$3401.82",
status: "paid",
action: null,
},
{
id: 15,
order: "Pertemuan PPID Satker Mabes Polri Langkah Strate",
customer: {
name: "Jenny Wilson",
},
date: "5/20/2022",
quantity: 4,
amount: "$2387.49",
status: "canceled",
action: null,
},
];

View File

@ -1,397 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { data } from "./data";
import TablePagination from "./table-pagination";
import { Button } from "@/components/ui/button";
import { format } from "date-fns";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Trash2,
} from "lucide-react";
import { title } from "process";
import { getCookiesDecrypt } from "@/lib/utils";
import { listDataImage, listDataTeks } from "@/service/content/content";
import page from "../page";
export type CompanyData = {
no: number;
title: string;
categoryName: string;
createdAt: string;
creatorGroup: string;
publishedOn: string;
isPublish: any;
isPublishOnPolda: any;
isDone: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "categoryName",
header: "Kategori",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah",
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: "creatorGroup",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("creatorGroup")}</span>
),
},
{
accessorKey: "publishedOn",
header: "Penempatan File",
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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TableTeks = () => {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [imageTable, setImageTable] = React.useState<CompanyData[]>([]);
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0, // Halaman pertama
pageSize: 10, // Jumlah baris per halaman
});
const [totalPage, setTotalPage] = React.useState<number>(1);
const [limit, setLimit] = React.useState<number>(10); // Jumlah baris per halaman
const [search, setSearch] = React.useState<string>("");
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState();
const [categoryFilter, setCategoryFilter] = React.useState([]);
const [statusFilter, setStatusFilter] = React.useState([]);
const [startDateString, setStartDateString] = React.useState("");
const [endDateString, setEndDateString] = React.useState("");
const [filterByCreator, setFilterByCreator] = React.useState("");
const [filterBySource, setFilterBySource] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: imageTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});
React.useEffect(() => {
initState();
}, [limit]);
async function initState() {
try {
const isForSelf = Number(roleId) === 4;
const res = await listDataTeks(
pagination.pageSize, // Ambil nilai dari pagination.pageSize
pagination.pageIndex + 1, // API sering menggunakan page 1-based
isForSelf,
!isForSelf,
categoryFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1")
? "1,2"
: statusFilter?.sort().join(","),
statusFilter?.sort().join(",").includes("1") ? userLevelId : "",
filterByCreator,
filterBySource,
startDateString,
endDateString
);
setupData(res.data?.data);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
function setupData(rawData: {
content: any[];
totalPages: number;
totalElements: number;
}) {
if (rawData?.content) {
const data: CompanyData[] = rawData.content.map((item, index) => ({
no: pagination.pageIndex * pagination.pageSize + index + 1,
title: item.title,
categoryName: item.categoryName,
creatorGroup: item.creatorGroup,
createdAt: item.createdAt,
isDone: item.isDone,
publishedOn: item.publishedOn,
isPublish: item.isPublish,
isPublishOnPolda: item.isPublishOnPolda,
}));
setImageTable(data);
setTotalPage(rawData.totalPages);
console.log(data, "dataImage");
}
}
return (
<div className="w-full">
<div className="flex items-center py-4 px-5">
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TableTeks;

View File

@ -1,52 +0,0 @@
import { Button } from '@/components/ui/button';
import { Table } from '@tanstack/react-table';
import { ChevronLeft, ChevronRight } from 'lucide-react';
interface DataTablePaginationProps {
table: Table<any>;
}
const TablePagination = ({ table }: DataTablePaginationProps) => {
return (
<div className="flex items-center justify-end py-4 px-10">
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex items-center gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className='w-8 h-8'
>
<ChevronLeft className='w-4 h-4' />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={table.getState().pagination.pageIndex === pageIndex ? 'default' : 'outline'}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className='w-8 h-8'
>
<ChevronRight className='w-4 h-4' />
</Button>
</div>
</div>
);
};
export default TablePagination;

View File

@ -1,7 +1,7 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Card, CardContent } from "@/components/ui/card";
import { UploadIcon } from "lucide-react";
import PressReleaseTable from "../schedule/press-conference/table-presscon/presscon-table";
import PressReleaseTable from "../schedule/press-conference/components/presscon-table";
import { Button } from "@/components/ui/button";
import ContestTable from "./table-contest/contest-table";

View File

@ -1,9 +1,9 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Card, CardContent } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import InternalTable from "../communication/internal/table-internal/internal-table";
import EscalationTable from "../communication/escalation/table-escalation/escalation-table";
import CollaborationTable from "../communication/collaboration/table-collaboration/collabroation-table";
import InternalTable from "../communication/internal/components/internal-table";
import EscalationTable from "../communication/escalation/components/escalation-table";
import CollaborationTable from "../communication/collaboration/components/collabroation-table";
import { Button } from "@/components/ui/button";
import { Search, UploadIcon } from "lucide-react";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";

View File

@ -7,9 +7,9 @@ import { Button } from "@/components/ui/button";
import { UploadIcon } from "lucide-react";
import RecentActivity from "./routine-task/recent-activity";
import CompanyTable from "./routine-task/routine-task-table";
import TaskTable from "../task/table-task/task-table";
import PressConferenceTable from "../schedule/press-release/table-persrilis/pressrilis-table";
import BlogTable from "../blog/table/blog-table";
import TaskTable from "../task/components/task-table";
import PressConferenceTable from "../schedule/press-release/components/pressrilis-table";
import BlogTable from "../blog/components/blog-table";
const DashboardPage = () => {
const t = useTranslations("AnalyticsDashboard");

View File

@ -0,0 +1,103 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
),
},
{
accessorKey: "isActive",
header: "Status",
cell: ({ row }) => {
const isActive = row.getValue<boolean>("isActive");
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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;

View File

@ -26,7 +26,6 @@ import {
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
@ -44,108 +43,22 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
date: string;
isActive: boolean;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { getPlanningSentPagination } from "@/service/planning/planning";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
),
},
{
accessorKey: "isActive",
header: "Status",
cell: ({ row }) => {
const isActive = row.getValue<boolean>("isActive");
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const MediahubTable = () => {
const [mediahubTable, setMediahubTable] = React.useState<CompanyData[]>([]);
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
@ -160,10 +73,9 @@ const MediahubTable = () => {
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
// const [search, setSearch] = React.useState(title);
const table = useReactTable({
data: mediahubTable,
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
@ -184,21 +96,30 @@ const MediahubTable = () => {
});
React.useEffect(() => {
initState();
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function initState() {
async function fetchData() {
try {
const res = await getPlanningSentPagination(limit, page, 1);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
createdAt: item.createdAt,
isActive: item.isActive === true,
}));
const res = await getPlanningSentPagination(limit, page - 1, 1, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
setMediahubTable(data);
setTotalPage(res.data.totalPages);
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
@ -206,7 +127,7 @@ const MediahubTable = () => {
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
@ -232,7 +153,7 @@ const MediahubTable = () => {
/>
</div>
</div>
<Table className="overflow-hidden">
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
@ -273,41 +194,11 @@ const MediahubTable = () => {
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};

View File

@ -1,23 +1,26 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { UploadIcon } from "lucide-react";
import TaskTable from "../../task/table-task/task-table";
import MediahubTable from "./table-mediahub/mediahub-table";
import TaskTable from "../../task/components/task-table";
import MediahubTable from "./components/mediahub-table";
import TicketingTable from "../../ticketing/components/table";
const MediahubPage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Perencanaan : Kanal MediaHub
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Perencanaan : Kanal Mediahub
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<MediahubTable />
</CardContent>

View File

@ -1,47 +0,0 @@
export const data = [
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
];

View File

@ -0,0 +1,103 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
),
},
{
accessorKey: "isActive",
header: "Status",
cell: ({ row }) => {
const isActive = row.getValue<boolean>("isActive");
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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;

View File

@ -26,7 +26,6 @@ import {
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
@ -44,109 +43,22 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
date: string;
isActive: boolean;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import page from "../page";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { getPlanningSentPagination } from "@/service/planning/planning";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("createdAt")}</span>
),
},
{
accessorKey: "isActive",
header: "Status",
cell: ({ row }) => {
const isActive = row.getValue<boolean>("isActive");
console.log("isActive value:", isActive);
return (
<div>
{isActive ? (
<b className="text-info">Terkirim</b>
) : (
<b className="text-danger">Belum Terkirim</b>
)}
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const MedsosTable = () => {
const [mediahubTable, setMediahubTable] = React.useState<CompanyData[]>([]);
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
@ -161,10 +73,9 @@ const MedsosTable = () => {
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
// const [search, setSearch] = React.useState(title);
const table = useReactTable({
data: mediahubTable,
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
@ -185,21 +96,30 @@ const MedsosTable = () => {
});
React.useEffect(() => {
initState();
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function initState() {
async function fetchData() {
try {
const res = await getPlanningSentPagination(limit, page, 2);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
createdAt: item.createdAt,
isActive: item.isActive === true,
}));
const res = await getPlanningSentPagination(limit, page - 1, 2, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
setMediahubTable(data);
setTotalPage(res.data.totalPages);
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
@ -207,7 +127,7 @@ const MedsosTable = () => {
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
@ -233,7 +153,7 @@ const MedsosTable = () => {
/>
</div>
</div>
<Table className="overflow-hidden">
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
@ -274,41 +194,11 @@ const MedsosTable = () => {
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};

View File

@ -1,20 +1,23 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Card, CardContent } from "@/components/ui/card";
import MedsosTable from "./table-medsos/medsos-table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import MedsosTable from "./components/medsos-table";
import TicketingTable from "../../ticketing/components/table";
const MedsosMediahubPage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Perencanaan : Kanal Medsos
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Perencanaan : Kanal Medsos
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<MedsosTable />
</CardContent>

View File

@ -1,47 +0,0 @@
export const data = [
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
{
title: "Seputar Prestasi",
status: "Terkirim",
date: "15/10/2024 9:11",
},
];

View File

@ -0,0 +1,153 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "startDate",
header: "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: "startTime",
header: "Time",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Address",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const address: string = row.getValue("address");
return (
<span className="whitespace-nowrap">
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
</span>
);
},
},
{
accessorKey: "statusName",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
diterima: "bg-green-100 text-green-600",
"menunggu review": "bg-orange-100 text-orange-600",
};
// Mengambil `statusName` dari data API
const status = row.getValue("statusName") as string;
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
// Gunakan `statusName` untuk pencocokan
const statusStyles =
statusColors[statusName] || "bg-gray-100 text-gray-600";
return (
<Badge
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
>
{status} {/* Tetap tampilkan nilai asli */}
</Badge>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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;

View File

@ -0,0 +1,183 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Search } from "lucide-react";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { paginationSchedule } from "@/service/schedule/schedule";
const EventTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await paginationSchedule(limit, page - 1, 2, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default EventTable;

View File

@ -1,32 +1,35 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { UploadIcon } from "lucide-react";
import PressConferenceTable from "../press-conference/table-presscon/presscon-table";
import EventTable from "./table-event/event-table";
import PressConferenceTable from "../press-conference/components/presscon-table";
import EventTable from "./components/event-table";
import { Link } from "@/components/navigation";
import TicketingTable from "../../ticketing/components/table";
const EventPage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Event
</div>
<div>
<Link href={"/schedule/event/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Event
</div>
<div className="flex-none">
<Link href={"/schedule/event/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<EventTable />
</CardContent>

View File

@ -1,101 +0,0 @@
export const data = [
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
];

View File

@ -1,355 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
startDate: string;
endDate: string;
startTime: string;
address: string;
speakerName: string;
uploaderName: string;
status: string;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { paginationSchedule } from "@/service/schedule/schedule";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "startDate",
header: "Tanggal Mulai ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
),
},
{
accessorKey: "endDate",
header: "Tanggal Selesai",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
),
},
{
accessorKey: "startTime",
header: "Waktu",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Lokasi",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("address")}</span>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("status")}
</span>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const EventTable = () => {
const [eventTable, setEventTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: eventTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await paginationSchedule(limit, page, 2);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
startDate: item.startDate,
endDate: item.endDate,
startTime: item.startTime,
address: item.address,
uploaderName: item.uploaderName,
speakerName: item.speakerName,
}));
setEventTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default EventTable;

View File

@ -0,0 +1,153 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "startDate",
header: "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: "startTime",
header: "Time",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Address",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const address: string = row.getValue("address");
return (
<span className="whitespace-nowrap">
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
</span>
);
},
},
{
accessorKey: "statusName",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
diterima: "bg-green-100 text-green-600",
"menunggu review": "bg-orange-100 text-orange-600",
};
// Mengambil `statusName` dari data API
const status = row.getValue("statusName") as string;
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
// Gunakan `statusName` untuk pencocokan
const statusStyles =
statusColors[statusName] || "bg-gray-100 text-gray-600";
return (
<Badge
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
>
{status} {/* Tetap tampilkan nilai asli */}
</Badge>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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;

View File

@ -0,0 +1,196 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { paginationSchedule } from "@/service/schedule/schedule";
const PressConferenceTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await paginationSchedule(limit, page - 1, 1, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default PressConferenceTable;

View File

@ -1,31 +1,34 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import PressConferenceTable from "./table-presscon/presscon-table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import PressConferenceTable from "./components/presscon-table";
import { UploadIcon } from "lucide-react";
import { Link } from "@/components/navigation";
import TicketingTable from "../../ticketing/components/table";
const PressConferencePage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Konferensi Pers
</div>
<div>
<Link href={"/schedule/press-conference/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Konferensi Pers
</div>
<div className="flex-none">
<Link href={"/schedule/press-conference/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<PressConferenceTable />
</CardContent>

View File

@ -1,101 +0,0 @@
export const data = [
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
];

View File

@ -1,355 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
startDate: string;
endDate: string;
startTime: string;
address: string;
speakerName: string;
uploaderName: string;
status: string;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { paginationSchedule } from "@/service/schedule/schedule";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "startDate",
header: "Tanggal Mulai ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
),
},
{
accessorKey: "endDate",
header: "Tanggal Selesai",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
),
},
{
accessorKey: "startTime",
header: "Waktu",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Lokasi",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("address")}</span>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("status")}
</span>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const PressConTable = () => {
const [pressconTable, setPressConTable] = React.useState<CompanyData[]>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: pressconTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await paginationSchedule(limit, page, 1);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
startDate: item.startDate,
endDate: item.endDate,
startTime: item.startTime,
address: item.address,
uploaderName: item.uploaderName,
speakerName: item.speakerName,
}));
setPressConTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default PressConTable;

View File

@ -0,0 +1,153 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const title: string = row.getValue("title");
return (
<span className="whitespace-nowrap">
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
</span>
);
},
},
{
accessorKey: "startDate",
header: "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: "startTime",
header: "Time",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Address",
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
const address: string = row.getValue("address");
return (
<span className="whitespace-nowrap">
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
</span>
);
},
},
{
accessorKey: "statusName",
header: "Status",
cell: ({ row }) => {
const statusColors: Record<string, string> = {
diterima: "bg-green-100 text-green-600",
"menunggu review": "bg-orange-100 text-orange-600",
};
// Mengambil `statusName` dari data API
const status = row.getValue("statusName") as string;
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
// Gunakan `statusName` untuk pencocokan
const statusStyles =
statusColors[statusName] || "bg-gray-100 text-gray-600";
return (
<Badge
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
>
{status} {/* Tetap tampilkan nilai asli */}
</Badge>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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;

View File

@ -0,0 +1,197 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { paginationSchedule } from "@/service/schedule/schedule";
const PressReleaseTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit]);
async function fetchData() {
try {
const res = await paginationSchedule(limit, page - 1, 3, "");
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default PressReleaseTable;

View File

@ -1,31 +1,34 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { UploadIcon } from "lucide-react";
import PressReleaseTable from "../press-conference/table-presscon/presscon-table";
import { Link } from "@/components/navigation";
import TicketingTable from "../../ticketing/components/table";
import PressReleaseTable from "./components/pressrilis-table";
const PressReleasePage = async () => {
return (
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Pers Rilis
</div>
<div>
<Link href={"/schedule/press-release/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Jadwal Pers Rilis
</div>
<div className="flex-none">
<Link href={"/schedule/press-release/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Jadwal
</Button>
</Link>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<PressReleaseTable />
</CardContent>

View File

@ -1,101 +0,0 @@
export const data = [
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Ops Mantap Praja & Pilkada 2024",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
{
title: "Seputar Prestasi",
startDate: "12/10/2024",
endDate: "15/10/2024",
time: "10:00",
loccation:
"2, Jl. Trunojoyo No.3, RT.2/RW.1, Selong, Kec. Kby. Baru, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12110, Indonesia",
speakerName: "Tn anang",
uploaderName: "Mabes Polri - Approver",
status: "Terkirim",
},
];

View File

@ -1,357 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export type CompanyData = {
no: number;
title: string;
startDate: string;
endDate: string;
startTime: string;
address: string;
speakerName: string;
uploaderName: string;
status: string;
};
import { data } from "./data";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { paginationSchedule } from "@/service/schedule/schedule";
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "startDate",
header: "Tanggal Mulai ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
),
},
{
accessorKey: "endDate",
header: "Tanggal Selesai",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
),
},
{
accessorKey: "startTime",
header: "Waktu",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("startTime")}</span>
),
},
{
accessorKey: "address",
header: "Lokasi",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("address")}</span>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
return (
<span className="whitespace-nowrap text-blue-600">
{row.getValue("status")}
</span>
);
},
},
{
accessorKey: "speakerName",
header: "Disampaikan oleh",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("speakerName")}</span>
),
},
{
accessorKey: "uploaderName",
header: "Sumber ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
),
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<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 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>
<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>
);
},
},
];
const PressReleaseTable = () => {
const [pressReleaseTable, setPressReleaseTable] = React.useState<
CompanyData[]
>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const table = useReactTable({
data: pressReleaseTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await paginationSchedule(limit, page, 3);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
startDate: item.startDate,
endDate: item.endDate,
startTime: item.startTime,
address: item.address,
uploaderName: item.uploaderName,
speakerName: item.speakerName,
}));
setPressReleaseTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default PressReleaseTable;

View File

@ -0,0 +1,133 @@
import * as React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { format } from "date-fns";
const columns: ColumnDef<any>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => <span>{row.getValue("no")}</span>,
},
{
accessorKey: "title",
header: "Title",
cell: ({ row }) => <span>{row.getValue("title")}</span>,
},
{
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: "assignmentType",
header: "Category Task",
cell: ({ row }) => {
const type = row.getValue("assignmentType") as { name: string };
return <span>{type?.name}</span>;
},
},
{
accessorKey: "createdAt",
header: "Upload Date ",
cell: ({ row }) => {
const createdAt = row.getValue("createdAt") as
| string
| number
| undefined;
const formattedDate =
createdAt && !isNaN(new Date(createdAt).getTime())
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
: "-";
return <span className="whitespace-nowrap">{formattedDate}</span>;
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => {
const isActive = row.original.isActive;
const isDone = row.original.isDone;
let statusText = "";
if (isDone) {
statusText = "Selesai";
} else if (isActive) {
statusText = "Aktif";
} else {
statusText = "Nonaktif";
}
const statusColors: Record<string, string> = {
Aktif: "bg-primary/20 text-primary",
Selesai: "bg-success/20 text-success",
Nonaktif: "bg-gray-200 text-gray-500",
};
const statusStyles = statusColors[statusText] || "default";
return (
<Badge className={cn("rounded-full px-5", statusStyles)}>
{statusText}
</Badge>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
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 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 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>
<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;

View File

@ -0,0 +1,229 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { paginationBlog } from "@/service/blog/blog";
import { ticketingPagination } from "@/service/ticketing/ticketing";
import { Badge } from "@/components/ui/badge";
import { useRouter, useSearchParams } from "next/navigation";
import TablePagination from "@/components/table/table-pagination";
import columns from "./columns";
import { listTask } from "@/service/task";
const TaskTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [activeTab, setActiveTab] = React.useState("atensi-khusus");
const table = useReactTable({
data: dataTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
onPaginationChange: setPagination,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
pagination,
},
});
React.useEffect(() => {
const pageFromUrl = searchParams?.get("page");
if (pageFromUrl) {
setPage(Number(pageFromUrl));
}
}, [searchParams]);
React.useEffect(() => {
fetchData();
}, [page, limit, activeTab]);
async function fetchData() {
try {
const res = await listTask("", page - 1, limit, activeTab);
const data = res.data?.data;
const contentData = data?.content;
contentData.forEach((item: any, index: number) => {
item.no = (page - 1) * limit + index + 1;
});
console.log("contentData : ", contentData);
setDataTable(contentData);
setTotalData(data?.totalElements);
setTotalPage(data?.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="mx-5 mb-3">
<div className="">
<div className="row">
<Button
onClick={() => setActiveTab("atensi-khusus")}
className={`col-md-6 text-center rounded-none ${
activeTab == "atensi-khusus" ? "text-blue-600" : "text-muted"
}`}
>
Atensi Khusus
</Button>
<Button
onClick={() => setActiveTab("tugas-harian")}
className={`col text-center rounded-none ${
activeTab == "tugas-harian" ? "text-blue-600" : "text-muted"
}`}
>
Tugas Harian
</Button>
</div>
</div>
</div>
<div className="flex justify-between items-center px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden mt-3">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
table={table}
totalData={totalData}
totalPage={totalPage}
/>
</div>
);
};
export default TaskTable;

View File

@ -1,12 +1,13 @@
"use client";
import { Card, CardContent } from "@/components/ui/card";
import TaskTable from "./table-task/task-table";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import TaskTable from "./components/task-table";
import { Button } from "@/components/ui/button";
import { UploadIcon } from "lucide-react";
import SiteBreadcrumb from "@/components/site-breadcrumb";
import { Link } from "@/components/navigation";
import { checkAuthorization, checkLoginSession } from "@/lib/utils";
import React, { useEffect } from "react";
import TicketingTable from "../ticketing/components/table";
const TaskPage = () => {
useEffect(() => {
@ -22,22 +23,24 @@ const TaskPage = () => {
<div>
<SiteBreadcrumb />
<div className="space-y-4">
<Card className="py-4 px-3">
<div className="flex flex-row justify-between items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Table Penugasan
</div>
<div>
<Link href={"/task/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Penugasan
</Button>
</Link>
</div>
</div>
</Card>
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Table Penugasan
</div>
<div className="flex-none">
<Link href={"/task/create"}>
<Button color="primary" className="text-white">
<UploadIcon />
Buat Penugasan
</Button>
</Link>
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TaskTable />
</CardContent>

View File

@ -1,380 +0,0 @@
"use client";
import * as React from "react";
import {
ColumnDef,
ColumnFiltersState,
PaginationState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Badge,
ChevronLeft,
ChevronRight,
Eye,
MoreVertical,
Search,
SquarePen,
Trash2,
TrendingDown,
TrendingUp,
} from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
import { Link } from "@/components/navigation";
import { title } from "process";
import search from "../../app/chat/components/search";
import { format } from "date-fns";
import { listTask } from "@/service/task";
import { getCookiesDecrypt } from "@/lib/utils";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
} from "@/components/ui/select";
export type CompanyData = {
no: number;
title: string;
uniqueCode: string;
assignmentMainType: string;
assignmentType: string;
createdAt: string;
isDone: string;
};
export const columns: ColumnDef<CompanyData>[] = [
{
accessorKey: "no",
header: "No",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("no")}
</h4>
</div>
</div>
),
},
{
accessorKey: "title",
header: "Judul",
cell: ({ row }) => (
<div className="flex items-center gap-5">
<div className="flex-1 text-start">
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
{row.getValue("title")}
</h4>
</div>
</div>
),
},
{
accessorKey: "uniqueCode",
header: "Kode ",
cell: ({ row }) => (
<span className="whitespace-nowrap">{row.getValue("uniqueCode")}</span>
),
},
{
accessorKey: "assignmentMainType",
header: "Tipe Tugas ",
cell: ({ row }) => (
<span className="whitespace-nowrap">
{row.getValue("assignmentMainType")}
</span>
),
},
{
accessorKey: "assignmentType",
header: "Jenis Tugas ",
cell: ({ row }) => (
<span className="whitespace-nowrap">
{row.getValue("assignmentType")}
</span>
),
},
{
accessorKey: "createdAt",
header: "Tanggal Unggah",
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: "isDone",
header: "Status",
cell: ({ row }) => {
const isDone = row.getValue<boolean>("isDone");
return (
<div>
<Button
size="sm"
color="success"
variant="outline"
className={` btn btn-sm ${
isDone ? "btn-outline-success" : "btn-outline-primary"
} pill-btn ml-1`}
>
{isDone ? "Selesai" : "Aktif"}
</Button>
</div>
);
},
},
{
id: "actions",
accessorKey: "action",
header: "Actions",
enableHiding: false,
cell: ({ row }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="icon"
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
>
<span className="sr-only">Open menu</span>
<MoreVertical className="h-4 w-4 text-default-800" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="p-0" align="end">
<a href="/en/task/detail/[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>
</a>
<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>
);
},
},
];
const TaskTable = () => {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [taskTable, setTaskTable] = React.useState<CompanyData[]>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const [rowSelection, setRowSelection] = React.useState({});
const [pagination, setPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const [page, setPage] = React.useState(1);
const [totalPage, setTotalPage] = React.useState(1);
const [limit, setLimit] = React.useState(10);
const [search, setSearch] = React.useState(title);
const userId = getCookiesDecrypt("uie");
const userLevelNumber = getCookiesDecrypt("ulne");
const userRoleId = getCookiesDecrypt("urie");
const table = useReactTable({
data: taskTable,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
columnFilters,
pagination,
},
});
React.useEffect(() => {
initState();
}, [page, limit]);
async function initState() {
try {
const res = await listTask(limit, page);
const data = res.data.data.content.map((item: any, index: number) => ({
no: (page - 1) * limit + index + 1,
title: item.title,
uniqueCode: item.uniqueCode || "-",
assignmentMainType: item.assignmentMainType?.name || "-",
assignmentType: item.assignmentType?.name || "-",
createdAt: item.createdAt,
isDone: item.isDone,
}));
setTaskTable(data);
setTotalPage(res.data.totalPages);
} catch (error) {
console.error("Error fetching tasks:", error);
}
}
return (
<div className="w-full overflow-x-auto">
<div className="flex justify-between items-center py-4 px-5">
<div>
<InputGroup merged>
<InputGroupText className="bg-transparent dark:border-secondary dark:group-focus-within:border-secondary">
<Search className=" h-4 w-4 dark:text-white" />
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
/>
</InputGroup>
</div>
<div className="col-sm-2 col-xs-4 my-1">
{/* <Select onValueChange={handleLimit} name="limit">
<SelectContent>
<SelectGroup>
<SelectItem value="10">1-10 Data</SelectItem>
<SelectItem value="20">1-20 Data</SelectItem>
<SelectItem value="25">1-25 Data</SelectItem>
<SelectItem value="50">1-50 Data</SelectItem>
</SelectGroup>
</SelectContent>
</Select> */}
</div>
<div className="flex-none">
<Input
placeholder="Filter Status..."
value={
(table.getColumn("status")?.getFilterValue() as string) ?? ""
}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
table.getColumn("status")?.setFilterValue(event.target.value)
}
className="max-w-sm "
/>
</div>
</div>
<Table className="overflow-hidden">
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="bg-default-200">
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="h-[75px]"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="flex items-center justify-center py-4 gap-2 flex-none">
<Button
variant="outline"
size="icon"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="w-8 h-8"
>
<ChevronLeft className="w-4 h-4" />
</Button>
{table.getPageOptions().map((page, pageIndex) => (
<Button
key={`basic-data-table-${pageIndex}`}
onClick={() => table.setPageIndex(pageIndex)}
size="icon"
className="w-8 h-8"
variant={
table.getState().pagination.pageIndex === pageIndex
? "default"
: "outline"
}
>
{page + 1}
</Button>
))}
<Button
variant="outline"
size="icon"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="w-8 h-8"
>
<ChevronRight className="w-4 h-4" />
</Button>
</div>
</div>
);
};
export default TaskTable;

View File

@ -10,26 +10,26 @@ const TicketingPage = async () => {
<SiteBreadcrumb />
<div className="space-y-4">
<Card>
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Ticket Data
</div>
<div className="flex-none">
{/* <Button
<CardHeader className="border-b border-solid border-default-200 mb-6">
<CardTitle>
<div className="flex items-center">
<div className="flex-1 text-xl font-medium text-default-900">
Ticket Data
</div>
<div className="flex-none">
{/* <Button
fullWidth
size="md"
>
<Plus className="w-6 h-6 me-1.5"/>
New Ticket
</Button> */}
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TicketingTable />
</div>
</div>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<TicketingTable />
</CardContent>
</Card>
</div>

122
package-lock.json generated
View File

@ -149,6 +149,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
"dev": true,
"engines": {
"node": ">=10"
},
@ -1214,6 +1215,7 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@ -1230,6 +1232,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"dev": true,
"engines": {
"node": ">=12"
},
@ -1241,6 +1244,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
@ -1771,6 +1775,7 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@ -1783,6 +1788,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"engines": {
"node": ">= 8"
}
@ -1791,6 +1797,7 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@ -1820,6 +1827,7 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"optional": true,
"engines": {
"node": ">=14"
@ -3685,7 +3693,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==",
"devOptional": true,
"dev": true,
"dependencies": {
"@types/react": "*"
}
@ -3979,6 +3987,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -3992,6 +4001,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@ -4005,12 +4015,14 @@
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
"dev": true
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@ -4055,7 +4067,8 @@
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
@ -4346,12 +4359,14 @@
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"engines": {
"node": ">=8"
},
@ -4373,6 +4388,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.1.1"
},
@ -4432,6 +4448,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
"dev": true,
"engines": {
"node": ">= 6"
}
@ -4531,6 +4548,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -4554,6 +4572,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@ -4738,6 +4757,7 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@ -4761,6 +4781,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"bin": {
"cssesc": "bin/cssesc"
},
@ -5428,7 +5449,8 @@
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true
},
"node_modules/diff": {
"version": "5.2.0",
@ -5453,7 +5475,8 @@
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true
},
"node_modules/doctrine": {
"version": "3.0.0",
@ -5554,7 +5577,8 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/elkjs": {
"version": "0.9.3",
@ -5602,7 +5626,8 @@
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
@ -6442,6 +6467,7 @@
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@ -6457,6 +6483,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@ -6480,6 +6507,7 @@
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
@ -6523,6 +6551,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -6613,6 +6642,7 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
@ -6681,6 +6711,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@ -6836,6 +6867,7 @@
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
@ -6857,6 +6889,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.3"
},
@ -6868,6 +6901,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
@ -6876,6 +6910,7 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
@ -7843,6 +7878,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@ -7974,6 +8010,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -7997,6 +8034,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -8020,6 +8058,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@ -8064,6 +8103,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
@ -8312,6 +8352,7 @@
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dev": true,
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
@ -8329,6 +8370,7 @@
"version": "1.21.6",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
"dev": true,
"bin": {
"jiti": "bin/jiti.js"
}
@ -8587,6 +8629,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"dev": true,
"engines": {
"node": ">=14"
},
@ -8690,7 +8733,8 @@
"node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true
},
"node_modules/lucide-react": {
"version": "0.390.0",
@ -9404,6 +9448,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"engines": {
"node": ">= 8"
}
@ -10191,6 +10236,7 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@ -10251,6 +10297,7 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
@ -10299,6 +10346,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"dev": true,
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
@ -10593,6 +10641,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -10647,6 +10696,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"dev": true,
"engines": {
"node": ">= 6"
}
@ -10945,6 +10995,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -10958,6 +11009,7 @@
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true,
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
@ -10996,6 +11048,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
@ -11007,6 +11060,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -11015,6 +11069,7 @@
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
"dev": true,
"engines": {
"node": ">= 6"
}
@ -11032,6 +11087,7 @@
"version": "8.4.49",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -11059,6 +11115,7 @@
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
"dev": true,
"dependencies": {
"postcss-value-parser": "^4.0.0",
"read-cache": "^1.0.0",
@ -11075,6 +11132,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
"dev": true,
"dependencies": {
"camelcase-css": "^2.0.1"
},
@ -11093,6 +11151,7 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -11127,6 +11186,7 @@
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
"integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
"dev": true,
"bin": {
"yaml": "bin.mjs"
},
@ -11138,6 +11198,7 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -11162,6 +11223,7 @@
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@ -11173,7 +11235,8 @@
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/preact": {
"version": "10.12.1",
@ -11278,6 +11341,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
@ -11789,6 +11853,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
"dev": true,
"dependencies": {
"pify": "^2.3.0"
}
@ -11797,6 +11862,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@ -12219,6 +12285,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@ -12291,6 +12358,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
@ -12482,6 +12550,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"dependencies": {
"shebang-regex": "^3.0.0"
},
@ -12493,6 +12562,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -12529,6 +12599,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
@ -12658,6 +12729,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@ -12675,6 +12747,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -12687,12 +12760,14 @@
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/string-width/node_modules/ansi-regex": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"dev": true,
"engines": {
"node": ">=12"
},
@ -12704,6 +12779,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
@ -12839,6 +12915,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -12851,6 +12928,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -12955,6 +13033,7 @@
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
@ -12976,6 +13055,7 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
"dev": true,
"engines": {
"node": ">= 6"
}
@ -13149,6 +13229,7 @@
"version": "3.4.16",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.16.tgz",
"integrity": "sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==",
"dev": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@ -13208,6 +13289,7 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dev": true,
"dependencies": {
"any-promise": "^1.0.0"
}
@ -13216,6 +13298,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"dev": true,
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
@ -13323,6 +13406,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
@ -13380,7 +13464,8 @@
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
"dev": true
},
"node_modules/tsconfig-paths": {
"version": "3.15.0",
@ -13858,7 +13943,8 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/uuid": {
"version": "9.0.1",
@ -14097,6 +14183,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
@ -14203,6 +14290,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@ -14220,6 +14308,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@ -14235,12 +14324,14 @@
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -14254,6 +14345,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
"dev": true,
"engines": {
"node": ">=12"
},
@ -14265,6 +14357,7 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"engines": {
"node": ">=12"
},
@ -14276,6 +14369,7 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},

View File

@ -1,8 +1,12 @@
import { title } from "process";
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
export async function paginationBlog(size: number, page: number) {
export async function paginationBlog(
size: number,
page: number,
title: string = ""
) {
return await httpGetInterceptor(
`blog/pagination?enablePage=0&page=${page}&size=${size}`
`blog/pagination?enablePage=1&page=${page}&size=${size}&title=${title}`
);
}

View File

@ -3,10 +3,35 @@ import {
httpGetInterceptor,
httpPostInterceptor,
} from "../http-config/http-interceptor-service";
import { title } from "process";
export async function listTicketingInternal(page: number, size: any) {
export async function listTicketingInternal(
page: number,
size: any,
title: string = ""
) {
return await httpGetInterceptor(
`ticketing/internal/pagination?enablePage=0&size=${size}&page=${page}`
`ticketing/internal/pagination?enablePage=1&size=${size}&page=${page}&title=${title}`
);
}
export async function getTicketingEscalationPagination(
page: number,
size: any,
title: string = ""
) {
return await httpGetInterceptor(
`ticketing/escalation/pagination?enablePage=1&size=${size}&page=${page}&title=${title}`
);
}
export async function getTicketingCollaborationPagination(
page: number,
size: any,
title: string = ""
) {
return await httpGetInterceptor(
`ticketing/collaboration/pagination?enablePage=1&size=${size}&page=${page}&title=${title}`
);
}

View File

@ -2,8 +2,8 @@ import { getAPIInterceptor, postAPIInterceptor } from "@/config/api";
import { httpGetInterceptor } from "../http-config/http-interceptor-service";
export async function listDataImage(
page: any,
limit: any,
page: any,
isForSelf: any,
isApproval: any,
categoryFilter: any,
@ -12,16 +12,17 @@ export async function listDataImage(
creator: any,
source: any,
startDate: any,
endDate: any
endDate: any,
title: string = ""
) {
return await getAPIInterceptor(
`media/list?enablePage=0&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=1&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
export async function listDataVideo(
page: any,
limit: any,
page: any,
isForSelf: any,
isApproval: any,
categoryFilter: any,
@ -30,16 +31,17 @@ export async function listDataVideo(
creator: any,
source: any,
startDate: any,
endDate: any
endDate: any,
title: string = ""
) {
return await getAPIInterceptor(
`media/list?enablePage=0&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=2&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=2&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
export async function listDataTeks(
page: any,
limit: any,
page: any,
isForSelf: any,
isApproval: any,
categoryFilter: any,
@ -48,10 +50,11 @@ export async function listDataTeks(
creator: any,
source: any,
startDate: any,
endDate: any
endDate: any,
title: string = ""
) {
return await getAPIInterceptor(
`media/list?enablePage=0&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=3&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=3&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
@ -66,10 +69,11 @@ export async function listDataAudio(
creator: any,
source: any,
startDate: any,
endDate: any
endDate: any,
title: string = ""
) {
return await getAPIInterceptor(
`media/list?enablePage=0&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=4&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}`
`media/list?enablePage=1&sortBy=createdAt&sort=desc&size=${limit}&page=${page}&typeId=4&isForSelf=${isForSelf}&isApproval=${isApproval}&categoryId=${categoryFilter}&statusId=${statusFilter}&needApprovalFromLevel=${needApprovalFromLevel}&creatorUserLevelName=${source}&creatorName=${creator}&startDate=${startDate}&endDate=${endDate}&title=${title}`
);
}
@ -80,13 +84,13 @@ export async function listSPIT(
isPublish: any
) {
return await httpGetInterceptor(
`media/spit/pagination?enablePage=0&page=${page}&size=${limit}&sort=desc&sortBy=contentTitleId&title=${title}&isPublish=${isPublish}`
`media/spit/pagination?enablePage=1&page=${page}&size=${limit}&sort=desc&sortBy=contentTitleId&title=${title}&isPublish=${isPublish}`
);
}
export async function listNulisAI(page: any, limit: any) {
export async function listNulisAI(limit: any, page: any, title: string = "") {
return await getAPIInterceptor(
`media/nulis-ai/pagination?enablePage=0&page=${page}&size=${limit}`
`media/nulis-ai/pagination?enablePage=1&page=${page}&size=${limit}&title=${title}`
);
}

View File

@ -3,9 +3,10 @@ import { httpGetInterceptor } from "../http-config/http-interceptor-service";
export async function getPlanningSentPagination(
size: number,
page: number,
typeId: number
typeId: number,
title: string = ""
) {
return await httpGetInterceptor(
`planning/pagination/sent?enablePage=0&size=${size}&page=${page}&typeId=${typeId}`
`planning/pagination/sent?enablePage=1&size=${size}&page=${page}&typeId=${typeId}&title=${title}`
);
}

View File

@ -5,9 +5,10 @@ import { type } from "os";
export async function paginationSchedule(
size: number,
page: number,
type: any
type: any,
title: string = ""
) {
return await httpGetInterceptor(
`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}`
`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`
);
}

View File

@ -16,8 +16,13 @@ import {
// );
// }
export async function listTask(page: any, limit: any) {
const url = `assignment/list?enablePage=0&size=${limit}&page=${page}`;
export async function listTask(
title: string = "",
page: any,
size: any,
taskType: string
) {
const url = `assignment/list?enablePage=1&size=${size}&page=${page}&title=${title}&taskType=${taskType}`;
return getAPIInterceptor(url);
}