From bf4cedc768c28212bf78678a8da4335ccc206f0f Mon Sep 17 00:00:00 2001 From: Anang Yusman Date: Wed, 25 Dec 2024 01:18:48 +0700 Subject: [PATCH] feat:convert SPIT, edit blog,edit task.publish planning --- .../contributor/blog/components/columns.tsx | 14 +- .../contributor/blog/update/[id]/page.tsx | 15 + .../content/image/components/columns.tsx | 6 + .../content/image/update/[id]/page.tsx | 16 + .../content/spit/convert/[id]/page.tsx | 16 + .../contributor/content/spit/page.tsx | 35 +- .../content/spit/table-spit/columns.tsx | 222 +++---- .../content/spit/table-spit/data.ts | 184 ------ .../content/spit/table-spit/page.tsx | 383 ------------ .../spit/table-spit/table-pagination.tsx | 52 -- .../content/spit/table-spit/table-spit.tsx | 232 ++++++++ .../internal/components/columns.tsx | 12 +- .../internal/components/internal-table.tsx | 2 +- .../internal/update/[id]/page.tsx | 19 + .../(protected)/shared/communication/page.tsx | 69 +-- components/form/blog/blog--update-form.tsx | 415 +++++++++++++ .../communication/internal-detail-form.tsx | 6 +- .../form/communication/internal-edit-form.tsx | 363 ++++++++++++ components/form/content/image-detail-form.tsx | 8 +- components/form/content/image-form.tsx | 130 ++--- components/form/content/image-update-form.tsx | 441 ++++++++++++++ components/form/content/spit-convert-form.tsx | 552 ++++++++++++++++++ .../form/contest/contest-detail-form.tsx | 2 +- service/content/content.ts | 22 +- 24 files changed, 2317 insertions(+), 899 deletions(-) create mode 100644 app/[locale]/(protected)/contributor/blog/update/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/content/image/update/[id]/page.tsx create mode 100644 app/[locale]/(protected)/contributor/content/spit/convert/[id]/page.tsx delete mode 100644 app/[locale]/(protected)/contributor/content/spit/table-spit/data.ts delete mode 100644 app/[locale]/(protected)/contributor/content/spit/table-spit/page.tsx delete mode 100644 app/[locale]/(protected)/contributor/content/spit/table-spit/table-pagination.tsx create mode 100644 app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx create mode 100644 app/[locale]/(protected)/shared/communication/internal/update/[id]/page.tsx create mode 100644 components/form/blog/blog--update-form.tsx create mode 100644 components/form/communication/internal-edit-form.tsx create mode 100644 components/form/content/image-update-form.tsx create mode 100644 components/form/content/spit-convert-form.tsx diff --git a/app/[locale]/(protected)/contributor/blog/components/columns.tsx b/app/[locale]/(protected)/contributor/blog/components/columns.tsx index c69445ed..3838aaf3 100644 --- a/app/[locale]/(protected)/contributor/blog/components/columns.tsx +++ b/app/[locale]/(protected)/contributor/blog/components/columns.tsx @@ -102,16 +102,16 @@ const columns: ColumnDef[] = [ View - {/* - - - Edit - - + + + + Edit + + Delete - */} + ); diff --git a/app/[locale]/(protected)/contributor/blog/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/blog/update/[id]/page.tsx new file mode 100644 index 00000000..db0bac9d --- /dev/null +++ b/app/[locale]/(protected)/contributor/blog/update/[id]/page.tsx @@ -0,0 +1,15 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormBlogUpdate from "@/components/form/blog/blog--update-form"; + +const BlogUpdatePage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default BlogUpdatePage; diff --git a/app/[locale]/(protected)/contributor/content/image/components/columns.tsx b/app/[locale]/(protected)/contributor/content/image/components/columns.tsx index 12dd6e04..3704bc4b 100644 --- a/app/[locale]/(protected)/contributor/content/image/components/columns.tsx +++ b/app/[locale]/(protected)/contributor/content/image/components/columns.tsx @@ -146,6 +146,12 @@ const columns: ColumnDef[] = [ View + + + + Edit + + Delete diff --git a/app/[locale]/(protected)/contributor/content/image/update/[id]/page.tsx b/app/[locale]/(protected)/contributor/content/image/update/[id]/page.tsx new file mode 100644 index 00000000..1adea644 --- /dev/null +++ b/app/[locale]/(protected)/contributor/content/image/update/[id]/page.tsx @@ -0,0 +1,16 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormImageDetail from "@/components/form/content/image-detail-form"; +import FormImageUpdate from "@/components/form/content/image-update-form"; + +const ImageUpdatePage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default ImageUpdatePage; diff --git a/app/[locale]/(protected)/contributor/content/spit/convert/[id]/page.tsx b/app/[locale]/(protected)/contributor/content/spit/convert/[id]/page.tsx new file mode 100644 index 00000000..ed9c8cac --- /dev/null +++ b/app/[locale]/(protected)/contributor/content/spit/convert/[id]/page.tsx @@ -0,0 +1,16 @@ +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormImageDetail from "@/components/form/content/image-detail-form"; +import FormConvertSPIT from "@/components/form/content/spit-convert-form"; + +const SPITConvertPage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default SPITConvertPage; diff --git a/app/[locale]/(protected)/contributor/content/spit/page.tsx b/app/[locale]/(protected)/contributor/content/spit/page.tsx index c87af372..0208103e 100644 --- a/app/[locale]/(protected)/contributor/content/spit/page.tsx +++ b/app/[locale]/(protected)/contributor/content/spit/page.tsx @@ -1,35 +1,24 @@ "use client"; -import { Card, CardContent } from "@/components/ui/card"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import SiteBreadcrumb from "@/components/site-breadcrumb"; -import TableImage from "./table-spit/page"; -import { Newspaper, NewspaperIcon, UploadIcon } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Icon } from "@iconify/react/dist/iconify.js"; -import TableSPIT from "./table-spit/page"; +import TableImage from "./table-spit/table-spit"; +import TableSPIT from "./table-spit/table-spit"; const ReactTableSPITPage = () => { return (
- -
-
- Konten SPIT -
- {/*
- - -
*/} -
-
+ + +
+
+ Konten SPIT +
+
+
+
diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx index af464e84..ca5cf595 100644 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx +++ b/app/[locale]/(protected)/contributor/content/spit/table-spit/columns.tsx @@ -1,145 +1,109 @@ "use client"; - import { ColumnDef } from "@tanstack/react-table"; -import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react"; - +import { + Eye, + MoreVertical, + MoveDownRight, + SquarePen, + Trash2, +} from "lucide-react"; import { Button } from "@/components/ui/button"; -import { Checkbox } from "@/components/ui/checkbox"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { format } from "date-fns"; +import { Link } from "@/components/navigation"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Badge } from "@/components/ui/badge"; -import { cn } from "@/lib/utils"; -export type DataProps = { - id: string | number; - order: string; - customer: { - name: string; - }; - date: string; - quantity: number; - amount: string; - status: "paid" | "due" | "canceled"; - action: React.ReactNode; -}; -export const columns: ColumnDef[] = [ - // { - // id: "select", - // header: ({ table }) => ( - // table.toggleAllPageRowsSelected(!!value)} - // aria-label="Select all" - // /> - // ), - // cell: ({ row }) => ( - //
- // row.toggleSelected(!!value)} - // aria-label="Select row" - // /> - //
- // ), - // enableSorting: false, - // enableHiding: false, - // }, +const columns: ColumnDef[] = [ { - accessorKey: "id", + accessorKey: "no", header: "No", - cell: ({ row }) => {row.getValue("id")}, - }, - { - accessorKey: "order", - header: "Judul", cell: ({ row }) => ( -
- {row.getValue("order")}, +
+
+

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

+
), }, { - accessorKey: "customer", - header: "Kategory", - cell: ({ row }) => { - const user = row.original.customer; + accessorKey: "contentTitle", + header: "Judul", + cell: ({ row }: { row: { getValue: (key: string) => string } }) => { + const title: string = row.getValue("contentTitle"); return ( -
-
- - {user?.name ?? "Unknown User"} - -
+ + {title.length > 50 ? `${title.slice(0, 30)}...` : title} + + ); + }, + }, + { + accessorKey: "contentTag", + header: "Tag", + cell: ({ row }) => ( + {row.getValue("contentTag")} + ), + }, + + { + accessorKey: "contentType", + header: "Tipe Konten ", + cell: ({ row }) => ( + {row.getValue("contentType")} + ), + }, + { + accessorKey: "contentCreatedGroupBy", + header: "Sumber ", + cell: ({ row }) => ( + + {row.getValue("contentCreatedGroupBy")} + + ), + }, + + { + accessorKey: "isPublish", + header: "Status", + cell: ({ row }) => { + const isPublish = row.getValue("isPublish"); + return ( +
+
); }, }, + { - accessorKey: "date", - header: "Tanggal unggah", + accessorKey: "contentCreatedDate", + header: "Tanggal Unggah", cell: ({ row }) => { - return {row.getValue("date")}; - }, - }, - { - accessorKey: "quantity", - header: "Kreator", - cell: ({ row }) => { - return {row.getValue("quantity")}; - }, - }, - { - accessorKey: "amount", - header: "Sumber", - cell: ({ row }) => { - return {row.getValue("amount")}; - }, - }, - { - accessorKey: "amount", - header: "Penempatan File", - cell: ({ row }) => { - return {row.getValue("amount")}; - }, - }, - { - accessorKey: "status", - header: "Status", - cell: ({ row }) => { - const statusColors: Record = { - paid: "bg-success/20 text-success", - due: "bg-warning/20 text-warning", - canceled: "bg-destructive/20 text-destructive", - }; - const status = row.getValue("status"); - const statusStyles = statusColors[status] || "default"; - return ( - - {status}{" "} - - ); - }, - }, - { - accessorKey: "amount", - header: "Kurasi Konten", - cell: ({ row }) => { - return {row.getValue("amount")}; - }, - }, - { - accessorKey: "amount", - header: "Saran", - cell: ({ row }) => { - return {row.getValue("amount")}; + const createdAt = row.getValue("contentCreatedDate") as + | string + | number + | undefined; + + const formattedDate = + createdAt && !isNaN(new Date(createdAt).getTime()) + ? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss") + : "-"; + return {formattedDate}; }, }, { @@ -160,21 +124,19 @@ export const columns: ColumnDef[] = [ - - - View - - - - Edit - - - - Delete - + + + + Pindah Ke Mediahub + + ); }, }, ]; + +export default columns; diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/data.ts b/app/[locale]/(protected)/contributor/content/spit/table-spit/data.ts deleted file mode 100644 index 99b38b91..00000000 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/data.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { DataProps } from "./columns"; - -export const data: DataProps[] = [ - { - id: 1, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Liputan Kegiatan", - }, - date: "3/26/2022", - quantity: 13, - amount: "$1779.53", - status: "paid", - action: null, - }, - { - id: 2, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Liputan Kegiatan", - }, - date: "2/6/2022", - quantity: 13, - amount: "$2215.78", - status: "due", - action: null, - }, - { - id: 3, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Liputan Kegiatan", - }, - date: "9/6/2021", - quantity: 1, - amount: "$3183.60", - status: "due", - action: null, - }, - { - id: 4, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Liputan Kegiatan", - }, - date: "11/7/2021", - quantity: 13, - amount: "$2587.86", - status: "canceled", - action: null, - }, - { - id: 5, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Rachel Brown", - }, - date: "5/6/2022", - quantity: 12, - amount: "$3840.73", - status: "paid", - action: null, - }, - { - id: 6, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Megan Taylor", - }, - date: "2/14/2022", - quantity: 12, - amount: "$4764.18", - status: "canceled", - action: null, - }, - { - id: 7, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Sophie Clark", - }, - date: "7/30/2022", - quantity: 6, - amount: "$2875.05", - status: "paid", - action: null, - }, - { - id: 8, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Natalie Martin", - }, - date: "6/30/2022", - quantity: 9, - amount: "$2491.02", - status: "due", - action: null, - }, - { - id: 9, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Hannah Lewis", - }, - date: "8/9/2022", - quantity: 8, - amount: "$3006.95", - status: "due", - action: null, - }, - { - id: 10, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Lisa White", - }, - date: "8/4/2022", - quantity: 12, - amount: "$2160.32", - status: "paid", - action: null, - }, - { - id: 11, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Emma Walker", - }, - date: "4/5/2022", - quantity: 8, - amount: "$1272.66", - status: "paid", - action: null, - }, - { - id: 12, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Jenny Wilson", - }, - date: "8/9/2022", - quantity: 2, - amount: "$4327.86", - status: "canceled", - action: null, - }, - { - id: 13, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Jenny Wilson", - }, - date: "2/10/2022", - quantity: 11, - amount: "$3671.81", - status: "canceled", - action: null, - }, - { - id: 14, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Jenny Wilson", - }, - date: "2/10/2022", - quantity: 2, - amount: "$3401.82", - status: "paid", - action: null, - }, - { - id: 15, - order: "Pertemuan PPID Satker Mabes Polri Langkah Strate", - customer: { - name: "Jenny Wilson", - }, - date: "5/20/2022", - quantity: 4, - amount: "$2387.49", - status: "canceled", - action: null, - }, -]; diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/page.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/page.tsx deleted file mode 100644 index 8b51bf27..00000000 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/page.tsx +++ /dev/null @@ -1,383 +0,0 @@ -"use client"; -import * as React from "react"; -import { - ColumnDef, - ColumnFiltersState, - PaginationState, - SortingState, - VisibilityState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { Input } from "@/components/ui/input"; - -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; - -import { Button } from "@/components/ui/button"; -import { format } from "date-fns"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { - ChevronLeft, - ChevronRight, - Eye, - MoreVertical, - Trash2, -} from "lucide-react"; -import { title } from "process"; - -import { getCookiesDecrypt } from "@/lib/utils"; -import { listSPIT } from "@/service/content/content"; -import { pages } from "next/dist/build/templates/app-page"; - -export type CompanyData = { - no: number; - title: string; - categoryName: string; - createdAt: string; - creatorGroup: string; - publishedOn: string; - isPublish: any; - isPublishOnPolda: any; - isDone: string; -}; - -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 }) => { - const createdAt = row.getValue("createdAt") as - | string - | number - | undefined; - - const formattedDate = - createdAt && !isNaN(new Date(createdAt).getTime()) - ? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss") - : "-"; - return {formattedDate}; - }, - }, - { - accessorKey: "creatorGroup", - header: "Sumber ", - cell: ({ row }) => ( - {row.getValue("creatorGroup")} - ), - }, - { - accessorKey: "publishedOn", - header: "Penempatan File", - cell: ({ row }) => { - const isPublish = row.original.isPublish; - const isPublishOnPolda = row.original.isPublishOnPolda; - - let displayText = "-"; - if (isPublish && !isPublishOnPolda) { - displayText = "Mabes"; - } else if (isPublish && isPublishOnPolda) { - displayText = "Mabes & Polda"; - } else if (!isPublish && isPublishOnPolda) { - displayText = "Polda"; - } - - return ( -
- {displayText} -
- ); - }, - }, - - { - accessorKey: "isDone", - header: "Status", - cell: ({ row }) => { - const isDone = row.getValue("isDone"); - return ( -
- -
- ); - }, - }, - { - id: "actions", - accessorKey: "action", - header: "Actions", - enableHiding: false, - cell: ({ row }) => { - return ( - - - - - - - - - View - - - - - Delete - - - - ); - }, - }, -]; - -const TableSPIT = () => { - const [spitTable, setSpitTable] = React.useState([]); - 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, // Halaman pertama - pageSize: 10, // Jumlah baris per halaman - }); - const [page, setPage] = React.useState(1); // Halaman aktif - const [totalPage, setTotalPage] = React.useState(1); // Total halaman - const [limit, setLimit] = React.useState(6); // Jumlah baris per halaman - const [search, setSearch] = React.useState(title); - const userId = getCookiesDecrypt("uie"); - const userLevelId = getCookiesDecrypt("ulie"); - - const [categories, setCategories] = React.useState(); - const [categoryFilter, setCategoryFilter] = React.useState([]); - const [statusFilter, setStatusFilter] = React.useState([1, 2]); - const [startDateString, setStartDateString] = React.useState(""); - const [endDateString, setEndDateString] = React.useState(""); - const [filterByCreator, setFilterByCreator] = React.useState(""); - const [filterBySource, setFilterBySource] = React.useState(""); - - const roleId = getCookiesDecrypt("urie"); - - const table = useReactTable({ - data: spitTable, - columns, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnVisibilityChange: setColumnVisibility, - onRowSelectionChange: setRowSelection, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection, - }, - }); - - // React.useEffect(() => { - // initState(); - // }, [page, limit]); - - // async function initState() { - // try { - // const isForSelf = Number(roleId) == 4; - - // let isPublish; - // if (statusFilter.length > 1) { - // isPublish = ""; - // } else if (statusFilter.length === 1) { - // if (statusFilter.includes(1)) { - // isPublish = false; - // } else { - // isPublish = true; - // } - // } else { - // isPublish = undefined; - // } - // const res = await listSPIT(pages, limit, search, isPublish); - // const data = res.data.data.content.map((item: any, index: number) => ({ - // no: (page - 1) * limit + index + 1, - // title: item.title, - // categoryName: item.categoryName, - // creatorGroup: item.creatorGroup, - // assignmentType: item.assignmentType?.name || "-", - // createdAt: item.createdAt, - // isDone: item.isDone, - // publishedOn: item.publishedOn, - // isPublish: item.isPublish, - // isPublishOnPolda: item.isPublishOnPolda, - // })); - - // setSpitTable(data); - // setTotalPage(res.data.totalPages); - // } catch (error) { - // console.error("Error fetching tasks:", error); - // } - // } - - return ( -
-
-
- ) => - table.getColumn("status")?.setFilterValue(event.target.value) - } - className="max-w-sm " - /> -
-
- - - - {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. - - - )} - -
-
- - {table.getPageOptions().map((page, pageIndex) => ( - - ))} - -
-
- ); -}; -export default TableSPIT; diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/table-pagination.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/table-pagination.tsx deleted file mode 100644 index ad78cfeb..00000000 --- a/app/[locale]/(protected)/contributor/content/spit/table-spit/table-pagination.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { Table } from '@tanstack/react-table'; -import { ChevronLeft, ChevronRight } from 'lucide-react'; - -interface DataTablePaginationProps { - table: Table; -} - -const TablePagination = ({ table }: DataTablePaginationProps) => { - return ( -
-
- {table.getFilteredSelectedRowModel().rows.length} of{" "} - {table.getFilteredRowModel().rows.length} row(s) selected. -
-
- - {table.getPageOptions().map((page, pageIndex) => ( - - - ))} - -
-
- ); -}; - -export default TablePagination; \ No newline at end of file diff --git a/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx b/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx new file mode 100644 index 00000000..36658412 --- /dev/null +++ b/app/[locale]/(protected)/contributor/content/spit/table-spit/table-spit.tsx @@ -0,0 +1,232 @@ +"use client"; +import * as React from "react"; +import { + ColumnDef, + ColumnFiltersState, + PaginationState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { Input } from "@/components/ui/input"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +import { Button } from "@/components/ui/button"; +import { + ChevronLeft, + ChevronRight, + Eye, + MoreVertical, + Search, + Trash2, +} from "lucide-react"; +import { title } from "process"; +import { getCookiesDecrypt } from "@/lib/utils"; +import TablePagination from "@/components/table/table-pagination"; +import { listSPIT } from "@/service/content/content"; + +import { useSearchParams } from "next/navigation"; +import { InputGroup, InputGroupText } from "@/components/ui/input-group"; +import columns from "./columns"; + +// export type CompanyData = { +// no: number; +// id: any; +// title: string; +// categoryName: string; +// createdAt: string; +// creatorGroup: string; +// publishedOn: string; +// isPublish: any; +// isPublishOnPolda: any; +// isDone: string; +// }; + +const TableSPIT = () => { + const searchParams = useSearchParams(); + const [spitTable, setSpitTable] = 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 [totalPage, setTotalPage] = React.useState(1); + const [limit, setLimit] = React.useState(10); + const [search, setSearch] = React.useState(""); + const userId = getCookiesDecrypt("uie"); + const userLevelId = getCookiesDecrypt("ulie"); + + const [totalData, setTotalData] = React.useState(1); + const [sorting, setSorting] = React.useState([]); + const [columnFilters, setColumnFilters] = React.useState( + [] + ); + const [statusFilter, setStatusFilter] = React.useState([1, 2]); + + const roleId = getCookiesDecrypt("urie"); + + const table = useReactTable({ + data: spitTable, + 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, search]); + + async function fetchData() { + let isPublish; + if (statusFilter.length > 1) { + isPublish = ""; + } else if (statusFilter.length === 1) { + if (statusFilter.includes(1)) { + isPublish = false; + } else { + isPublish = true; + } + } else { + isPublish = undefined; + } + + try { + const res = await listSPIT(page - 1, limit, search, isPublish); + const data = res.data?.data; + const contentData = data?.content; + contentData.forEach((item: any, index: number) => { + item.no = (page - 1) * limit + index + 1; + }); + + console.log("contentData : ", contentData); + + setSpitTable(contentData); + setTotalData(data?.totalElements); + setTotalPage(data?.totalPages); + } catch (error) { + console.error("Error fetching tasks:", error); + } + } + + const handleSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); // Perbarui state search + table.getColumn("judul")?.setFilterValue(e.target.value); // Set filter tabel + }; + + return ( +
+
+
+ + + + + + +
+
+ ) => + table.getColumn("status")?.setFilterValue(event.target.value) + } + className="max-w-sm " + /> +
+
+ + + + {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 TableSPIT; diff --git a/app/[locale]/(protected)/shared/communication/internal/components/columns.tsx b/app/[locale]/(protected)/shared/communication/internal/components/columns.tsx index ac4e763e..c55f5492 100644 --- a/app/[locale]/(protected)/shared/communication/internal/components/columns.tsx +++ b/app/[locale]/(protected)/shared/communication/internal/components/columns.tsx @@ -105,10 +105,14 @@ const columns: ColumnDef[] = [ View - - - Edit - + + + + Edit + + Delete diff --git a/app/[locale]/(protected)/shared/communication/internal/components/internal-table.tsx b/app/[locale]/(protected)/shared/communication/internal/components/internal-table.tsx index 4cba01b0..a9a4862c 100644 --- a/app/[locale]/(protected)/shared/communication/internal/components/internal-table.tsx +++ b/app/[locale]/(protected)/shared/communication/internal/components/internal-table.tsx @@ -151,7 +151,7 @@ const TableAudio = () => { }; return ( -
+
diff --git a/app/[locale]/(protected)/shared/communication/internal/update/[id]/page.tsx b/app/[locale]/(protected)/shared/communication/internal/update/[id]/page.tsx new file mode 100644 index 00000000..0f2efc81 --- /dev/null +++ b/app/[locale]/(protected)/shared/communication/internal/update/[id]/page.tsx @@ -0,0 +1,19 @@ +import { Card, CardContent } from "@/components/ui/card"; +import SiteBreadcrumb from "@/components/site-breadcrumb"; +import FormTask from "@/components/form/task/task-form"; +import FormTaskDetail from "@/components/form/task/task-detail-form"; +import FormDetailInternal from "@/components/form/communication/internal-detail-form"; +import FormEditInternal from "@/components/form/communication/internal-edit-form"; + +const InternalUpdatePage = async () => { + return ( +
+ +
+ +
+
+ ); +}; + +export default InternalUpdatePage; diff --git a/app/[locale]/(protected)/shared/communication/page.tsx b/app/[locale]/(protected)/shared/communication/page.tsx index 77104464..bda9d00c 100644 --- a/app/[locale]/(protected)/shared/communication/page.tsx +++ b/app/[locale]/(protected)/shared/communication/page.tsx @@ -11,8 +11,8 @@ const CommunicationPage = () => {
- - + +

Komunikasi

{ Kolaborasi -
- -
-
- - - - - + + +
+
+ + + + + +
-
- - -
-
- - - - - + + +
+
+ + + + + +
-
- - -
-
- - - - - + + +
+
+ + + + + +
-
- - + + +
); diff --git a/components/form/blog/blog--update-form.tsx b/components/form/blog/blog--update-form.tsx new file mode 100644 index 00000000..e44293e5 --- /dev/null +++ b/components/form/blog/blog--update-form.tsx @@ -0,0 +1,415 @@ +"use client"; +import React, { ChangeEvent, 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 { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Checkbox } from "@/components/ui/checkbox"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import JoditEditor from "jodit-react"; +import { register } from "module"; +import { Switch } from "@/components/ui/switch"; +import Cookies from "js-cookie"; +import { createTask } from "@/config/api"; +import { + createMedia, + getTagsBySubCategoryId, + listEnableCategory, +} from "@/service/content/content"; +import { getBlog, postBlog } from "@/service/blog/blog"; +import { Badge } from "@/components/ui/badge"; + +const taskSchema = z.object({ + title: z.string().min(1, { message: "Judul diperlukan" }), + slug: z.string().min(1, { message: "Judul diperlukan" }), + metadata: z.string().min(1, { message: "Judul diperlukan" }), + narration: z + .string() + .min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), + categoryName: z.string().min(1, { message: "Kategori diperlukan" }), +}); + +type Category = { + id: string; + categoryName: string; +}; + +type Detail = { + id: number; + title: string; + narration: string; + slug: string; + metadata: string; + categoryName: string; + categoryId: string; + thumbnailLink: string; + tags: string; +}; + +const initialCategories: Category[] = [ + { + id: "1", + categoryName: "Giat Polri", + }, + { + id: "2", + categoryName: "Giat Pimpinan", + }, + { + id: "3", + categoryName: "Liputan Kegiatan", + }, + { + id: "4", + categoryName: "Seputar Prestasi", + }, +]; + +export default function FormBlogUpdate() { + const MySwal = withReactContent(Swal); + const router = useRouter(); + const { id } = useParams() as { id: string }; + console.log(id); + const editor = useRef(null); + type TaskSchema = z.infer; + + const [selectedFiles, setSelectedFiles] = useState([]); + const taskId = Cookies.get("taskId"); + const scheduleId = Cookies.get("scheduleId"); + const scheduleType = Cookies.get("scheduleType"); + + const [categories] = useState(initialCategories); + const [selectedTarget, setSelectedTarget] = useState(""); + const [selectedCategory, setSelectedCategory] = useState(); + const [tags, setTags] = useState([]); + const [isDraft, setIsDraft] = useState(false); + + const [detail, setDetail] = useState(); + const [refresh, setRefresh] = useState(false); + + const [unitSelection, setUnitSelection] = useState({ + allUnit: false, + mabes: false, + polda: false, + polres: false, + }); + + let fileTypeId = "1"; + + const { + control, + handleSubmit, + setValue, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + const handleRemoveTag = (index: any) => { + setTags((prevTags) => prevTags.filter((_, i) => i !== index)); + }; + + const handleImageChange = (event: ChangeEvent) => { + if (event.target.files) { + const files = Array.from(event.target.files); + setSelectedFiles((prevImages: any) => [...prevImages, ...files]); + console.log("DATAFILE::", selectedFiles); + } + }; + + const handleRemoveImage = (index: number) => { + setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index)); + }; + + useEffect(() => { + async function initState() { + if (id) { + const response = await getBlog(id); + const details = response.data?.data; + + setDetail(details); + + // Set categoryId dari API ke form dan Select + setValue("categoryName", details?.categoryName); + setSelectedTarget(details?.categoryId); // Untuk dropdown + } + } + initState(); + }, [refresh, setValue]); + + const save = async (data: TaskSchema) => { + const requestData = { + ...data, + id: detail?.id, + title: data.title, + narration: data.narration, + categoryId: selectedTarget, + slug: data.slug, + metadata: data.metadata, + tags: "siap", + isDraft, + }; + + const response = await postBlog(requestData); + console.log("Form Data Submitted:", requestData); + console.log("response", response); + + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/contributor/blog"); + }); + }; + + const onSubmit = (data: TaskSchema) => { + 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 handlePublish = () => { + setIsDraft(false); + }; + + const handleSave = () => { + setIsDraft(false); + }; + + return ( +
+ {detail !== undefined ? ( +
+ +
+

Update Indeks

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

+ {errors.title.message} +

+ )} +
+ +
+ + ( + + )} + /> + {errors.narration?.message && ( +

+ {errors.narration.message} +

+ )} +
+
+
+ + ( + + )} + /> + {errors.slug?.message && ( +

+ {errors.slug.message} +

+ )} +
+
+
+
+ + ( + + )} + /> + {errors.metadata?.message && ( +

+ {errors.metadata.message} +

+ )} +
+
+
+
+
+
+ +
+ + { + // const file = e.target.files[0]; + // if (file) { + // console.log("Selected File:", file); + // // Tambahkan logika jika diperlukan, misalnya upload file ke server + // } + // }} + className="" + /> +
+
+ + + Thumbnail Gambar Utama + +
+
+ + ( + + )} + /> +
+
+
+ +
+ {detail?.tags?.split(",").map((tag, index) => ( + + {tag.trim()} + + ))} +
+
+
+
+
+ {/*
+ +
*/} +
+ +
+
+ +
+
+
+
+ ) : ( + "" + )} +
+ ); +} diff --git a/components/form/communication/internal-detail-form.tsx b/components/form/communication/internal-detail-form.tsx index 9583c542..77462c93 100644 --- a/components/form/communication/internal-detail-form.tsx +++ b/components/form/communication/internal-detail-form.tsx @@ -200,8 +200,8 @@ export default function FormDetailInternal() {
{ticketReply?.map((list) => ( -
-

+

+

Ticket #{list.id}

@@ -224,7 +224,7 @@ export default function FormDetailInternal() {

{list?.createdAt}

-

{list.message}

+

{list.message}

))}
diff --git a/components/form/communication/internal-edit-form.tsx b/components/form/communication/internal-edit-form.tsx new file mode 100644 index 00000000..2bcf5dc2 --- /dev/null +++ b/components/form/communication/internal-edit-form.tsx @@ -0,0 +1,363 @@ +"use client"; +"use client"; +import React, { useEffect, 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 { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Avatar, AvatarImage } from "@/components/ui/avatar"; +import { + getTicketingInternalDetail, + getTicketingInternalDiscussion, + saveTicketing, + saveTicketInternalReply, +} from "@/service/communication/communication"; +import { Textarea } from "@/components/ui/textarea"; + +const taskSchema = z.object({ + // description: z.string().min(2, { + // message: "Narasi Penugasan harus lebih dari 2 karakter.", + // }), +}); + +export type taskDetail = { + id: number; + title: string; + createdAt: string; + createdBy: { + id: number; + fullname: string; + }; + sendTo: { + id: number; + fullname: string; + }; + status: { + id: number; + name: string; + }; + priority: { + id: number; + name: string; + }; + description: string; + is_active: string; +}; + +export type replyDetail = { + id: number; + message: string; + createdAt: string; + messageFrom: { + id: number; + fullname: string; + }; + messageTo: { + id: number; + fullname: string; + }; +}; + +export default function FormEditInternal() { + const MySwal = withReactContent(Swal); + const { id } = useParams() as { id: string }; + const router = useRouter(); + + const [detail, setDetail] = useState(); + const [ticketReply, setTicketReply] = useState([]); + const [replyVisible, setReplyVisible] = useState(false); + const [replyMessage, setReplyMessage] = useState(""); + const [selectedPriority, setSelectedPriority] = useState(""); + const [selectedStatus, setSelectedStatus] = useState(""); + const [selectedTarget, setSelectedTarget] = useState(""); + type TaskSchema = z.infer; + + const { + control, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(taskSchema), + }); + + useEffect(() => { + async function initState() { + if (id) { + const response = await getTicketingInternalDetail(id); + setDetail(response.data?.data); + } + } + initState(); + getTicketReply(); + }, [id]); + + async function getTicketReply() { + const res = await getTicketingInternalDiscussion(id); + if (res.data !== null) { + setTicketReply(res.data?.data); + } + } + + const handleReply = () => { + setReplyVisible((prev) => !prev); // Toggle visibility + }; + + const handleSendReply = async () => { + if (replyMessage.trim() === "") { + MySwal.fire({ + title: "Error", + text: "Pesan tidak boleh kosong!", + icon: "error", + }); + return; + } + + const data = { + ticketId: id, + message: replyMessage, + }; + + try { + const response = await saveTicketInternalReply(data); + + // Tambahkan balasan baru ke daftar balasan + const newReply: replyDetail = { + id: response.data.id, + message: replyMessage, + createdAt: response.data.createdAt, + messageFrom: response.data.messageFrom, + messageTo: response.data.messageTo, + }; + + setTicketReply((prevReplies) => [newReply, ...prevReplies]); + + MySwal.fire({ + title: "Sukses", + text: "Pesan berhasil dikirim.", + icon: "success", + }); + + // Reset input dan sembunyikan form balasan + setReplyMessage(""); + setReplyVisible(false); + } catch (error) { + MySwal.fire({ + title: "Error", + text: "Gagal mengirim balasan.", + icon: "error", + }); + console.error("Error sending reply:", error); + } + }; + + const save = async (data: TaskSchema) => { + const requestData = { + // description: data?.description, + target: selectedTarget, + priorityId: 1, + statusId: 1, + // description: data.description, + // operatorTeam: selectedOptionId.join(","), // This should work now without the error + }; + + const response = await saveTicketing(requestData); + + console.log("Form Data Submitted:", requestData); + console.log("response", response); + + MySwal.fire({ + title: "Sukses", + text: "Data berhasil disimpan.", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then(() => { + router.push("/en/shared/communication"); + }); + }; + + const onSubmit = (data: TaskSchema) => { + 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); + } + }); + }; + + return ( + +
+
+ + + +
+ + {replyVisible && ( +
+ +