diff --git a/app/[locale]/(protected)/curator/media-tracking/component/column.tsx b/app/[locale]/(protected)/curator/media-tracking/component/column.tsx new file mode 100644 index 00000000..e469400f --- /dev/null +++ b/app/[locale]/(protected)/curator/media-tracking/component/column.tsx @@ -0,0 +1,90 @@ +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 { 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"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + + { + accessorKey: "title", + header: "Judul", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "date", + header: "Tanggal Masuk", + cell: ({ row }) => {row.getValue("date")}, + }, + + { + accessorKey: "duration", + header: "Durasi", + cell: ({ row }) => {row.getValue("duration")}, + }, + { + accessorKey: "crawling", + header: "Model Crawling", + cell: ({ row }) => {row.getValue("crawling")}, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => {row.getValue("status")}, + }, + { + id: "actions", + accessorKey: "action", + header: "Aksi", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + Detail + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/curator/media-tracking/component/table.tsx b/app/[locale]/(protected)/curator/media-tracking/component/table.tsx new file mode 100644 index 00000000..d29f7972 --- /dev/null +++ b/app/[locale]/(protected)/curator/media-tracking/component/table.tsx @@ -0,0 +1,180 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { Button } from "@/components/ui/button"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import { paginationBlog } from "@/service/blog/blog"; +import { ticketingPagination } from "@/service/ticketing/ticketing"; +import { Badge } from "@/components/ui/badge"; +import { useRouter, useSearchParams } from "next/navigation"; +import TablePagination from "@/components/table/table-pagination"; +import columns from "./column"; +import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; +import { getMediaTrackingMonitoring } from "@/service/media-tracking/media-tracking"; + +const MediaTrackingTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + 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: 10, + }); + const [page, setPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + 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, + }, + }); + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + React.useEffect(() => { + fetchData(); + }, [page, limit]); + + async function fetchData() { + try { + const response = await getMediaTrackingMonitoring(page, 10); + const data = response.data?.data; + const contentData = data?.content; + contentData.forEach((item: any, index: number) => { + item.no = (page - 1) * limit + index + 1; + }); + + console.log("contentData : ", data); + + setDataTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + 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 MediaTrackingTable; diff --git a/app/[locale]/(protected)/curator/media-tracking/page.tsx b/app/[locale]/(protected)/curator/media-tracking/page.tsx new file mode 100644 index 00000000..5e43e9b7 --- /dev/null +++ b/app/[locale]/(protected)/curator/media-tracking/page.tsx @@ -0,0 +1,11 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import MediaTrackingTable from "./component/table"; + +export default function MediaTracking() { + return ( +
+ + +
+ ); +} diff --git a/app/[locale]/(protected)/curator/task-plan/mediahub/create-daily/page.tsx b/app/[locale]/(protected)/curator/task-plan/mediahub/create-daily/page.tsx index 9ecaeaec..a14dcb8f 100644 --- a/app/[locale]/(protected)/curator/task-plan/mediahub/create-daily/page.tsx +++ b/app/[locale]/(protected)/curator/task-plan/mediahub/create-daily/page.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/popover"; import { Link } from "@/i18n/routing"; import { CalendarIcon } from "lucide-react"; -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { cn } from "@/lib/utils"; import { format } from "date-fns"; import JoditEditor from "jodit-react"; @@ -30,6 +30,21 @@ import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { getUserLevelForAssignments } from "@/service/task"; +import { list } from "postcss"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; const FormSchema = z.object({ date: z.date({ @@ -73,20 +88,22 @@ const items = [ const units = [ { - id: "mabes", + id: "1", label: "Mabes Polri", }, { - id: "polda", + id: "2", label: "Polda", }, { - id: "polres", + id: "3", label: "Polres", }, ]; -export default function CreateMonthly() { +export default function CreateDaily() { const MySwal = withReactContent(Swal); + const [listDest, setListDest] = useState([]); + const [destination, setDestination] = useState([]); const form = useForm>({ resolver: zodResolver(FormSchema), @@ -164,10 +181,82 @@ export default function CreateMonthly() { }; const handleUnitCheckedChange = (id: string, checked: boolean | string) => { - form.setValue( - "unit", - checked ? [...unit, id] : unit.filter((value) => value !== id) - ); + if (checked) { + form.setValue("unit", [...unit, id]); + } else { + if (id == "2") { + const temp = []; + for (const element of unit) { + if (element == "1") { + temp.push("1"); + } + } + form.setValue("unit", temp); + } else { + form.setValue( + "unit", + unit.filter((value) => value !== id) + ); + } + } + }; + + useEffect(() => { + async function initState() { + const response = await getUserLevelForAssignments(); + console.log("response", response); + setListDest(response.data.data.list); + } + + initState(); + }, []); + + const handleDestination = (e: any) => { + let arrayDestination = []; + + for (const element of destination) { + arrayDestination.push(element); + } + + if (e.target.name == "all") { + if (e.target.checked == true) { + const count = document.querySelectorAll(".input-all"); + for (const element of Array.from(count)) { + arrayDestination.push((element as HTMLInputElement).value); + } + } else { + arrayDestination = []; + } + } else if (e.target.name == `subAll${e.target.value}`) { + if (e.target.checked == true) { + const count = document.getElementsByClassName( + `input-suball-${e.target.value}` + ); + arrayDestination.push(e.target.value); + for (const element of Array.from(count)) { + arrayDestination.push((element as HTMLInputElement).value); + } + } else { + const count = document.getElementsByClassName( + `input-suball-${e.target.value}` + ); + + arrayDestination.splice(destination.indexOf(e.target.value), 1); + for (const element of Array.from(count)) { + const index = arrayDestination.indexOf( + (element as HTMLInputElement).value + ); + if (index > -1) { + arrayDestination.splice(index, 1); + } + } + } + } else if (e.target.checked == true) { + arrayDestination.push(e.target.value); + } else { + arrayDestination.splice(destination.indexOf(e.target.value), 1); + } + setDestination(arrayDestination); }; return ( @@ -226,7 +315,6 @@ export default function CreateMonthly() { handleAllCheckedChange(checked) } @@ -305,8 +393,7 @@ export default function CreateMonthly() { handleUnitCheckedChange(item.id, checked) @@ -321,6 +408,108 @@ export default function CreateMonthly() { }} /> ))} + + + + {`[Kustom]`} + + + + + + Daftar Wilayah Polda dan Polres + + +
+ {listDest?.map((list: any) => ( +
+ + +
+ + + +
+ +
+
+ + +
+ {list.subDestination.map( + (subDes: any) => ( +
+ + +
+ ) + )} +
+
+
+
+
+ ))} +
+
+
diff --git a/app/[locale]/(protected)/curator/task-plan/mediahub/create-monthly/page.tsx b/app/[locale]/(protected)/curator/task-plan/mediahub/create-monthly/page.tsx index a751e2a4..19f8ccbd 100644 --- a/app/[locale]/(protected)/curator/task-plan/mediahub/create-monthly/page.tsx +++ b/app/[locale]/(protected)/curator/task-plan/mediahub/create-monthly/page.tsx @@ -83,7 +83,9 @@ export default function CreateMonthly() { time: "3", description: data.detail, username: "", - date: new Date(data.month).getMonth() + 1, + date: `${new Date(data.month).getMonth() + 1}/${new Date( + data.month + ).getFullYear()}`, status: "Open", }; console.log("req", reqData, data.month); diff --git a/app/[locale]/(protected)/curator/task-plan/mediahub/create-weekly/page.tsx b/app/[locale]/(protected)/curator/task-plan/mediahub/create-weekly/page.tsx index 1c6bc2ae..3547775f 100644 --- a/app/[locale]/(protected)/curator/task-plan/mediahub/create-weekly/page.tsx +++ b/app/[locale]/(protected)/curator/task-plan/mediahub/create-weekly/page.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/popover"; import { Link, useRouter } from "@/i18n/routing"; import { CalendarIcon } from "lucide-react"; -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { cn } from "@/lib/utils"; import { format } from "date-fns"; import JoditEditor from "jodit-react"; @@ -30,7 +30,18 @@ import Swal from "sweetalert2"; import withReactContent from "sweetalert2-react-content"; import { error } from "@/config/swal"; import { getOnlyDate } from "@/utils/globals"; -import { savePlanning } from "@/service/agenda-setting/agenda-setting"; +import { + getMonthlyPlanList, + savePlanning, +} from "@/service/agenda-setting/agenda-setting"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import dayjs from "dayjs"; const FormSchema = z.object({ week: z.object({ @@ -47,6 +58,9 @@ const FormSchema = z.object({ detail: z.string({ required_error: "Required", }), + parentId: z.string({ + required_error: "Required", + }), }); export default function CreateMonthly() { const MySwal = withReactContent(Swal); @@ -57,6 +71,8 @@ export default function CreateMonthly() { detail: "", }, }); + const [monthlyList, setMonthlyList] = useState(); + const editor = useRef(null); const onSubmit = async (data: z.infer) => { @@ -91,6 +107,7 @@ export default function CreateMonthly() { username: "", date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`, status: "Open", + parentId: Number(data.parentId), }; console.log("req", reqData); const response = await savePlanning(reqData); @@ -112,6 +129,24 @@ export default function CreateMonthly() { }); }; + useEffect(() => { + getMonthlyPlanning(); + }, []); + + async function getMonthlyPlanning() { + const res = await getMonthlyPlanList(new Date().getDate(), 1); + + if (res.data !== null) { + const rawUser = res.data?.data; + const optionArr = rawUser.map((option: any) => ({ + id: option.id, + label: option.title, + value: String(option.id), + })); + console.log("ssss", optionArr); + setMonthlyList(optionArr); + } + } return (
@@ -198,6 +233,31 @@ export default function CreateMonthly() { )} /> + ( + + Perencanaan Bulanan + + + + + )} + /> [] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + { + accessorKey: "title", + header: "Judul Perencanaan", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "createdByName", + header: "Nama Pembuat", + cell: ({ row }) => {row.getValue("createdByName")}, + }, + { + accessorKey: "description", + header: "Deskripsi", + cell: ({ row }) => {htmlToString(row.getValue("description"))}, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => {row.getValue("status")}, + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + + Detail + + + + + ); + }, + }, +]; + +export default columns; diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/components/table.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/components/table.tsx new file mode 100644 index 00000000..68cd40ee --- /dev/null +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/components/table.tsx @@ -0,0 +1,183 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { Button } from "@/components/ui/button"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import { paginationBlog } from "@/service/blog/blog"; +import { ticketingPagination } from "@/service/ticketing/ticketing"; +import { Badge } from "@/components/ui/badge"; +import { useRouter, useSearchParams } from "next/navigation"; +import TablePagination from "@/components/table/table-pagination"; +import columns from "./columns"; + +const TaskPlanMediahubTable = (props: { + data: any; + totalPage: number; + totalData: number; +}) => { + const { data, totalPage, totalData } = props; + const router = useRouter(); + const searchParams = useSearchParams(); + + 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: 10, + }); + const [page, setPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + + const table = useReactTable({ + data: dataTable, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + onPaginationChange: setPagination, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + pagination, + }, + }); + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + React.useEffect(() => { + fetchData(); + }, [page, limit, data]); + + async function fetchData() { + // try { + // const res = await ticketingPagination("", limit, page - 1); + // const data = res.data?.data; + console.log("datgaa", data); + const contentData = data; + contentData.forEach((item: any, index: number) => { + item.no = (page - 1) * limit + index + 1; + }); + + console.log("contentData : ", contentData); + + setDataTable(contentData); + // setTotalData(data?.totalElements); + // } catch (error) { + // console.error("Error fetching tasks:", error); + // } + } + + 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 TaskPlanMediahubTable; diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-daily/page.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-daily/page.tsx new file mode 100644 index 00000000..a2161ab3 --- /dev/null +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-daily/page.tsx @@ -0,0 +1,436 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Link } from "@/i18n/routing"; +import { CalendarIcon } from "lucide-react"; +import React, { useRef, useState } from "react"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import JoditEditor from "jodit-react"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { Checkbox } from "@/components/ui/checkbox"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; + +const FormSchema = z.object({ + date: z.date({ + required_error: "Required", + }), + title: z.string({ + required_error: "Required", + }), + detail: z.string({ + required_error: "Required", + }), + output: z.array(z.string()).refine((value) => value.some((item) => item), { + message: "Required", + }), + unit: z.array(z.string()).refine((value) => value.some((item) => item), { + message: "Required", + }), + type: z.enum(["publication", "amplification", "contra"], { + required_error: "Required", + }), +}); + +const items = [ + { + id: "video", + label: "Audio Visual", + }, + { + id: "image", + label: "Foto", + }, + { + id: "audio", + label: "Audio", + }, + { + id: "text", + label: "Text", + }, +]; + +const units = [ + { + id: "mabes", + label: "Mabes Polri", + }, + { + id: "polda", + label: "Polda", + }, + { + id: "polres", + label: "Polres", + }, +]; +export default function CreateMonthly() { + const MySwal = withReactContent(Swal); + + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + unit: [], + output: [], + detail: "", + }, + }); + const editor = useRef(null); + + const onSubmit = async (data: z.infer) => { + console.log("data", data); + if (form.getValues("detail") == "") { + form.setError("detail", { + type: "manual", + message: "Required", + }); + } else { + MySwal.fire({ + title: "Simpan Data", + text: "Apakah Anda yakin ingin menyimpan data ini?", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Simpan", + }).then((result) => { + if (result.isConfirmed) { + save(data); + } + }); + } + }; + + const save = async (data: z.infer) => { + console.log("data", data); + }; + + const output = form.watch("output"); + + const isAllChecked = items.every((item) => output?.includes(item.id)); + + const unit = form.watch("unit"); + + const isAllUnitChecked = units.every((item) => unit?.includes(item.id)); + + const handleAllCheckedChange = (checked: boolean | string) => { + if (checked) { + form.setValue( + "output", + items.map((item) => item.id) + ); + } else { + form.setValue("output", []); + } + }; + + const handleItemCheckedChange = (id: string, checked: boolean | string) => { + form.setValue( + "output", + checked ? [...output, id] : output.filter((value) => value !== id) + ); + }; + + const handleAllUnitCheckedChange = (checked: boolean | string) => { + if (checked) { + form.setValue( + "unit", + units.map((item) => item.id) + ); + } else { + form.setValue("unit", []); + } + }; + + const handleUnitCheckedChange = (id: string, checked: boolean | string) => { + form.setValue( + "unit", + checked ? [...unit, id] : unit.filter((value) => value !== id) + ); + }; + + return ( +
+ +
+
+ + Bulanan + + + Mingguan + + +
+ Harian +
+
+
+

Perencanaan MediaHub

+ +
+ + ( + + Judul Perencanaan + + + + + )} + /> + ( + +
+ Output Tugas +
+
+
+ + handleAllCheckedChange(checked) + } + /> + +
+ + {items.map((item) => ( + { + return ( + + + + handleItemCheckedChange(item.id, checked) + } + /> + + + {item.label} + + + ); + }} + /> + ))} +
+ +
+ )} + /> + ( + +
+ Pelaksana Tugas +
+
+
+ + handleAllUnitCheckedChange(checked) + } + /> + +
+ + {units.map((item) => ( + { + return ( + + + + handleUnitCheckedChange(item.id, checked) + } + /> + + + {item.label} + + + ); + }} + /> + ))} +
+ +
+ )} + /> + ( + + Jenis Penugasan + + + + + + + + Publikasi + + + + + + + + Amplifikasi + + + + + + + Kontra + + + + + + )} + /> + ( + + Pilih Tanggal + + + + + + + + + + + )} + /> + ( + + Detail Perencanaan + + + + + )} + /> +
+ + +
+ + +
+
+
+ ); +} diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-monthly/page.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-monthly/page.tsx new file mode 100644 index 00000000..c092c096 --- /dev/null +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-monthly/page.tsx @@ -0,0 +1,229 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Link, useRouter } from "@/i18n/routing"; +import { CalendarIcon } from "lucide-react"; +import React, { useRef, useState } from "react"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import JoditEditor from "jodit-react"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { error } from "@/config/swal"; +import { savePlanning } from "@/service/agenda-setting/agenda-setting"; + +const FormSchema = z.object({ + month: z.date({ + required_error: "Required", + }), + title: z.string({ + required_error: "Required", + }), + detail: z.string({ + required_error: "Required", + }), +}); +export default function CreateMonthly() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + detail: "", + }, + }); + const editor = useRef(null); + + const onSubmit = async (data: z.infer) => { + if (form.getValues("detail") == "") { + form.setError("detail", { + type: "manual", + message: "Required", + }); + } else { + MySwal.fire({ + title: "Simpan Data", + text: "Apakah Anda yakin ingin menyimpan data ini?", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Simpan", + }).then((result) => { + if (result.isConfirmed) { + save(data); + } + }); + } + }; + + const save = async (data: z.infer) => { + const reqData = { + planningTypeId: 2, + title: data.title, + time: "3", + description: data.detail, + username: "", + date: `${new Date(data.month).getMonth() + 1}/${new Date( + data.month + ).getFullYear()}`, + status: "Open", + }; + console.log("req", reqData, data.month); + const response = await savePlanning(reqData); + close(); + if (response.error) { + error(response.message); + return false; + } + + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + router.push("/curator/task-plan/medsos-mediahub"); + } + }); + }; + + const handleMonthSelect = (selectedDate: Date | undefined) => { + if (!selectedDate) return; + const newDate = new Date( + selectedDate.getFullYear(), + selectedDate.getMonth(), + 1 + ); + form.setValue("month", newDate); + }; + return ( +
+ +
+
+
+ Bulanan +
+ + Mingguan + + + Harian + +
+
+

Perencanaan MediaHub Bulanan

+ +
+ + ( + + Judul Perencanaan + + + + + )} + /> + ( + + Pilih Bulan + + + + + + + + + + + )} + /> + ( + + Detail Perencanaan + + + + + )} + /> +
+ + +
+ + +
+
+
+ ); +} diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-weekly/page.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-weekly/page.tsx new file mode 100644 index 00000000..ccea6fb7 --- /dev/null +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/create-weekly/page.tsx @@ -0,0 +1,292 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Link, useRouter } from "@/i18n/routing"; +import { CalendarIcon } from "lucide-react"; +import React, { useEffect, useRef, useState } from "react"; +import { cn } from "@/lib/utils"; +import { format } from "date-fns"; +import JoditEditor from "jodit-react"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { error } from "@/config/swal"; +import { getOnlyDate } from "@/utils/globals"; +import { + getMonthlyPlanList, + savePlanning, +} from "@/service/agenda-setting/agenda-setting"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +const FormSchema = z.object({ + week: z.object({ + from: z.date({ + required_error: "Start date (from) is required", + }), + to: z.date({ + required_error: "End date (to) is required", + }), + }), + title: z.string({ + required_error: "Required", + }), + detail: z.string({ + required_error: "Required", + }), + parentId: z.string({ + required_error: "Required", + }), +}); +export default function CreateMonthly() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + detail: "", + }, + }); + const [monthlyList, setMonthlyList] = useState(); + + const editor = useRef(null); + + const onSubmit = async (data: z.infer) => { + if (form.getValues("detail") == "") { + form.setError("detail", { + type: "manual", + message: "Required", + }); + } else { + MySwal.fire({ + title: "Simpan Data", + text: "Apakah Anda yakin ingin menyimpan data ini?", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Simpan", + }).then((result) => { + if (result.isConfirmed) { + save(data); + } + }); + } + }; + + const save = async (data: z.infer) => { + const reqData = { + planningTypeId: 2, + title: data.title, + time: "2", + description: data.detail, + username: "", + date: `${getOnlyDate(data.week.from)} - ${getOnlyDate(data.week.to)}`, + status: "Open", + parentId: Number(data.parentId), + }; + console.log("req", reqData); + const response = await savePlanning(reqData); + close(); + if (response.error) { + error(response.message); + return false; + } + + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + router.push("/curator/task-plan/medsos-mediahub"); + } + }); + }; + + useEffect(() => { + getMonthlyPlanning(); + }, []); + + async function getMonthlyPlanning() { + const res = await getMonthlyPlanList(new Date().getDate(), 2); + + if (res.data !== null) { + const rawUser = res.data?.data; + const optionArr = rawUser.map((option: any) => ({ + id: option.id, + label: option.title, + value: String(option.id), + })); + console.log("ssss", optionArr); + setMonthlyList(optionArr); + } + } + + return ( +
+ +
+
+ + Bulanan + +
+ Mingguan +
+ + + Harian + +
+
+

Perencanaan MediaHub Mingguan

+ +
+ + ( + + Judul Perencanaan + + + + + )} + /> + ( + + Pilih Tanggal + + + + + + + + + + + )} + /> + ( + + Perencanaan Bulanan + + + + + )} + /> + ( + + Detail Perencanaan + + + + + )} + /> +
+ + +
+ + +
+
+
+ ); +} diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/detail/[id]/page.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/detail/[id]/page.tsx new file mode 100644 index 00000000..68451be8 --- /dev/null +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/detail/[id]/page.tsx @@ -0,0 +1,270 @@ +"use client"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { close, loading } from "@/config/swal"; +import { getWeeklyPlanList } from "@/service/agenda-setting/agenda-setting"; +import { getPlanningById } from "@/service/planning/planning"; +import { useParams } from "next/navigation"; +import dayjs from "dayjs"; +import { useEffect, useRef, useState } from "react"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import JoditEditor from "jodit-react"; + +export default function DetailTaskPlanMediahub() { + const params = useParams(); + const id = params?.id; + const editor = useRef(null); + + const [planningData, setPlanningData] = useState(); + + const [type, setType] = useState(""); + + const [weeklyList, setWeeklyList] = useState([]); + const [weeklySelected, setWeeklySelected] = useState(); + + const [taskOutput, setTaskOutput] = useState([]); + const [destination, setDestination] = useState([]); + const [listDest, setListDest] = useState([]); + const [topDestination, setTopDestination] = useState([]); + + useEffect(() => { + initFetch(); + }, [id]); + + async function initFetch() { + if (id != undefined) { + loading(); + const res = await getPlanningById(id); + close(); + + if (res?.data?.data != undefined) { + const data = res?.data?.data; + console.log("Data :", data); + setPlanningData(data); + setAssignedTopLevel(data?.assignedToTopLevel); + setArrayDestination(data?.assignedToLevel); + setArrayTaskOutput(data?.fileTypeOutput); + setType(String(data?.assignmentTypeId)); + } + } + } + + function setArrayDestination(assignedToLevel: any) { + if (assignedToLevel?.length > 0) { + const arrayDestination = []; + const arrayDest = assignedToLevel.split(","); + + for (const element of arrayDest) { + arrayDestination.push(element); + } + + setDestination(arrayDestination); + } + } + + function setAssignedTopLevel(assignedToTopLevel: any) { + if (assignedToTopLevel?.length > 0) { + const arrayTopLevel = []; + const arrayTop = assignedToTopLevel.split(","); + + for (const element of arrayTop) { + arrayTopLevel.push(Number(element)); + } + + setTopDestination(arrayTopLevel); + } + } + + function setArrayTaskOutput(output: any) { + if (output?.length > 0) { + const arrayOutput = []; + const arrOutput = output.split(","); + + for (const element of arrOutput) { + arrayOutput.push(Number(element)); + } + + setTaskOutput(arrayOutput); + } + } + + useEffect(() => { + getWeeklyPlanning(); + }, [planningData]); + + async function getWeeklyPlanning() { + const TODAY = dayjs().format("YYYY-MM-DD"); + const res = await getWeeklyPlanList(planningData?.date || TODAY, 1); + + if (res.data !== null) { + const rawUser = res.data?.data; + const optionArr = rawUser.map((option: any) => ({ + id: option.id, + label: option.title, + value: option.id, + })); + console.log("res", optionArr); + + setWeeklyList(optionArr); + } + } + return ( + <> + +
+

Perencanaan Mediahub

+

Judul Perencanaan

+ +

Output Tugas

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+

Pelaksana Tugas

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+

Jenis Penugasan

+ +
+ + +
+
+ + +
+
+ + +
+
+

Tanggal

+ +

Penugasan Mingguan

+ + +
+ + ); +} diff --git a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/page.tsx b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/page.tsx index 5009e0f2..67ea7a5c 100644 --- a/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/page.tsx +++ b/app/[locale]/(protected)/curator/task-plan/medsos-mediahub/page.tsx @@ -1,9 +1,41 @@ +"use client"; import SiteBreadcrumb from "@/components/site-breadcrumb"; +import ListViewSocialMediaTable from "@/components/table/task-plan/list-view-social-media-table"; +import SingleViewSocialMediaTable from "@/components/table/task-plan/single-view-social-media-table"; +import { Button } from "@/components/ui/button"; +import { useRouter } from "@/i18n/routing"; +import { useState } from "react"; -export default function TaskPlanMedsosMediaHub() { +export default function TaskPlanSocialMediaMediaHub() { + const router = useRouter(); + const [view, setView] = useState("single"); return ( -
+ <> -
+
+
+ + +
+ {view == "single" ? ( + + ) : ( + + )} +
+ ); } diff --git a/components/icon.tsx b/components/icon.tsx new file mode 100644 index 00000000..d2a65f90 --- /dev/null +++ b/components/icon.tsx @@ -0,0 +1,130 @@ +import { SVGProps } from "react"; + +type IconSvgProps = SVGProps & { + size?: number; +}; + +export const FacebookIcon = ({ + size, + height = 24, + width = 24, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + + + + + + + + + + +); +export const InstagramIcon = ({ + size, + height = 24, + width = 24, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + +); +export const YoutubeIcon = ({ + size, + height = 24, + width = 24, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + + + + +); + +export const TiktokIcon = ({ + size, + height = 24, + width = 24, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + +); +export const XIcon = ({ + size, + height = 24, + width = 24, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + +); diff --git a/components/partials/customizer/data.tsx b/components/partials/customizer/data.tsx index 19ad8777..ebcf3524 100644 --- a/components/partials/customizer/data.tsx +++ b/components/partials/customizer/data.tsx @@ -9,7 +9,10 @@ export const verticalLayoutSvg = ( d="M0 4C0 1.79086 1.79086 0 4 0H9V72H4C1.79086 72 0 70.2091 0 68V4Z" className="fill-default-200 dark:fill-default-300" /> - + - - - - + + + + ); export const horizontalLayoutSvg = ( - - - - - - - - - - + + + + + + + + + + ); export const semiBoxLayoutSvg = ( - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + ); export const compactLayoutSvg = ( - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ); export const classicSidebarSvg = ( - - - - - - - - - - - - - - + + + + + + + + + + + + + + ); export const draggableSidebarSvg = ( - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + ); export const twoColumnSidebarSvg = ( - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + ); export const compactSidebarSvg = ( - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ); export const pinnedSidebarSvg = ( - + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -479,58 +1210,187 @@ export const pinnedSidebarSvg = ( ); export const wideContentWidthSvg = ( - - - - - - - - - - + + + + + + + + + + ); export const boxedContentWidthSvg = ( - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + ); export const defaultSkinSvg = ( - + ); export const borderedSkinSvg = ( - + - - - - - - - - - + + + + + + + + + ); export const defaultSidebarColorSvg = ( - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + ); export const colorSidebarColorSvg = ( - + ); export const gradientSidebarColorSvg = ( - + - - - - - + + + + + - - - - + + + + ); export const lightTopbarColorSvg = ( - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + ); export const colorTopbarColorSvg = ( - + [] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + // { + // accessorKey: "title", + // header: "Judul Perencanaan", + // cell: ({ row }) => {row.getValue("title")}, + // }, + { + accessorKey: "title", + header: "Judul Perencanaan", + cell: ({ row }) => { + const datas = row.original.subPlanningList; + return ( + + + {row.getValue("title")} + + + + Rencanaan Mingguan + + + + + + + + + {datas?.map((data: any) => ( + + + + + + + ))} +
Judul PerencanaanBatas WaktuStatusAksi
+ {data.title} + {data.date}{data.status} + + + + + + + Detail + + + +
+
+
+ ); + }, + }, + { + accessorKey: "date", + header: "Batas Waktu", + cell: ({ row }) => {row.getValue("date")}, + }, + + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => {row.getValue("status")}, + }, + + { + id: "actions", + accessorKey: "action", + header: "Actions", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + Detail + + + + ); + }, + }, +]; + +export default columns; diff --git a/components/table/task-plan/list-view-social-media-table.tsx b/components/table/task-plan/list-view-social-media-table.tsx new file mode 100644 index 00000000..2de87113 --- /dev/null +++ b/components/table/task-plan/list-view-social-media-table.tsx @@ -0,0 +1,179 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { Button } from "@/components/ui/button"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import { paginationBlog } from "@/service/blog/blog"; +import { ticketingPagination } from "@/service/ticketing/ticketing"; +import { Badge } from "@/components/ui/badge"; +import { useRouter, useSearchParams } from "next/navigation"; +import TablePagination from "@/components/table/table-pagination"; +import columns from "./list-view-social-media-column"; +import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting"; + +const ListViewSocialMediaTable = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + 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: 10, + }); + const [page, setPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + 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, + }, + }); + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + React.useEffect(() => { + fetchData(); + }, [page, limit]); + + async function fetchData() { + try { + const res = await getPlanningPagination(page - 1, "", 10, 2, 3); + const data = res.data?.data; + const contentData = data?.content; + contentData.forEach((item: any, index: number) => { + item.no = (page - 1) * limit + index + 1; + }); + + console.log("contentData : ", data); + + setDataTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + 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 ListViewSocialMediaTable; diff --git a/components/table/task-plan/single-view-social-media-table.tsx b/components/table/task-plan/single-view-social-media-table.tsx new file mode 100644 index 00000000..642ba104 --- /dev/null +++ b/components/table/task-plan/single-view-social-media-table.tsx @@ -0,0 +1,469 @@ +"use client"; +import dayjs from "dayjs"; +import { useEffect, useRef, useState } from "react"; +import utc from "dayjs/plugin/utc"; +import { ChevronLeft, ChevronRight } from "lucide-react"; +import { close, loading } from "@/config/swal"; +import { useSearchParams } from "next/navigation"; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/css"; +import "swiper/css/free-mode"; +import "swiper/css/navigation"; +import "swiper/css/thumbs"; + +import Image from "next/image"; +import { FreeMode, Navigation, Thumbs } from "swiper/modules"; +import { Swiper as SwiperType } from "swiper/types"; +import { + getMonthlyPlanList, + getPlanningDailyByTypeId, + getPlanningDailyMedsosByPlatform, + getPlanningMonthlyPerSocmed, + getWeeklyPlanList, + getWeeklyPlanListByParentId, +} from "@/service/agenda-setting/agenda-setting"; +import TaskPlanMediahubTable from "@/app/[locale]/(protected)/curator/task-plan/mediahub/components/table"; +import weekday from "dayjs/plugin/weekday"; +import { Icon } from "@iconify/react/dist/iconify.js"; +import { + FacebookIcon, + InstagramIcon, + TiktokIcon, + XIcon, + YoutubeIcon, +} from "@/components/icon"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import TaskPlanningSocialMediaTable from "./social-media-modal/table"; + +const WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; +const TODAY = dayjs().format("YYYY-MM-DD"); + +export default function SingleViewSocialMediaTable() { + const params = useSearchParams(); + const [selectedMonthItem, setSelectedMonthItem] = useState< + string | undefined + >(undefined); + const [selectedWeekly, setSelectedWeekly] = useState( + undefined + ); + const [selectedDate, setSelectedDate] = useState( + new Date(TODAY).getDate() + ); + const [nowDate, setNowDate] = useState(TODAY); + + const INITIAL_YEAR = dayjs().format("YYYY"); + const INITIAL_MONTH = dayjs().format("M"); + const size = 20; + + const page: string | undefined | null = params?.get("page"); + const id: string | undefined | null = params?.get("id"); + const pages = page ? Number(page) - 1 : 0; + const no = (size || 10) * pages; + + const [selectedMonth, setSelectedMonth] = useState( + dayjs(new Date(parseInt(INITIAL_YEAR), parseInt(INITIAL_MONTH) - 1, 1)) + ); + + const [selectedMonthTitle, setSelectedMonthTitle] = useState(""); + const [days, setDays] = useState([]); + + const weekday = require("dayjs/plugin/weekday"); + const weekOfYear = require("dayjs/plugin/weekOfYear"); + + const [planningData, setPlanningData] = useState([]); + + dayjs.extend(utc); + dayjs.extend(weekday); + dayjs.extend(weekOfYear); + + let currentMonthDays: any; + let previousMonthDays: any; + let nextMonthDays: any; + + const [monthlyList, setMonthlyList] = useState([]); + const [weeklyList, setWeeklyList] = useState([]); + const [getData, setGetData] = useState([]); + const [isOpen, setIsOpen] = useState(false); + const [selectedDateNow, setSelectedDateNow] = useState(""); + const [selectedPlatform, setSelectedPlatform] = useState(""); + + useEffect(() => { + createCalendar("START"); + }, []); + + function createDaysForCurrentMonth( + year: string, + month: string, + daysInMonth: number + ) { + const days: any = []; + for (let day = 1; day <= daysInMonth; day++) { + const date = dayjs( + new Date(parseInt(year), parseInt(month) - 1, day) + ).format("YYYY-MM-DD"); + days.push({ + date, + isCurrentMonth: true, + isToday: date === TODAY, + }); + } + return days; + } + + async function getMonthlyPlanning(dates: number) { + const res = await getMonthlyPlanList(dates, 2); + setMonthlyList(res.data?.data); + } + + async function getWeeklyPlanning( + id: string | undefined, + date: number | undefined + ) { + if (id) { + const res = await getWeeklyPlanListByParentId(id, 2); + setWeeklyList(res.data?.data); + } else { + const res = await getWeeklyPlanList(date, 2, true); + setWeeklyList(res.data?.data); + } + } + + function createCalendar( + year: string = INITIAL_YEAR, + month: string = INITIAL_MONTH + ) { + year = year === "START" ? INITIAL_YEAR : year; + + fetchData(month, year); + + setSelectedMonthTitle( + dayjs(new Date(parseInt(year), parseInt(month) - 1)) + .utc() + .local() + .format("MMMM YYYY") + ); + + currentMonthDays = createDaysForCurrentMonth( + year, + month, + dayjs(`${year}-${month}-01`).daysInMonth() + ); + + getMonthlyPlanning(year ? currentMonthDays[0]?.date : TODAY); + getWeeklyPlanning(undefined, year ? currentMonthDays[0]?.date : TODAY); + + previousMonthDays = createDaysForPreviousMonth(year, month); + nextMonthDays = createDaysForNextMonth(year, month); + const listDay = [ + ...previousMonthDays, + ...currentMonthDays, + ...nextMonthDays, + ]; + setDays(listDay); + } + + function getWeekday(date: string | undefined) { + return dayjs(date).weekday(); + } + + function createDaysForPreviousMonth(year: string, month: string) { + const firstDayOfTheMonthWeekday = getWeekday(currentMonthDays[0]?.date); + + const previousMonth = dayjs(`${year}-${month}-01`).subtract(1, "month"); + + // Cover first day of the month being sunday (firstDayOfTheMonthWeekday == 0) + const visibleNumberOfDaysFromPreviousMonth = firstDayOfTheMonthWeekday + ? firstDayOfTheMonthWeekday - 1 + : 6; + + const previousMonthLastMondayDayOfMonth = dayjs(currentMonthDays[0].date) + .subtract(visibleNumberOfDaysFromPreviousMonth, "day") + .date(); + + return [...new Array(visibleNumberOfDaysFromPreviousMonth)].map( + (day, index) => ({ + date: dayjs( + `${previousMonth.year()}-${previousMonth.month() + 1}-${ + previousMonthLastMondayDayOfMonth + index + }` + ).format("YYYY-MM-DD"), + dayOfMonth: previousMonthLastMondayDayOfMonth + index, + isCurrentMonth: false, + }) + ); + } + + function createDaysForNextMonth(year: string, month: string) { + const lastDayOfTheMonthWeekday = getWeekday( + `${year}-${month}-${currentMonthDays.length}` + ); + + const nextMonth = dayjs(`${year}-${month}-01`).add(1, "month"); + + const visibleNumberOfDaysFromNextMonth = lastDayOfTheMonthWeekday + ? 7 - lastDayOfTheMonthWeekday + : lastDayOfTheMonthWeekday; + + return [...new Array(visibleNumberOfDaysFromNextMonth)].map( + (day, index) => ({ + date: dayjs( + `${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}` + ).format("YYYY-MM-DD"), + dayOfMonth: index + 1, + isCurrentMonth: false, + }) + ); + } + + async function fetchData( + month: string, + year: string, + + parentId?: string | undefined + ) { + loading(); + const res = await getPlanningMonthlyPerSocmed(month, year, 2, parentId); + close(); + setPlanningData(res.data?.data); + } + + function getPrevMonth() { + const selectedMonthNew = dayjs(selectedMonth).subtract(1, "month"); + + createCalendar( + selectedMonthNew.format("YYYY"), + selectedMonthNew.format("M") + ); + fetchData("", selectedMonthNew?.format("YYYY-MM-DD")); + setSelectedMonth(selectedMonthNew); + setSelectedDate(1); + } + + function getPresentMonth() { + const selectedMonthNew = dayjs( + new Date(parseInt(INITIAL_YEAR), parseInt(INITIAL_MONTH) - 1, 1) + ); + + createCalendar( + selectedMonthNew.format("YYYY"), + selectedMonthNew.format("M") + ); + fetchData("", TODAY); + setSelectedDate(Number(dayjs().format("D"))); + setSelectedMonth(selectedMonthNew); + } + + function getNextMonth() { + const selectedMonthNew = dayjs(selectedMonth).add(1, "month"); + + createCalendar( + selectedMonthNew.format("YYYY"), + selectedMonthNew.format("M") + ); + fetchData("", selectedMonthNew?.format("YYYY-MM-DD")); + setSelectedMonth(selectedMonthNew); + setSelectedDate(1); + } + const onSelectedMonthItem = (id: string | undefined) => { + // fetchData(date) + setSelectedMonthItem(id); + getWeeklyPlanning(id, undefined); + }; + + const onSelectedWeekly = (id: string | undefined) => { + setSelectedWeekly(id); + fetchData("", String(id)); + }; + + const removeSelection = () => { + setSelectedMonthItem(undefined); + setSelectedWeekly(undefined); + }; + + const onSelectedSocmed = async (date: string, platform: string) => { + setSelectedDateNow(date); + setSelectedPlatform(platform); + setIsOpen(true); + }; + + const getDataForThisDate = (day: number) => { + const todayData = planningData?.find((a: any) => a?.day == day); + + if (todayData) { + return ( +
+ + onSelectedSocmed(todayData.planningList[0].date, "5") + } + className="flex flex-row gap-5 rounded-sm bg-[#0C0705] text-white px-3 py-1 justify-center" + > + Total: {todayData.totalTwitter} + + + onSelectedSocmed(todayData.planningList[0].date, "1") + } + className="flex flex-row gap-5 rounded-sm bg-[#1877F2] text-white px-3 py-1 justify-center" + > + Total: {todayData.totalFacebook} + + + onSelectedSocmed(todayData.planningList[0].date, "2") + } + className="flex flex-row gap-5 rounded-sm bg-[#d62976] text-white px-3 py-1 justify-center" + > + Total: {todayData.totalInstagram} + + + onSelectedSocmed(todayData.planningList[0].date, "3") + } + className="flex flex-row gap-5 rounded-sm bg-[#FF0000] text-white px-3 py-1 justify-center" + > + Total: {todayData.totalYoutube} + + + onSelectedSocmed(todayData.planningList[0].date, "4") + } + className="flex flex-row gap-5 rounded-sm bg-[#000000] text-white px-3 py-1 justify-center" + > + Total: {todayData.totalTiktok} + +
+ ); + } + }; + + return ( +
+
+ +

{selectedMonthTitle}

+
+ +
+

Rencana Bulanan

+ {monthlyList?.length > 0 ? ( +
+ {monthlyList?.map((item: any) => ( +
onSelectedMonthItem(item.id)} + > +

{item.title}

+
+ ))} +
+ ) : ( +
+ Rencana Bulanan Belum Tersedia +
+ )} +

