From 76cc8ca0999de8b311bc9bfff1eed73410960578 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Thu, 29 May 2025 18:16:54 +0800 Subject: [PATCH 1/2] feat:add live report,kalender polri,popup,iklan --- .../admin/settings/iklan/component/column.tsx | 113 +++++ .../settings/iklan/component/popup-column.tsx | 110 +++++ .../settings/iklan/component/popup-table.tsx | 153 +++++++ .../iklan/component/static-toogle.tsx | 40 ++ .../iklan/component/status-toogle.tsx | 37 ++ .../admin/settings/iklan/component/table.tsx | 393 ++++++++++++++++++ .../(protected)/admin/settings/iklan/page.tsx | 52 +++ .../admin/settings/popup/component/column.tsx | 113 +++++ .../settings/popup/component/popup-column.tsx | 110 +++++ .../settings/popup/component/popup-table.tsx | 153 +++++++ .../popup/component/static-toogle.tsx | 40 ++ .../popup/component/status-toogle.tsx | 37 ++ .../admin/settings/popup/component/table.tsx | 393 ++++++++++++++++++ .../(protected)/admin/settings/popup/page.tsx | 52 +++ .../component/calendar-polri-table.tsx | 349 ++++++++++++++++ .../calendar-polri/component/columns.tsx | 183 ++++++++ .../schedule/calendar-polri/create/page.tsx | 17 + .../calendar-polri/detail/[id]/page.tsx | 21 + .../schedule/calendar-polri/layout.tsx | 9 + .../schedule/calendar-polri/page.tsx | 21 + .../calendar-polri/update/[id]/page.tsx | 22 + .../live-report/component/columns.tsx | 183 ++++++++ .../component/live-report-table.tsx | 349 ++++++++++++++++ .../schedule/live-report/create/page.tsx | 17 + .../schedule/live-report/detail/[id]/page.tsx | 21 + .../schedule/live-report/layout.tsx | 9 + .../contributor/schedule/live-report/page.tsx | 22 + .../schedule/live-report/update/[id]/page.tsx | 22 + .../schedule/press-conference/page.tsx | 4 +- app/[locale]/page.tsx | 3 - lib/menus.ts | 204 ++++----- messages/en.json | 7 +- messages/in.json | 7 +- 33 files changed, 3127 insertions(+), 139 deletions(-) create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/column.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/popup-column.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/popup-table.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/static-toogle.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/status-toogle.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/component/table.tsx create mode 100644 app/[locale]/(protected)/admin/settings/iklan/page.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/column.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/popup-column.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/popup-table.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/static-toogle.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/status-toogle.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/component/table.tsx create mode 100644 app/[locale]/(protected)/admin/settings/popup/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/layout.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/component/columns.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/layout.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/page.tsx create mode 100644 app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx new file mode 100644 index 00000000..6ffd551f --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/column.tsx @@ -0,0 +1,113 @@ +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"; +import { setBanner } from "@/service/settings/settings"; +import { error } from "@/config/swal"; +import { useToast } from "@/components/ui/use-toast"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + + { + accessorKey: "title", + header: "Judul", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "categoryName", + header: "Kategori", + cell: ({ row }) => {row.getValue("categoryName")}, + }, + { + accessorKey: "createdAt", + header: "Tanggal Unggah", + cell: ({ row }) => ( + {formatDateToIndonesian(row.getValue("createdAt"))} + ), + }, + + { + accessorKey: "statusName", + header: "Status", + cell: ({ row }) => {row.getValue("statusName")}, + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + const { toast } = useToast(); + + const handleBanner = async (id: number) => { + const response = setBanner(id, true); + toast({ + title: "Success", + }); + }; + return ( + + + + + + + + Detail + + + + handleBanner(row.original.id)}> + Jadikan Banner + + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/popup-column.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/popup-column.tsx new file mode 100644 index 00000000..899f2124 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/popup-column.tsx @@ -0,0 +1,110 @@ +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"; +import StatusToogle from "./status-toogle"; +import StaticToogle from "./static-toogle"; + +const columns: ColumnDef[] = [ + // { + // accessorKey: "no", + // header: "No", + // cell: ({ row }) => {row.getValue("no")}, + // }, + + { + accessorKey: "title", + header: "Judul", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "categoryName", + header: "Kategori", + cell: ({ row }) => {row.getValue("categoryName")}, + }, + { + accessorKey: "createdAt", + header: "Tanggal Unggah", + cell: ({ row }) => ( + {formatDateToIndonesian(row.getValue("createdAt"))} + ), + }, + { + accessorKey: "isStaticBanner", + header: "Static Banner", + cell: ({ row }) => ( + + ), + }, + { + accessorKey: "statusName", + header: "Status Banner", + cell: ({ row }) => ( + + ), + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + + Detail + + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/popup-table.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/popup-table.tsx new file mode 100644 index 00000000..6d9401ce --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/popup-table.tsx @@ -0,0 +1,153 @@ +"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 { useSearchParams } from "next/navigation"; + +import { close, loading } from "@/config/swal"; +import { Link, useRouter } from "@/i18n/routing"; +import columns from "./popup-column"; +import { listBanner, listStaticBanner } from "@/service/settings/settings"; + +const IklanListTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const [showData, setShowData] = React.useState("10"); + + 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 [getData, setGetData] = React.useState([]); + const dataChange = searchParams?.get("dataChange"); + + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + const table = useReactTable({ + data: getData, + 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(() => { + if (dataChange) { + router.push("/admin/settings/banner"); + } + getListBanner(); + }, [dataChange]); + + React.useEffect(() => { + getListBanner(); + // getListStaticBanner(); + }, [page, showData]); + + async function getListBanner() { + loading(); + let temp: any; + + const response = await listBanner(); + const data = response?.data?.data?.content; + console.log("banner", data); + setGetData(data); + + close(); + } + + return ( + <> + + + {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 IklanListTable; diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/static-toogle.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/static-toogle.tsx new file mode 100644 index 00000000..66392c4e --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/static-toogle.tsx @@ -0,0 +1,40 @@ +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { useRouter } from "@/i18n/routing"; +import { setStaticBanner } from "@/service/settings/settings"; + +export default function StaticToogle(props: { + id: number; + initChecked: boolean; +}) { + const { id, initChecked } = props; + const { toast } = useToast(); + const router = useRouter(); + + const changeStaticBanner = async (id: number) => { + const response = await setStaticBanner(id); + + if (response?.error) { + toast({ + variant: "destructive", + title: response?.message, + }); + return false; + } + + toast({ + title: "Success ", + }); + router.push("/admin/settings/banner?dataChange=true"); + }; + + return ( + { + changeStaticBanner(id); + }} + /> + ); +} diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/status-toogle.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/status-toogle.tsx new file mode 100644 index 00000000..22f11b79 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/status-toogle.tsx @@ -0,0 +1,37 @@ +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { useRouter } from "@/i18n/routing"; +import { setBanner } from "@/service/settings/settings"; + +export default function StatusToogle(props: { + id: number; + initChecked: boolean; +}) { + const { id, initChecked } = props; + const { toast } = useToast(); + const router = useRouter(); + + const disableBanner = async () => { + const response = await setBanner(id, false); + + if (response?.error) { + toast({ + variant: "destructive", + title: response?.message, + }); + return false; + } + + toast({ + title: "Success ", + }); + router.push("/admin/settings/banner?dataChange=true"); + }; + return ( + disableBanner()} + /> + ); +} diff --git a/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx b/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx new file mode 100644 index 00000000..21f35ad3 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/component/table.tsx @@ -0,0 +1,393 @@ +"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 IklanList = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + 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); + typingTimer = setTimeout(doneTyping, doneTypingInterval); + }; + + 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, + "", + 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 ( + <> +
+ +
+ + + + + + + + 1 - 10 Data + + + 1 - 20 Data + + + 1 - 25 Data + + + 1 - 50 Data + + + + + + + + + +
+ +
+

Kategory

+ {categories?.map((category: any) => ( +
+ + handleChange("category", category.id, Boolean(e)) + } + /> + +
+ ))} +

