From b0457e2924b1f1e25b0f431c738d8a8dc03b0b78 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Tue, 11 Feb 2025 13:54:31 +0800 Subject: [PATCH] feat:add media tracking --- .../media-online/component/column.tsx | 54 ++++ .../media-online/component/table.tsx | 302 +++++++++++++++++ .../media-tracking/media-online/page.tsx | 11 + .../tb-news/component/column.tsx | 58 ++++ .../tb-news/component/table.tsx | 305 ++++++++++++++++++ .../admin/media-tracking/tb-news/page.tsx | 11 + components/form/task/task-detail-form.tsx | 12 +- lib/menus.ts | 12 +- 8 files changed, 756 insertions(+), 9 deletions(-) create mode 100644 app/[locale]/(protected)/admin/media-tracking/media-online/component/column.tsx create mode 100644 app/[locale]/(protected)/admin/media-tracking/media-online/component/table.tsx create mode 100644 app/[locale]/(protected)/admin/media-tracking/media-online/page.tsx create mode 100644 app/[locale]/(protected)/admin/media-tracking/tb-news/component/column.tsx create mode 100644 app/[locale]/(protected)/admin/media-tracking/tb-news/component/table.tsx create mode 100644 app/[locale]/(protected)/admin/media-tracking/tb-news/page.tsx diff --git a/app/[locale]/(protected)/admin/media-tracking/media-online/component/column.tsx b/app/[locale]/(protected)/admin/media-tracking/media-online/component/column.tsx new file mode 100644 index 00000000..36024514 --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/media-online/component/column.tsx @@ -0,0 +1,54 @@ +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 { + formatDateToIndonesian, + getOnlyDate, + htmlToString, +} from "@/utils/globals"; +import { Link, useRouter } from "@/i18n/routing"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + + { + accessorKey: "title", + header: "Nama Media Online", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "link", + header: "Link", + cell: ({ row }) => {row.getValue("categoryName")}, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/media-tracking/media-online/component/table.tsx b/app/[locale]/(protected)/admin/media-tracking/media-online/component/table.tsx new file mode 100644 index 00000000..28c87044 --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/media-online/component/table.tsx @@ -0,0 +1,302 @@ +"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, + UserIcon, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + 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 "./column"; +import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { listDataMedia } from "@/service/broadcast/broadcast"; +import { listEnableCategory } from "@/service/content/content"; +import { Checkbox } from "@/components/ui/checkbox"; +import { close, loading } from "@/config/swal"; +import { Link } from "@/i18n/routing"; + +const MediaOnlineTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const [search, setSearch] = React.useState(""); + const [showData, setShowData] = React.useState("10"); + const [categories, setCategories] = React.useState(); + const [dataTable, setDataTable] = React.useState([]); + const [totalData, setTotalData] = React.useState(1); + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + const [pagination, setPagination] = React.useState({ + pageIndex: 0, + pageSize: Number(showData), + }); + const [categoryFilter, setCategoryFilter] = React.useState([]); + const [statusFilter, setStatusFilter] = React.useState([]); + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + 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, + }, + }); + + let typingTimer: any; + const doneTypingInterval = 1500; + + // const handleKeyUp = () => { + // clearTimeout(typingTimer); + // typingTimer = setTimeout(doneTyping, doneTypingInterval); + // }; + + const handleKeyDown = () => { + clearTimeout(typingTimer); + }; + + // async function doneTyping() { + // fetchData(); + // } + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + // React.useEffect(() => { + // fetchData(); + // setPagination({ + // pageIndex: 0, + // pageSize: Number(showData), + // }); + // }, [page, showData]); + + // async function fetchData() { + // try { + // loading(); + // const res = await listDataMedia( + // page - 1, + // showData, + // search, + // categoryFilter?.sort().join(","), + // statusFilter?.sort().join(",") + // ); + // const data = res?.data?.data; + // const contentData = data?.content; + // contentData.forEach((item: any, index: number) => { + // item.no = (page - 1) * Number(showData) + index + 1; + // }); + + // console.log("contentData : ", data); + + // setDataTable(contentData); + // setTotalData(data?.totalElements); + // setTotalPage(data?.totalPages); + // close(); + // } catch (error) { + // console.error("Error fetching tasks:", error); + // } + // } + + React.useEffect(() => { + getCategories(); + }, []); + + async function getCategories() { + const category = await listEnableCategory(""); + const resCategory = category?.data?.data?.content; + setCategories(resCategory); + } + + const handleChange = (type: string, id: number, checked: boolean) => { + if (type === "category") { + if (checked) { + const temp: number[] = [...categoryFilter]; + temp.push(id); + setCategoryFilter(temp); + } else { + const temp = categoryFilter.filter((a) => a !== id); + setCategoryFilter(temp); + } + } else { + if (checked) { + const temp: number[] = [...statusFilter]; + temp.push(id); + setStatusFilter(temp); + } else { + const temp = statusFilter.filter((a) => a !== id); + setStatusFilter(temp); + } + } + }; + + return ( +
+
+

Media Online

+
+ +
+ + + + setSearch(e.target.value)} + className="max-w-[300px]" + /> +
+ + + + + + + + 1 - 10 Data + + + 1 - 20 Data + + + 1 - 25 Data + + + 1 - 50 Data + + + + +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+ +
+ ); +}; + +export default MediaOnlineTable; diff --git a/app/[locale]/(protected)/admin/media-tracking/media-online/page.tsx b/app/[locale]/(protected)/admin/media-tracking/media-online/page.tsx new file mode 100644 index 00000000..bd811c30 --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/media-online/page.tsx @@ -0,0 +1,11 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import MediaOnlineTable from "./component/table"; + +export default function AdminMediaOnline() { + return ( +
+ + +
+ ); +} diff --git a/app/[locale]/(protected)/admin/media-tracking/tb-news/component/column.tsx b/app/[locale]/(protected)/admin/media-tracking/tb-news/component/column.tsx new file mode 100644 index 00000000..e963dea3 --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/tb-news/component/column.tsx @@ -0,0 +1,58 @@ +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 { + formatDateToIndonesian, + getOnlyDate, + htmlToString, +} from "@/utils/globals"; +import { Link, useRouter } from "@/i18n/routing"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + { + accessorKey: "date", + header: "Tanggal", + cell: ({ row }) => {row.getValue("categoryName")}, + }, + { + accessorKey: "title", + header: "Media Online", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "link", + header: "Link Berita", + cell: ({ row }) => {row.getValue("categoryName")}, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/media-tracking/tb-news/component/table.tsx b/app/[locale]/(protected)/admin/media-tracking/tb-news/component/table.tsx new file mode 100644 index 00000000..c2407cd7 --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/tb-news/component/table.tsx @@ -0,0 +1,305 @@ +"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, + UserIcon, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + 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 "./column"; +import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { listDataMedia } from "@/service/broadcast/broadcast"; +import { listEnableCategory } from "@/service/content/content"; +import { Checkbox } from "@/components/ui/checkbox"; +import { close, loading } from "@/config/swal"; +import { Link } from "@/i18n/routing"; +import { Label } from "@/components/ui/label"; + +const NewsTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const [search, setSearch] = React.useState(""); + const [showData, setShowData] = React.useState("10"); + const [categories, setCategories] = React.useState(); + const [dataTable, setDataTable] = React.useState([]); + const [totalData, setTotalData] = React.useState(1); + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [showTable, setShowTable] = React.useState(false); + const [columnVisibility, setColumnVisibility] = + React.useState({}); + const [rowSelection, setRowSelection] = React.useState({}); + const [pagination, setPagination] = React.useState({ + pageIndex: 0, + pageSize: Number(showData), + }); + const [categoryFilter, setCategoryFilter] = React.useState([]); + const [statusFilter, setStatusFilter] = React.useState([]); + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + 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, + }, + }); + + let typingTimer: any; + const doneTypingInterval = 1500; + + // const handleKeyUp = () => { + // clearTimeout(typingTimer); + // typingTimer = setTimeout(doneTyping, doneTypingInterval); + // }; + + const handleKeyDown = () => { + clearTimeout(typingTimer); + }; + + // async function doneTyping() { + // fetchData(); + // } + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + // React.useEffect(() => { + // fetchData(); + // setPagination({ + // pageIndex: 0, + // pageSize: Number(showData), + // }); + // }, [page, showData]); + + // async function fetchData() { + // try { + // loading(); + // const res = await listDataMedia( + // page - 1, + // showData, + // search, + // categoryFilter?.sort().join(","), + // statusFilter?.sort().join(",") + // ); + // const data = res?.data?.data; + // const contentData = data?.content; + // contentData.forEach((item: any, index: number) => { + // item.no = (page - 1) * Number(showData) + index + 1; + // }); + + // console.log("contentData : ", data); + + // setDataTable(contentData); + // setTotalData(data?.totalElements); + // setTotalPage(data?.totalPages); + // close(); + // } catch (error) { + // console.error("Error fetching tasks:", error); + // } + // } + + React.useEffect(() => { + getCategories(); + }, []); + + async function getCategories() { + const category = await listEnableCategory(""); + const resCategory = category?.data?.data?.content; + setCategories(resCategory); + } + + const handleChange = (type: string, id: number, checked: boolean) => { + if (type === "category") { + if (checked) { + const temp: number[] = [...categoryFilter]; + temp.push(id); + setCategoryFilter(temp); + } else { + const temp = categoryFilter.filter((a) => a !== id); + setCategoryFilter(temp); + } + } else { + if (checked) { + const temp: number[] = [...statusFilter]; + temp.push(id); + setStatusFilter(temp); + } else { + const temp = statusFilter.filter((a) => a !== id); + setStatusFilter(temp); + } + } + }; + + return ( +
+
+

+ Tracking Berita hari ini! +

+
+
+ + +

Sisa kuota harian: 30 Artikel

+
+ {!showTable && ( +
+ + +
+ )} + {showTable && ( + <> + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+ +
+ +
+ + )} +
+ ); +}; + +export default NewsTable; diff --git a/app/[locale]/(protected)/admin/media-tracking/tb-news/page.tsx b/app/[locale]/(protected)/admin/media-tracking/tb-news/page.tsx new file mode 100644 index 00000000..a8baea3f --- /dev/null +++ b/app/[locale]/(protected)/admin/media-tracking/tb-news/page.tsx @@ -0,0 +1,11 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import NewsTable from "./component/table"; + +export default function AdminNews() { + return ( +
+ + +
+ ); +} diff --git a/components/form/task/task-detail-form.tsx b/components/form/task/task-detail-form.tsx index 7ba1ba01..8b09c338 100644 --- a/components/form/task/task-detail-form.tsx +++ b/components/form/task/task-detail-form.tsx @@ -1470,7 +1470,7 @@ export default function FormTaskDetail() {