From 0cd97530ca9a87f9ba896665ef49c7fb2fc78307 Mon Sep 17 00:00:00 2001 From: Rama Priyanto Date: Tue, 7 Jan 2025 19:59:32 +0700 Subject: [PATCH] fix:create edit deatil category --- .../settings/category/component/column.tsx | 3 +- .../settings/category/component/create.tsx | 311 ++++++++++----- .../settings/category/component/edit.tsx | 367 +++++++++++++----- .../settings/category/component/table.tsx | 12 +- .../category/component/unit-mapping.tsx | 253 ++++++++++++ service/settings/settings.ts | 14 +- 6 files changed, 753 insertions(+), 207 deletions(-) create mode 100644 app/[locale]/(protected)/admin/settings/category/component/unit-mapping.tsx diff --git a/app/[locale]/(protected)/admin/settings/category/component/column.tsx b/app/[locale]/(protected)/admin/settings/category/component/column.tsx index 86a71741..27248a15 100644 --- a/app/[locale]/(protected)/admin/settings/category/component/column.tsx +++ b/app/[locale]/(protected)/admin/settings/category/component/column.tsx @@ -103,7 +103,8 @@ const columns: ColumnDef[] = [ - + + categoryDelete(row.original.id)} className="hover:underline cursor-pointer hover:text-destructive" diff --git a/app/[locale]/(protected)/admin/settings/category/component/create.tsx b/app/[locale]/(protected)/admin/settings/category/component/create.tsx index 1faef3f6..69ed0898 100644 --- a/app/[locale]/(protected)/admin/settings/category/component/create.tsx +++ b/app/[locale]/(protected)/admin/settings/category/component/create.tsx @@ -25,11 +25,18 @@ import { useRouter } from "@/i18n/routing"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { getUserRoles, postCategory } from "@/service/settings/settings"; -import { useEffect, useState } from "react"; +import { Fragment, useEffect, useState } from "react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Icon } from "@iconify/react/dist/iconify.js"; import { Textarea } from "@/components/ui/textarea"; import { close, error, loading } from "@/config/swal"; +import { UnitMapping } from "./unit-mapping"; +import { useToast } from "@/components/ui/use-toast"; +import { stringify } from "querystring"; +import { useDropzone } from "react-dropzone"; +import { CloudUpload } from "lucide-react"; +import Image from "next/image"; +import { Upload } from "tus-js-client"; const FormSchema = z.object({ title: z.string({ @@ -48,17 +55,11 @@ const FormSchema = z.object({ .refine((value) => value.some((item) => item), { message: "Required", }), - publishTo: z.string({ - required_error: "Required", + publishTo: z.array(z.string()).refine((value) => value.some((item) => item), { + message: "Required", }), - file: z - .instanceof(File, { - message: "Invalid file format", - }) - .optional() - .refine((file) => file && file.size > 0, { - message: "File is required", - }), + + file: z.string().optional(), }); const listContent = [ @@ -80,26 +81,62 @@ const listContent = [ }, ]; +const publishToList = [ + { + id: "mabes", + name: "Nasional", + }, + { + id: "polda", + name: "Polda", + }, + { + id: "satker", + name: "Satker", + }, + { + id: "internasional", + name: "Internasional", + }, +]; + export default function CreateCategoryModal() { const router = useRouter(); + const { toast } = useToast(); + + const [files, setFiles] = useState([]); + const [isOpen, setIsOpen] = useState(false); + const [satkerData, setSatkerData] = useState([]); + const [unitData, setUnitData] = useState([]); const [userList, setUserList] = useState< { id: string; name: string; isInternal: boolean }[] >([]); + const form = useForm>({ resolver: zodResolver(FormSchema), - defaultValues: { contentType: [], selectedUser: [], publishTo: "national" }, + defaultValues: { contentType: [], selectedUser: [], publishTo: [] }, }); const contentType = form.watch("contentType"); - const isAllContentChecked = listContent.every((item) => contentType?.includes(item.id) ); const users = form.watch("selectedUser"); - const isAllUserChecked = userList.every((item) => users?.includes(item.id)); + const target = form.watch("publishTo"); + const isAllTargetChecked = publishToList.every((item) => + target?.includes(item.id) + ); + + const { getRootProps, getInputProps } = useDropzone({ + onDrop: (acceptedFiles) => { + setFiles(acceptedFiles.map((file) => Object.assign(file))); + }, + maxFiles: 1, + }); + useEffect(() => { getRoles(); }, []); @@ -111,36 +148,77 @@ export default function CreateCategoryModal() { dataRoles[i].id = String(dataRoles[i].id); } setUserList(dataRoles); - console.log("dasda", dataRoles); } const onSubmit = async (data: z.infer) => { - if (data.file instanceof Blob) { - const formMedia = new FormData(); - - loading(); - - formMedia.append("name", data.title); - formMedia.append("description", data.description); - formMedia.append("mediaTypes", data.contentType.join(",")); - formMedia.append("file", data.file); - formMedia.append("publishedFor", data.selectedUser.sort().join(",")); - formMedia.append( - "isInt", - data.publishTo === "national" ? "false" : "true" - ); - console.log(formMedia); - const response = await postCategory(formMedia); - close(); - if (response?.error == true) { - error(response.message); - return false; + if (data.publishTo.includes("polda") || data.publishTo.includes("satker")) { + if ( + (data.publishTo.includes("polda") && unitData?.length < 1) || + (data.publishTo.includes("satker") && satkerData?.length < 1) + ) { + const poldaValidation = data.publishTo.includes("polda"); + const satkerValidation = data.publishTo.includes("satker"); + toast({ + title: + poldaValidation && satkerValidation + ? "Pilih Polda dan Satker tujuan" + : `Pilih ${poldaValidation ? "Polda" : "Satker"} tujuan`, + variant: "destructive", + }); + } else { + save(data); } - router.push("/admin/settings/category?dataChange=true"); + } else { + save(data); } }; + + const save = async (data: z.infer) => { + const formMedia = new FormData(); + + loading(); + + const unit = unitData?.join(","); + const satker = satkerData?.join(","); + const join = + unitData?.length > 0 && satkerData?.length > 0 + ? unit + "," + satker + : unitData?.length > 0 + ? unit + : satkerData?.length > 0 + ? satker + : ""; + + formMedia.append("name", data.title); + formMedia.append("description", data.description); + formMedia.append("mediaTypes", data.contentType.join(",")); + formMedia.append("publishedFor", data.selectedUser.join(",")); + formMedia.append("file", files[0]); + formMedia.append("publishedLocation", data.publishTo.sort().join(",")); + formMedia.append("publishedLocationLevel", join); + + const response = await postCategory(formMedia); + close(); + if (response?.error) { + toast({ title: stringify(response.message), variant: "destructive" }); + return false; + } + toast({ + title: "Succes", + description: "Kategori berhasil dibuat", + }); + router.push("/admin/settings/category?dataChange=true"); + setIsOpen(false); + }; + + const handleRemoveFile = (file: File) => { + const uploadedFiles = files; + const filtered = uploadedFiles.filter((i) => i.name !== file.name); + setFiles([...filtered]); + }; + return ( - +