Status

+
+ + handleChange("status", 1, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 2, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 3, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 4, Boolean(e)) + } + /> + +
+
+
+
+
+
+
+ + + {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 IklanList; diff --git a/app/[locale]/(protected)/admin/settings/iklan/page.tsx b/app/[locale]/(protected)/admin/settings/iklan/page.tsx new file mode 100644 index 00000000..8615d36c --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/iklan/page.tsx @@ -0,0 +1,52 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import PopUpList from "../popup/component/table"; +import PopUpListTable from "../popup/component/popup-table"; +import IklanList from "./component/table"; +import IklanListTable from "./component/popup-table"; + +export default function AdminIklan() { + const [selectedTab, setSelectedTab] = useState("content"); + + return ( +
+ +
+
+ {selectedTab === "content" ? "List Media" : " List Pop Up"} + +
+ + +
+
+ + {selectedTab === "content" ? : } +
+
+ ); +} diff --git a/app/[locale]/(protected)/admin/settings/popup/component/column.tsx b/app/[locale]/(protected)/admin/settings/popup/component/column.tsx new file mode 100644 index 00000000..6ffd551f --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/column.tsx @@ -0,0 +1,113 @@ +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"; +import { setBanner } from "@/service/settings/settings"; +import { error } from "@/config/swal"; +import { useToast } from "@/components/ui/use-toast"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + + { + accessorKey: "title", + header: "Judul", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "categoryName", + header: "Kategori", + cell: ({ row }) => {row.getValue("categoryName")}, + }, + { + accessorKey: "createdAt", + header: "Tanggal Unggah", + cell: ({ row }) => ( + {formatDateToIndonesian(row.getValue("createdAt"))} + ), + }, + + { + accessorKey: "statusName", + header: "Status", + cell: ({ row }) => {row.getValue("statusName")}, + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + const { toast } = useToast(); + + const handleBanner = async (id: number) => { + const response = setBanner(id, true); + toast({ + title: "Success", + }); + }; + return ( + + + + + + + + Detail + + + + handleBanner(row.original.id)}> + Jadikan Banner + + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/settings/popup/component/popup-column.tsx b/app/[locale]/(protected)/admin/settings/popup/component/popup-column.tsx new file mode 100644 index 00000000..899f2124 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/popup-column.tsx @@ -0,0 +1,110 @@ +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"; +import StatusToogle from "./status-toogle"; +import StaticToogle from "./static-toogle"; + +const columns: ColumnDef[] = [ + // { + // accessorKey: "no", + // header: "No", + // cell: ({ row }) => {row.getValue("no")}, + // }, + + { + accessorKey: "title", + header: "Judul", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "categoryName", + header: "Kategori", + cell: ({ row }) => {row.getValue("categoryName")}, + }, + { + accessorKey: "createdAt", + header: "Tanggal Unggah", + cell: ({ row }) => ( + {formatDateToIndonesian(row.getValue("createdAt"))} + ), + }, + { + accessorKey: "isStaticBanner", + header: "Static Banner", + cell: ({ row }) => ( + + ), + }, + { + accessorKey: "statusName", + header: "Status Banner", + cell: ({ row }) => ( + + ), + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + + Detail + + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/admin/settings/popup/component/popup-table.tsx b/app/[locale]/(protected)/admin/settings/popup/component/popup-table.tsx new file mode 100644 index 00000000..4e458d86 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/popup-table.tsx @@ -0,0 +1,153 @@ +"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 { useSearchParams } from "next/navigation"; + +import { close, loading } from "@/config/swal"; +import { Link, useRouter } from "@/i18n/routing"; +import columns from "./popup-column"; +import { listBanner, listStaticBanner } from "@/service/settings/settings"; + +const PopUpListTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const [showData, setShowData] = React.useState("10"); + + 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 [getData, setGetData] = React.useState([]); + const dataChange = searchParams?.get("dataChange"); + + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + const table = useReactTable({ + data: getData, + 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(() => { + if (dataChange) { + router.push("/admin/settings/banner"); + } + getListBanner(); + }, [dataChange]); + + React.useEffect(() => { + getListBanner(); + // getListStaticBanner(); + }, [page, showData]); + + async function getListBanner() { + loading(); + let temp: any; + + const response = await listBanner(); + const data = response?.data?.data?.content; + console.log("banner", data); + setGetData(data); + + close(); + } + + return ( + <> + + + {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 PopUpListTable; diff --git a/app/[locale]/(protected)/admin/settings/popup/component/static-toogle.tsx b/app/[locale]/(protected)/admin/settings/popup/component/static-toogle.tsx new file mode 100644 index 00000000..66392c4e --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/static-toogle.tsx @@ -0,0 +1,40 @@ +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { useRouter } from "@/i18n/routing"; +import { setStaticBanner } from "@/service/settings/settings"; + +export default function StaticToogle(props: { + id: number; + initChecked: boolean; +}) { + const { id, initChecked } = props; + const { toast } = useToast(); + const router = useRouter(); + + const changeStaticBanner = async (id: number) => { + const response = await setStaticBanner(id); + + if (response?.error) { + toast({ + variant: "destructive", + title: response?.message, + }); + return false; + } + + toast({ + title: "Success ", + }); + router.push("/admin/settings/banner?dataChange=true"); + }; + + return ( + { + changeStaticBanner(id); + }} + /> + ); +} diff --git a/app/[locale]/(protected)/admin/settings/popup/component/status-toogle.tsx b/app/[locale]/(protected)/admin/settings/popup/component/status-toogle.tsx new file mode 100644 index 00000000..22f11b79 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/status-toogle.tsx @@ -0,0 +1,37 @@ +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { useRouter } from "@/i18n/routing"; +import { setBanner } from "@/service/settings/settings"; + +export default function StatusToogle(props: { + id: number; + initChecked: boolean; +}) { + const { id, initChecked } = props; + const { toast } = useToast(); + const router = useRouter(); + + const disableBanner = async () => { + const response = await setBanner(id, false); + + if (response?.error) { + toast({ + variant: "destructive", + title: response?.message, + }); + return false; + } + + toast({ + title: "Success ", + }); + router.push("/admin/settings/banner?dataChange=true"); + }; + return ( + disableBanner()} + /> + ); +} diff --git a/app/[locale]/(protected)/admin/settings/popup/component/table.tsx b/app/[locale]/(protected)/admin/settings/popup/component/table.tsx new file mode 100644 index 00000000..f23f6709 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/component/table.tsx @@ -0,0 +1,393 @@ +"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 PopUpList = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + 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); + typingTimer = setTimeout(doneTyping, doneTypingInterval); + }; + + 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, + "", + 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 ( + <> +
+ +
+ + + + + + + + 1 - 10 Data + + + 1 - 20 Data + + + 1 - 25 Data + + + 1 - 50 Data + + + + + + + + + +
+ +
+

Kategory

+ {categories?.map((category: any) => ( +
+ + handleChange("category", category.id, Boolean(e)) + } + /> + +
+ ))} +

Status

+
+ + handleChange("status", 1, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 2, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 3, Boolean(e)) + } + /> + +
+
+ + handleChange("status", 4, Boolean(e)) + } + /> + +
+
+
+
+
+
+
+ + + {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 PopUpList; diff --git a/app/[locale]/(protected)/admin/settings/popup/page.tsx b/app/[locale]/(protected)/admin/settings/popup/page.tsx new file mode 100644 index 00000000..3a699be6 --- /dev/null +++ b/app/[locale]/(protected)/admin/settings/popup/page.tsx @@ -0,0 +1,52 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import ContentListTable from "../banner/component/table"; +import BannerListTable from "../banner/component/banner-table"; +import PopUpList from "./component/table"; +import PopUpListTable from "./component/popup-table"; + +export default function AdminPopup() { + const [selectedTab, setSelectedTab] = useState("content"); + + return ( +
+ +
+
+ {selectedTab === "content" ? "List Media" : " List Pop Up"} + +
+ + +
+
+ + {selectedTab === "content" ? : } +
+
+ ); +} diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx new file mode 100644 index 00000000..187d669c --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx @@ -0,0 +1,349 @@ +"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 { + ChevronDown, + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, + UploadIcon, +} 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"; +import { CardHeader, CardTitle } from "@/components/ui/card"; +import { Link } from "@/i18n/routing"; +import { useTranslations } from "next-intl"; +import useTableColumns from "./columns"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Label } from "@/components/ui/label"; + +const CalendarPolriTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const t = useTranslations("Schedule"); + 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 [showData, setShowData] = React.useState("50"); + const [pagination, setPagination] = React.useState({ + pageIndex: 0, + pageSize: Number(showData), + }); + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + const [search, setSearch] = React.useState(""); + const [statusFilter, setStatusFilter] = React.useState([]); + const columns = useTableColumns(); + 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, showData, search, statusFilter]); + + async function fetchData() { + try { + const res = await paginationSchedule( + showData, + page - 1, + 1, + search, + statusFilter + ); + 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 : ", contentData); + + setDataTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + const handleStatusCheckboxChange = (statusId: number) => { + const updatedFilter = statusFilter.includes(statusId) + ? statusFilter.filter((id) => id !== statusId) + : [...statusFilter, statusId]; + + setStatusFilter(updatedFilter); + }; + + const handleSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); // Perbarui state search + table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel + }; + + return ( +
+ + +
+
+ {t("press-conference")} {t("schedule")} +
+
+ + + +
+
+
+
+
+
+
+ + + + + + +
+
+
+ + + + + + + + 1 - 10 Data + + + 1 - 50 Data + + + 1 - 100 Data + + + 1 - 250 Data + + + + +
+
+ + + + + +
+

Filter

+
+ + +
+ handleStatusCheckboxChange(1)} + /> + +
+
+ handleStatusCheckboxChange(2)} + /> + +
+
+
+
+
+ + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + +
+
+
+ + + {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 CalendarPolriTable; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx new file mode 100644 index 00000000..1a3a3ae3 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/columns.tsx @@ -0,0 +1,183 @@ +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 { Link } from "@/components/navigation"; +import { useTranslations } from "next-intl"; + +const useTableColumns = () => { + const t = useTranslations("Table"); // Panggil di dalam hook + + const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: t("no"), + cell: ({ row }) => ( +
+
+

+ {row.getValue("no")} +

+
+
+ ), + }, + + { + accessorKey: "title", + header: t("title"), + cell: ({ row }: { row: { getValue: (key: string) => string } }) => { + const title: string = row.getValue("title"); + return ( + + {title.length > 50 ? `${title.slice(0, 30)}...` : title} + + ); + }, + }, + { + accessorKey: "startDate", + header: t("start-date"), + cell: ({ row }) => ( + {row.getValue("startDate")} + ), + }, + { + accessorKey: "endDate", + header: t("end-date"), + cell: ({ row }) => ( + {row.getValue("endDate")} + ), + }, + { + accessorKey: "time", + header: t("time"), + cell: ({ row }: { row: { original: any } }) => { + console.log("Row Original Data:", row.original); + const { startTime, endTime } = row.original; + return ( + + {startTime || "N/A"} - {endTime || "N/A"} + + ); + }, + }, + { + accessorKey: "address", + header: t("address"), + cell: ({ row }: { row: { getValue: (key: string) => string } }) => { + const address: string = row.getValue("address"); + return ( + + {address.length > 50 ? `${address.slice(0, 40)}...` : address} + + ); + }, + }, + { + accessorKey: "statusName", + header: "Status", + cell: ({ row }) => { + const statusColors: Record = { + 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 ( + + {status} {/* Tetap tampilkan nilai asli */} + + ); + }, + }, + { + accessorKey: "speaker", + header: t("speaker"), + cell: ({ row }: { row: { original: any } }) => { + console.log("Row Original Data:", row.original); + const { speakerTitle, speakerName } = row.original; + return ( + + {speakerTitle || ""} {speakerName || ""} + + ); + }, + }, + { + accessorKey: "uploaderName", + header: t("source"), + cell: ({ row }) => ( + + {row.getValue("uploaderName")} + + ), + }, + + { + id: "actions", + accessorKey: "action", + header: t("action"), + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + + + Detail + + + + + + Edit + + + + + Delete + + + + ); + }, + }, + ]; + + return columns; +}; + +export default useTableColumns; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx new file mode 100644 index 00000000..250cc651 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/create/page.tsx @@ -0,0 +1,17 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; + +const CalendarPolriCreatePage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default CalendarPolriCreatePage; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx new file mode 100644 index 00000000..f3347ffb --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/detail/[id]/page.tsx @@ -0,0 +1,21 @@ +"use client"; +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; +import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form"; +import { useParams } from "next/navigation"; +import { id } from "date-fns/locale"; + +const CalendarPolriDetailPage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default CalendarPolriDetailPage; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/layout.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/layout.tsx new file mode 100644 index 00000000..051b27cb --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/layout.tsx @@ -0,0 +1,9 @@ +export const metadata = { + title: "Press Conference", +}; + +const Layout = ({ children }: { children: React.ReactNode }) => { + return <>{children}; +}; + +export default Layout; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/page.tsx new file mode 100644 index 00000000..5f6bab97 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/page.tsx @@ -0,0 +1,21 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import PressConferenceTable from "../press-conference/components/presscon-table"; +import CalendarPolriTable from "./component/calendar-polri-table"; + +const CalendarPolriPage = async () => { + return ( +
+ +
+ + + + + +
+
+ ); +}; + +export default CalendarPolriPage; diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx new file mode 100644 index 00000000..ce527b9a --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/update/[id]/page.tsx @@ -0,0 +1,22 @@ +"use client"; +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; +import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form"; +import { useParams } from "next/navigation"; +import { id } from "date-fns/locale"; +import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form"; + +const CalendarPolriUpdatePage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default CalendarPolriUpdatePage; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/component/columns.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/component/columns.tsx new file mode 100644 index 00000000..1a3a3ae3 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/component/columns.tsx @@ -0,0 +1,183 @@ +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 { Link } from "@/components/navigation"; +import { useTranslations } from "next-intl"; + +const useTableColumns = () => { + const t = useTranslations("Table"); // Panggil di dalam hook + + const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: t("no"), + cell: ({ row }) => ( +
+
+

+ {row.getValue("no")} +

+
+
+ ), + }, + + { + accessorKey: "title", + header: t("title"), + cell: ({ row }: { row: { getValue: (key: string) => string } }) => { + const title: string = row.getValue("title"); + return ( + + {title.length > 50 ? `${title.slice(0, 30)}...` : title} + + ); + }, + }, + { + accessorKey: "startDate", + header: t("start-date"), + cell: ({ row }) => ( + {row.getValue("startDate")} + ), + }, + { + accessorKey: "endDate", + header: t("end-date"), + cell: ({ row }) => ( + {row.getValue("endDate")} + ), + }, + { + accessorKey: "time", + header: t("time"), + cell: ({ row }: { row: { original: any } }) => { + console.log("Row Original Data:", row.original); + const { startTime, endTime } = row.original; + return ( + + {startTime || "N/A"} - {endTime || "N/A"} + + ); + }, + }, + { + accessorKey: "address", + header: t("address"), + cell: ({ row }: { row: { getValue: (key: string) => string } }) => { + const address: string = row.getValue("address"); + return ( + + {address.length > 50 ? `${address.slice(0, 40)}...` : address} + + ); + }, + }, + { + accessorKey: "statusName", + header: "Status", + cell: ({ row }) => { + const statusColors: Record = { + 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 ( + + {status} {/* Tetap tampilkan nilai asli */} + + ); + }, + }, + { + accessorKey: "speaker", + header: t("speaker"), + cell: ({ row }: { row: { original: any } }) => { + console.log("Row Original Data:", row.original); + const { speakerTitle, speakerName } = row.original; + return ( + + {speakerTitle || ""} {speakerName || ""} + + ); + }, + }, + { + accessorKey: "uploaderName", + header: t("source"), + cell: ({ row }) => ( + + {row.getValue("uploaderName")} + + ), + }, + + { + id: "actions", + accessorKey: "action", + header: t("action"), + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + + + Detail + + + + + + Edit + + + + + Delete + + + + ); + }, + }, + ]; + + return columns; +}; + +export default useTableColumns; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx new file mode 100644 index 00000000..1b8e767c --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx @@ -0,0 +1,349 @@ +"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 { + ChevronDown, + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, + UploadIcon, +} 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"; +import { CardHeader, CardTitle } from "@/components/ui/card"; +import { Link } from "@/i18n/routing"; +import { useTranslations } from "next-intl"; +import useTableColumns from "./columns"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Label } from "@/components/ui/label"; + +const LiveReportTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const t = useTranslations("Schedule"); + 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 [showData, setShowData] = React.useState("50"); + const [pagination, setPagination] = React.useState({ + pageIndex: 0, + pageSize: Number(showData), + }); + const [page, setPage] = React.useState(1); + const [totalPage, setTotalPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + const [search, setSearch] = React.useState(""); + const [statusFilter, setStatusFilter] = React.useState([]); + const columns = useTableColumns(); + 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, showData, search, statusFilter]); + + async function fetchData() { + try { + const res = await paginationSchedule( + showData, + page - 1, + 1, + search, + statusFilter + ); + 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 : ", contentData); + + setDataTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + const handleStatusCheckboxChange = (statusId: number) => { + const updatedFilter = statusFilter.includes(statusId) + ? statusFilter.filter((id) => id !== statusId) + : [...statusFilter, statusId]; + + setStatusFilter(updatedFilter); + }; + + const handleSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); // Perbarui state search + table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel + }; + + return ( +
+ + +
+
+ {t("live-report")} {t("schedule")} +
+
+ + + +
+
+
+
+
+
+
+ + + + + + +
+
+
+ + + + + + + + 1 - 10 Data + + + 1 - 50 Data + + + 1 - 100 Data + + + 1 - 250 Data + + + + +
+
+ + + + + +
+

Filter

+
+ + +
+ handleStatusCheckboxChange(1)} + /> + +
+
+ handleStatusCheckboxChange(2)} + /> + +
+
+
+
+
+ + + + + + {table + .getAllColumns() + .filter((column) => column.getCanHide()) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ); + })} + + +
+
+
+ + + {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 LiveReportTable; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx new file mode 100644 index 00000000..2fdfb6fa --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx @@ -0,0 +1,17 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; + +const LiveReportCreatePage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default LiveReportCreatePage; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx new file mode 100644 index 00000000..422ea884 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx @@ -0,0 +1,21 @@ +"use client"; +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; +import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form"; +import { useParams } from "next/navigation"; +import { id } from "date-fns/locale"; + +const LiveReportDetailPage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default LiveReportDetailPage; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/layout.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/layout.tsx new file mode 100644 index 00000000..051b27cb --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/layout.tsx @@ -0,0 +1,9 @@ +export const metadata = { + title: "Press Conference", +}; + +const Layout = ({ children }: { children: React.ReactNode }) => { + return <>{children}; +}; + +export default Layout; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/page.tsx new file mode 100644 index 00000000..486550fd --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/page.tsx @@ -0,0 +1,22 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import PressConferenceTable from "../press-conference/components/presscon-table"; +import CalendarPolriTable from "./component/live-report-table"; +import LiveReportTable from "./component/live-report-table"; + +const LiveReportPage = async () => { + return ( +
+ +
+ + + + + +
+
+ ); +}; + +export default LiveReportPage; diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx new file mode 100644 index 00000000..025ada2a --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx @@ -0,0 +1,22 @@ +"use client"; +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormPressConference from "@/components/form/schedule/press-conference-form"; +import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form"; +import { useParams } from "next/navigation"; +import { id } from "date-fns/locale"; +import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form"; + +const LiveReportUpdatePage = () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default LiveReportUpdatePage; diff --git a/app/[locale]/(protected)/contributor/schedule/press-conference/page.tsx b/app/[locale]/(protected)/contributor/schedule/press-conference/page.tsx index 38284a1e..7d2f3e75 100644 --- a/app/[locale]/(protected)/contributor/schedule/press-conference/page.tsx +++ b/app/[locale]/(protected)/contributor/schedule/press-conference/page.tsx @@ -3,7 +3,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import PressConferenceTable from "./components/presscon-table"; -const PressConferencePage = async () => { +const CalendarPolriPage = async () => { return (
@@ -18,4 +18,4 @@ const PressConferencePage = async () => { ); }; -export default PressConferencePage; +export default CalendarPolriPage; diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 2bbdbef6..d7d3ded0 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -7,12 +7,9 @@ import ContentCategory from "@/components/landing-page/content-category"; import Coverage from "@/components/landing-page/coverage"; import Hero from "@/components/landing-page/hero"; import Footer from "@/components/landing-page/footer"; -import Division from "@/components/landing-page/division"; import Navbar from "@/components/landing-page/navbar"; import { ReactLenis } from "@studio-freight/react-lenis"; import MountedProvider from "@/providers/mounted.provider"; -import NewsTicker from "@/components/landing-page/news-tickers"; -import AreaCoverageWorkUnits from "@/components/landing-page/area-coverage-and-work-units"; import HeroNew from "@/components/landing-page/hero-new"; const Home = ({ params: { locale } }: { params: { locale: string } }) => { diff --git a/lib/menus.ts b/lib/menus.ts index f497d379..5c8413b2 100644 --- a/lib/menus.ts +++ b/lib/menus.ts @@ -180,24 +180,38 @@ export function getMenuList(pathname: string, t: any): Group[] { icon: "uil:schedule", submenus: [ { - href: "/contributor/schedule/press-conference", - label: t("press-conference"), - active: pathname.includes("/schedule/press-conference"), + href: "/contributor/schedule/live-report", + label: t("live-report"), + active: pathname.includes("/schedule/live-report"), icon: "heroicons:arrow-trending-up", children: [], }, + // { + // href: "/contributor/schedule/press-conference", + // label: t("press-conference"), + // active: pathname.includes("/schedule/press-conference"), + // icon: "heroicons:arrow-trending-up", + // children: [], + // }, + // { + // href: "/contributor/schedule/event", + // label: "event", + // active: pathname.includes("/schedule/event"), + // icon: "heroicons:shopping-cart", + // children: [], + // }, + // { + // href: "/contributor/schedule/press-release", + // label: t("press-release"), + // active: pathname.includes("/schedule/press-release"), + // icon: "heroicons:shopping-cart", + // children: [], + // }, { - href: "/contributor/schedule/event", - label: "event", - active: pathname.includes("/schedule/event"), - icon: "heroicons:shopping-cart", - children: [], - }, - { - href: "/contributor/schedule/press-release", - label: t("press-release"), - active: pathname.includes("/schedule/press-release"), - icon: "heroicons:shopping-cart", + href: "/contributor/schedule/calendar-polri", + label: t("calendar-polri"), + active: pathname.includes("/schedule/calendar-polri"), + icon: "heroicons:arrow-trending-up", children: [], }, ], @@ -271,20 +285,20 @@ export function getMenuList(pathname: string, t: any): Group[] { active: pathname.includes("/settinng"), icon: "material-symbols:settings", submenus: [ - { - href: "/admin/settings/category", - label: t("category"), - active: pathname === "/admin/settings/category", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/tag", - label: "Tag", - active: pathname === "/admin/settings/tag", - icon: "heroicons:arrow-trending-up", - children: [], - }, + // { + // href: "/admin/settings/category", + // label: t("category"), + // active: pathname === "/admin/settings/category", + // icon: "heroicons:arrow-trending-up", + // children: [], + // }, + // { + // href: "/admin/settings/tag", + // label: "Tag", + // active: pathname === "/admin/settings/tag", + // icon: "heroicons:arrow-trending-up", + // children: [], + // }, { href: "/admin/settings/banner", label: "Banner", @@ -292,6 +306,20 @@ export function getMenuList(pathname: string, t: any): Group[] { icon: "heroicons:arrow-trending-up", children: [], }, + { + href: "/admin/settings/popup", + label: "Pop Up", + active: pathname === "/admin/settings/popup", + icon: "heroicons:arrow-trending-up", + children: [], + }, + { + href: "/admin/settings/iklan", + label: "Iklan", + active: pathname === "/admin/settings/iklan", + icon: "heroicons:arrow-trending-up", + children: [], + }, // { // href: "/admin/settings/feedback", // label: "Feedback", @@ -1865,20 +1893,6 @@ export function getMenuList(pathname: string, t: any): Group[] { active: pathname.includes("/settinng"), icon: "material-symbols:settings", submenus: [ - { - href: "/admin/settings/category", - label: t("category"), - active: pathname === "/admin/settings/category", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/tag", - label: "Tag", - active: pathname === "/admin/settings/tag", - icon: "heroicons:arrow-trending-up", - children: [], - }, { href: "/admin/settings/banner", label: "Banner", @@ -1887,30 +1901,16 @@ export function getMenuList(pathname: string, t: any): Group[] { children: [], }, { - href: "/admin/settings/feedback", - label: "Feedback", - active: pathname === "/admin/settings/feedback", + href: "/admin/settings/popup", + label: "Pop Up", + active: pathname === "/admin/settings/popup", icon: "heroicons:arrow-trending-up", children: [], }, { - href: "/admin/settings/faq", - label: "FAQ", - active: pathname === "/admin/settings/faq", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "https://nat-mediahub.polri.go.id/", - label: "Mediahub 2022", - active: pathname === "/admin/settings/mediahub-2022", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/privacy", - label: t("privacy"), - active: pathname === "/admin/settings/privacy", + href: "/admin/settings/iklan", + label: "Iklan", + active: pathname === "/admin/settings/iklan", icon: "heroicons:arrow-trending-up", children: [], }, @@ -2323,20 +2323,6 @@ export function getMenuList(pathname: string, t: any): Group[] { active: pathname.includes("/settinng"), icon: "material-symbols:settings", submenus: [ - { - href: "/admin/settings/category", - label: t("category"), - active: pathname === "/admin/settings/category", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/tag", - label: "Tag", - active: pathname === "/admin/settings/tag", - icon: "heroicons:arrow-trending-up", - children: [], - }, { href: "/admin/settings/banner", label: "Banner", @@ -2345,30 +2331,16 @@ export function getMenuList(pathname: string, t: any): Group[] { children: [], }, { - href: "/admin/settings/feedback", - label: "Feedback", - active: pathname === "/admin/settings/feedback", + href: "/admin/settings/popup", + label: "Pop Up", + active: pathname === "/admin/settings/popup", icon: "heroicons:arrow-trending-up", children: [], }, { - href: "/admin/settings/faq", - label: "FAQ", - active: pathname === "/admin/settings/faq", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "https://nat-mediahub.polri.go.id/", - label: "Mediahub 2022", - active: pathname === "/admin/settings/mediahub-2022", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/privacy", - label: t("privacy"), - active: pathname === "/admin/settings/privacy", + href: "/admin/settings/iklan", + label: "Iklan", + active: pathname === "/admin/settings/iklan", icon: "heroicons:arrow-trending-up", children: [], }, @@ -2596,20 +2568,6 @@ export function getMenuList(pathname: string, t: any): Group[] { active: pathname.includes("/settinng"), icon: "material-symbols:settings", submenus: [ - { - href: "/admin/settings/category", - label: t("category"), - active: pathname === "/admin/settings/category", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/tag", - label: "Tag", - active: pathname === "/admin/settings/tag", - icon: "heroicons:arrow-trending-up", - children: [], - }, { href: "/admin/settings/banner", label: "Banner", @@ -2618,30 +2576,16 @@ export function getMenuList(pathname: string, t: any): Group[] { children: [], }, { - href: "/admin/settings/feedback", - label: "Feedback", - active: pathname === "/admin/settings/feedback", + href: "/admin/settings/popup", + label: "Pop Up", + active: pathname === "/admin/settings/popup", icon: "heroicons:arrow-trending-up", children: [], }, { - href: "/admin/settings/faq", - label: "FAQ", - active: pathname === "/admin/settings/faq", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "https://nat-mediahub.polri.go.id/", - label: "Mediahub 2022", - active: pathname === "/admin/settings/mediahub-2022", - icon: "heroicons:arrow-trending-up", - children: [], - }, - { - href: "/admin/settings/privacy", - label: t("privacy"), - active: pathname === "/admin/settings/privacy", + href: "/admin/settings/iklan", + label: "Iklan", + active: pathname === "/admin/settings/iklan", icon: "heroicons:arrow-trending-up", children: [], }, diff --git a/messages/en.json b/messages/en.json index 07ba87c3..c4e283b0 100644 --- a/messages/en.json +++ b/messages/en.json @@ -342,7 +342,9 @@ "contact": "Contact", "ptt": "PTT", "web-chat": "Web-Chat", - "setting-tracking": "Media Tracking" + "setting-tracking": "Media Tracking", + "calendar-polri": "Calendar Polri", + "live-report": "Live Report" }, "Changelog": { "version": "Version's", @@ -596,7 +598,8 @@ "press-conference": "Press Conference", "press-release": "Press Release", "create-schedule": "Create Schedule", - "event": "event" + "event": "event", + "live-report": "Live Report" }, "Blog": { "table": "Table", diff --git a/messages/in.json b/messages/in.json index d4812412..6b0171b5 100644 --- a/messages/in.json +++ b/messages/in.json @@ -343,7 +343,9 @@ "contact": "kontak", "ptt": "PTT", "web-chat": "Web-Chat", - "setting-tracking": "Media Tracking" + "setting-tracking": "Media Tracking", + "calendar-polri": "Kalender Polri", + "live-report": "Live Report" }, "Changelog": { "version": "Version's", @@ -597,7 +599,8 @@ "press-conference": "Konferensi Pers", "press-release": "Pers Rilis", "create-schedule": "Buat Jadwal", - "event": "event" + "event": "event", + "live-report": "Live Report" }, "Blog": { "table": "Tabel", From 883abc9402425e54c9b5e0d2081a088f577981c3 Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Fri, 30 May 2025 23:24:39 +0800 Subject: [PATCH 2/2] [QUDO-129,QUDO-122] feat:live report and media tracking --- .../component/calendar-polri-table.tsx | 2 +- .../component/live-report-table.tsx | 34 +- .../schedule/live-report/create/page.tsx | 3 +- .../schedule/live-report/detail/[id]/page.tsx | 3 +- .../schedule/live-report/update/[id]/page.tsx | 3 +- .../form/schedule/live-report-detail-form.tsx | 407 +++++++++++++++++ components/form/schedule/live-report-form.tsx | 384 ++++++++++++++++ .../form/schedule/live-report-update-form.tsx | 409 ++++++++++++++++++ messages/en.json | 3 +- messages/in.json | 3 +- 10 files changed, 1242 insertions(+), 9 deletions(-) create mode 100644 components/form/schedule/live-report-detail-form.tsx create mode 100644 components/form/schedule/live-report-form.tsx create mode 100644 components/form/schedule/live-report-update-form.tsx diff --git a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx index 187d669c..10116e1e 100644 --- a/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx +++ b/app/[locale]/(protected)/contributor/schedule/calendar-polri/component/calendar-polri-table.tsx @@ -158,7 +158,7 @@ const CalendarPolriTable = () => {
- {t("press-conference")} {t("schedule")} + {t("calendar-polri")} {t("schedule")}
diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx index 1b8e767c..cbe89c77 100644 --- a/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx +++ b/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx @@ -57,6 +57,15 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; const LiveReportTable = () => { const router = useRouter(); @@ -81,6 +90,7 @@ const LiveReportTable = () => { const [limit, setLimit] = React.useState(10); const [search, setSearch] = React.useState(""); const [statusFilter, setStatusFilter] = React.useState([]); + const [selectedType, setSelectedType] = React.useState("1"); const columns = useTableColumns(); const table = useReactTable({ data: dataTable, @@ -112,14 +122,14 @@ const LiveReportTable = () => { React.useEffect(() => { fetchData(); - }, [page, showData, search, statusFilter]); + }, [page, showData, search, statusFilter, selectedType]); async function fetchData() { try { const res = await paginationSchedule( showData, page - 1, - 1, + selectedType, search, statusFilter ); @@ -161,7 +171,7 @@ const LiveReportTable = () => { {t("live-report")} {t("schedule")}
- +
+
+ +
diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx index 2fdfb6fa..1e7adc20 100644 --- a/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx +++ b/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx @@ -2,13 +2,14 @@ import { Card, CardContent } from "@/components/ui/card"; import SiteBreadcrumb from "@/components/site-breadcrumb"; import FormTask from "@/components/form/task/task-form"; import FormPressConference from "@/components/form/schedule/press-conference-form"; +import FormLiveReport from "@/components/form/schedule/live-report-form"; const LiveReportCreatePage = () => { return (
- +
); diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx index 422ea884..273f3b55 100644 --- a/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx +++ b/app/[locale]/(protected)/contributor/schedule/live-report/detail/[id]/page.tsx @@ -6,13 +6,14 @@ import FormPressConference from "@/components/form/schedule/press-conference-for import FormDetailPressConference from "@/components/form/schedule/press-conference-detail-form"; import { useParams } from "next/navigation"; import { id } from "date-fns/locale"; +import FormDetailLiveReport from "@/components/form/schedule/live-report-detail-form"; const LiveReportDetailPage = () => { return (
- +
); diff --git a/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx index 025ada2a..109a315f 100644 --- a/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx +++ b/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx @@ -7,13 +7,14 @@ import FormDetailPressConference from "@/components/form/schedule/press-conferen import { useParams } from "next/navigation"; import { id } from "date-fns/locale"; import FormUpdatePressConference from "@/components/form/schedule/press-conference-update-form"; +import FormUpdateLiveReport from "@/components/form/schedule/live-report-update-form"; const LiveReportUpdatePage = () => { return (
- +
); diff --git a/components/form/schedule/live-report-detail-form.tsx b/components/form/schedule/live-report-detail-form.tsx new file mode 100644 index 00000000..2bd4d714 --- /dev/null +++ b/components/form/schedule/live-report-detail-form.tsx @@ -0,0 +1,407 @@ +"use client"; +import React, { useEffect, useRef, useState } from "react"; +import { useForm, Controller } from "react-hook-form"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Card } from "@/components/ui/card"; +import { zodResolver } from "@hookform/resolvers/zod"; +import * as z from "zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { useParams, useRouter } from "next/navigation"; +import { Switch } from "@/components/ui/switch"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { cn } from "@/lib/utils"; +import { CalendarIcon, Clock1, Locate, MapPin, User2 } from "lucide-react"; +import { Calendar } from "@/components/ui/calendar"; +import { addDays, format, parseISO, setDate } from "date-fns"; +import { DateRange } from "react-day-picker"; +import TimePicker from "react-time-picker"; +import "react-time-picker/dist/TimePicker.css"; +import "react-clock/dist/Clock.css"; +import MapHome from "@/components/maps/MapHome"; +import { Textarea } from "@/components/ui/textarea"; +import { error, loading } from "@/lib/swal"; +import Cookies from "js-cookie"; +import { + detailSchedule, + listScheduleNext, + listScheduleToday, + postSchedule, +} from "@/service/schedule/schedule"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { formatDateToIndonesian } from "@/utils/globals"; +import { formatDate } from "@fullcalendar/core/index.js"; + +const taskSchema = z.object({ + title: z.string().min(1, { message: "Judul diperlukan" }), + level: z.string().min(1, { message: "Judul diperlukan" }), + name: z.string().min(1, { message: "Judul diperlukan" }), + location: z.string().min(1, { message: "Judul diperlukan" }), +}); + +interface Detail { + id: number; + title: string; + address: string; + speakerTitle: string; + speakerName: string; + addressLat: number; + addressLong: number; +} + +export default function FormDetailLiveReport() { + const { id } = useParams() as { id: string }; + console.log(id); + const router = useRouter(); + const [isLiveStreamingEnabled, setIsLiveStreamingEnabled] = useState(false); + type TaskSchema = z.infer; + const [startTime, setStartTime] = useState("08:00"); + const [endTime, setEndTime] = useState("09:00"); + const [date, setDate] = useState(); + const [todayList, setTodayList] = useState([]); + const [nextDayList, setNextDayList] = useState([]); + + const [detail, setDetail] = useState(); + const [refresh, setRefresh] = useState(false); + + const { + control, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + defaultValues: { + location: "", + }, + }); + + async function getDataByDate() { + const resToday = await listScheduleToday(); + const today = resToday?.data?.data; + setTodayList(today); + const resNext = await listScheduleNext(); + const next = resNext?.data?.data; + + setNextDayList(next); + } + + useEffect(() => { + async function initState() { + if (id) { + const response = await detailSchedule(id); + const details = response?.data?.data; + + setDetail(details); + if (details) { + setDate({ + from: parseISO(details.startDate), + to: parseISO(details.endDate), + }); + } + if (details) { + setStartTime(details.startTime); + setEndTime(details.endTime); + } + getDataByDate(); + } + } + initState(); + }, [refresh, setValue]); + + const handleStartTime = (e: React.ChangeEvent) => { + setStartTime(e.target.value); + }; + + const handleEndTime = (e: React.ChangeEvent) => { + setEndTime(e.target.value); + }; + + return ( +
+ +
+

Form Konferensi Pers

+ {detail !== undefined ? ( +
+ {/* Input Title */} +
+ + ( + + )} + /> + {errors.title?.message && ( +

{errors.title.message}

+ )} +
+
+
+ +
+

Aktifkan fitur live streaming

+ + setIsLiveStreamingEnabled(checked) + } + /> +
+
+
+ + {isLiveStreamingEnabled && ( +
+ ( + + )} + /> + {errors.title?.message && ( +

+ {errors.title.message} +

+ )} +
+ )} + +
+
+ + + + + + + + + +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ {/* Kirim setValue ke MapHome */} + setValue("location", location)} + /> +
+
+ ( +