Rencana Mingguan

+ {weeklyList?.length > 0 ? ( +
+ {weeklyList?.map((item: any) => ( + onSelectedWeekly(item.id)} + > +

{item.title}

+
+ ))} +
+ ) : ( +
+ Rencana Mingguan Belum Tersedia +
+ )} +
+
+
+
+
    + {WEEKDAYS.map((weekday, index) => ( +
  1. + {weekday} +
  2. + ))} +
+
    + {days?.map((day: any, index: number) => ( +
  1. + + {parseInt(day.date.split("-")[2])} + + {getDataForThisDate(parseInt(day.date.split("-")[2]))} +
  2. + ))} +
+
+
+
+ + + + Perencanaan Medsos Harian + +
+ +
+
+
+
+ ); +} diff --git a/components/table/task-plan/social-media-modal/column.tsx b/components/table/task-plan/social-media-modal/column.tsx new file mode 100644 index 00000000..9960b267 --- /dev/null +++ b/components/table/task-plan/social-media-modal/column.tsx @@ -0,0 +1,104 @@ +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 { 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"; + +const columns: ColumnDef[] = [ + { + accessorKey: "no", + header: "No", + cell: ({ row }) => {row.getValue("no")}, + }, + // { + // accessorKey: "title", + // header: "Judul Perencanaan", + // cell: ({ row }) => {row.getValue("title")}, + // }, + { + accessorKey: "title", + header: "Judul Perencanaan", + cell: ({ row }) => {row.getValue("title")}, + }, + { + accessorKey: "createdByName", + header: "Nama Pembuat", + cell: ({ row }) => {row.getValue("createdByName")}, + }, + { + accessorKey: "createdAt", + header: "Dibuat", + cell: ({ row }) => {row.getValue("createdAt")}, + }, + { + accessorKey: "status", + header: "Dibuat", + cell: ({ row }) => {row.getValue("status")}, + }, + { + accessorKey: "platformTypeId", + header: "Jenis Platform", + cell: ({ row }) => {row.getValue("platformTypeId")}, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => {row.getValue("status")}, + }, + { + accessorKey: "description", + header: "Deskripsi", + cell: ({ row }) => {htmlToString(row.getValue("status"))}, + }, + + { + id: "actions", + accessorKey: "action", + header: "Aksi", + enableHiding: false, + cell: ({ row }) => { + return ( + + + + + + + Detail + + + + ); + }, + }, +]; + +export default columns; diff --git a/components/table/task-plan/social-media-modal/table.tsx b/components/table/task-plan/social-media-modal/table.tsx new file mode 100644 index 00000000..68d04bf5 --- /dev/null +++ b/components/table/task-plan/social-media-modal/table.tsx @@ -0,0 +1,200 @@ +"use client"; + +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { Button } from "@/components/ui/button"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + SquarePen, + Trash2, + TrendingDown, + TrendingUp, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import { paginationBlog } from "@/service/blog/blog"; +import { ticketingPagination } from "@/service/ticketing/ticketing"; +import { Badge } from "@/components/ui/badge"; +import { useRouter, useSearchParams } from "next/navigation"; +import TablePagination from "@/components/table/table-pagination"; +import columns from "./column"; +import { + getPlanningDailyMedsosByPlatform, + getPlanningPagination, +} from "@/service/agenda-setting/agenda-setting"; + +const TaskPlanningSocialMediaTable = (props: { + date: string; + platform: string; +}) => { + const router = useRouter(); + const searchParams = useSearchParams(); + + 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: 10, + }); + const [page, setPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + 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, + }, + }); + + React.useEffect(() => { + const pageFromUrl = searchParams?.get("page"); + if (pageFromUrl) { + setPage(Number(pageFromUrl)); + } + }, [searchParams]); + + React.useEffect(() => { + fetchData(); + }, [page, limit, props]); + + async function fetchData() { + try { + const response = await getPlanningDailyMedsosByPlatform( + "0", + 20, + props.date, + props.platform + ); + const data = response.data?.data; + const contentData = data?.content; + contentData.forEach((item: any, index: number) => { + item.no = (page - 1) * limit + index + 1; + item.platformTypeId = + props.platform === "1" + ? "Facebook" + : props.platform === "2" + ? "Instagram" + : props.platform === "3" + ? "Youtube" + : props.platform === "4" + ? "Tiktok" + : props.platform === "3" + ? "X" + : ""; + }); + + setDataTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + 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 TaskPlanningSocialMediaTable; diff --git a/service/agenda-setting/agenda-setting.ts b/service/agenda-setting/agenda-setting.ts index b3fd52fb..63996f22 100644 --- a/service/agenda-setting/agenda-setting.ts +++ b/service/agenda-setting/agenda-setting.ts @@ -63,3 +63,23 @@ export async function savePlanning(data: any) { const url = "planning"; return postAPIInterceptor(url, data); } + +export async function getPlanningMonthlyPerSocmed( + month = "", + year = "", + typeId: number, + parentId = "" +) { + const url = `planning/socmed/monthly?month=${month}&year=${year}&typeId=${typeId}&parentId=${parentId}`; + return getAPIInterceptor(url); +} + +export async function getPlanningDailyMedsosByPlatform( + page: string, + size = 10, + date: string, + platformTypeId: string +) { + const url = `planning/pagination/daily?enablePage=1&size=${size}&page=${page}&date=${date}&typeId=2&platformTypeId=${platformTypeId}`; + return getAPIInterceptor(url); +} diff --git a/service/media-tracking/media-tracking.ts b/service/media-tracking/media-tracking.ts new file mode 100644 index 00000000..078c131f --- /dev/null +++ b/service/media-tracking/media-tracking.ts @@ -0,0 +1,6 @@ +import { getAPIInterceptor } from "@/config/api"; + +export async function getMediaTrackingMonitoring(page: number, size: number) { + const url = `cekmedsos/monitoring/pagination?page=${page}&size=${size}`; + return getAPIInterceptor(url); +}