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..10116e1e --- /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("calendar-polri")} {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..cbe89c77 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/component/live-report-table.tsx @@ -0,0 +1,377 @@ +"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"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +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 [selectedType, setSelectedType] = React.useState("1"); + 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, selectedType]); + + async function fetchData() { + try { + const res = await paginationSchedule( + showData, + page - 1, + selectedType, + 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..1e7adc20 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/create/page.tsx @@ -0,0 +1,18 @@ +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 ( +
+ +
+ +
+
+ ); +}; + +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..273f3b55 --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/detail/[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 FormDetailLiveReport from "@/components/form/schedule/live-report-detail-form"; + +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..109a315f --- /dev/null +++ b/app/[locale]/(protected)/contributor/schedule/live-report/update/[id]/page.tsx @@ -0,0 +1,23 @@ +"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"; +import FormUpdateLiveReport from "@/components/form/schedule/live-report-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 81b1ff9b..6839f537 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -5,7 +5,6 @@ import Footer from "@/components/landing-page/footer"; import Navbar from "@/components/landing-page/navbar"; import { ReactLenis } from "@studio-freight/react-lenis"; import MountedProvider from "@/providers/mounted.provider"; - import HeroNew from "@/components/landing-page/hero-new"; const Home = ({ params: { locale } }: { params: { locale: string } }) => { 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)} + /> +
+
+ ( +