diff --git a/app/(admin)/admin/magazine/detail/[id]/page.tsx b/app/(admin)/admin/magazine/detail/[id]/page.tsx new file mode 100644 index 0000000..058b325 --- /dev/null +++ b/app/(admin)/admin/magazine/detail/[id]/page.tsx @@ -0,0 +1,9 @@ +import EditMagazineForm from "@/components/form/magazine/edit-magazine-form"; + +export default function DetailArticlePage() { + return ( +
+ +
+ ); +} diff --git a/app/(admin)/admin/magazine/edit/[id]/page.tsx b/app/(admin)/admin/magazine/edit/[id]/page.tsx new file mode 100644 index 0000000..d956702 --- /dev/null +++ b/app/(admin)/admin/magazine/edit/[id]/page.tsx @@ -0,0 +1,9 @@ +import EditMagazineForm from "@/components/form/magazine/edit-magazine-form"; + +export default function EditArticlePage() { + return ( +
+ +
+ ); +} diff --git a/components/form/article/create-article-form.tsx b/components/form/article/create-article-form.tsx index a51a030..4459233 100644 --- a/components/form/article/create-article-form.tsx +++ b/components/form/article/create-article-form.tsx @@ -28,6 +28,7 @@ import { close, error, loading } from "@/config/swal"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { getCategoryById } from "@/service/master-categories"; +import { saveManualContext } from "@/service/generate-article"; // const CustomEditor = dynamic( // () => { @@ -156,6 +157,31 @@ export default function CreateArticleForm() { return doc.body.innerHTML; } + const saveArticleToDise = async ( + values: z.infer + ) => { + const request = { + title: values.title, + articleBody: removeImgTags(values.description), + metaDescription: values.title, + metaTitle: values.title, + mainKeyword: values.title, + additionalKeywords: values.title, + createdBy: "345", + style: "Informational", + projectId: 2, + clientId: "humasClientIdtest", + lang: "id", + }; + + const res = await saveManualContext(request); + if (res.error) { + res.message; + return 0; + } + return res?.data?.data?.id; + }; + const save = async (values: z.infer) => { loading(); const formData = { @@ -163,11 +189,10 @@ export default function CreateArticleForm() { typeId: 1, slug: values.slug, categoryIds: values.category.map((a) => a.id).join(","), - // categoryId: values.category[0].id, tags: values.tags.join(","), description: htmlToString(removeImgTags(values.description)), htmlDescription: removeImgTags(values.description), - aiArticleId: "", + // aiArticleId: saveArticleToDise(values), }; const response = await createArticle(formData); @@ -185,7 +210,6 @@ export default function CreateArticleForm() { const resFile = await uploadArticleFile(articleId, formFiles); } } - console.log("thyu,", thumbnailImg[0]); if (thumbnailImg?.length > 0 || files?.length > 0) { if (thumbnailImg?.length > 0) { const formFiles = new FormData(); @@ -395,7 +419,6 @@ export default function CreateArticleForm() { {useAi && ( setValue("description", data)} - generatedId={(data) => {}} /> )} diff --git a/components/form/article/generate-ai-single-form.tsx b/components/form/article/generate-ai-single-form.tsx index 3d0ac60..be082c7 100644 --- a/components/form/article/generate-ai-single-form.tsx +++ b/components/form/article/generate-ai-single-form.tsx @@ -62,7 +62,6 @@ const articleSize = [ export default function GenerateSingleArticleForm(props: { content: (data: string) => void; - generatedId?: (id: string) => void; }) { const [selectedWritingSyle, setSelectedWritingStyle] = useState("Informational"); @@ -139,10 +138,8 @@ export default function GenerateSingleArticleForm(props: { createdBy: "123123", clientId: "humasClientIdtest", }; - console.log("reqq", request); const res = await generateDataArticle(request); close(); - console.log("res", res?.data?.data); if (res?.error) { error("Error"); } diff --git a/components/form/magazine/create-magazine-form.tsx b/components/form/magazine/create-magazine-form.tsx index 263e8dc..6e87668 100644 --- a/components/form/magazine/create-magazine-form.tsx +++ b/components/form/magazine/create-magazine-form.tsx @@ -160,12 +160,12 @@ export default function NewCreateMagazineForm() { // rows: values.rows, }; console.log("formd", formData); - const response = await createMagazine(formData); + // const response = await createMagazine(formData); - if (response?.error) { - error(response.message); - return false; - } + // if (response?.error) { + // error(response.message); + // return false; + // } // const magazineId = response?.data?.data?.id; // if (files?.length > 0) { // const formFiles = new FormData(); @@ -184,7 +184,7 @@ export default function NewCreateMagazineForm() { // } close(); - // successSubmit("/admin/magazine"); + successSubmit("/admin/magazine"); }; function successSubmit(redirect: string) { @@ -431,9 +431,11 @@ export default function NewCreateMagazineForm() { - + + + diff --git a/components/form/magazine/edit-magazine-form.tsx b/components/form/magazine/edit-magazine-form.tsx new file mode 100644 index 0000000..9e9ccc4 --- /dev/null +++ b/components/form/magazine/edit-magazine-form.tsx @@ -0,0 +1,459 @@ +"use client"; +import { FormEvent, Fragment, useEffect, useRef, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import * as z from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import { Input, Textarea } from "@nextui-org/input"; +import dynamic from "next/dynamic"; +import JoditEditor from "jodit-react"; +import { useDropzone } from "react-dropzone"; +import { Button } from "@nextui-org/button"; +import { CloudUploadIcon, TimesIcon } from "@/components/icons"; +import Image from "next/image"; +import { Switch } from "@nextui-org/switch"; +import { + createArticle, + getArticleByCategory, + uploadArticleFile, + uploadArticleThumbnail, +} from "@/service/article"; +import ReactSelect from "react-select"; +import makeAnimated from "react-select/animated"; +import { Checkbox, Chip } from "@nextui-org/react"; +import { htmlToString } from "@/utils/global"; +import { close, error, loading } from "@/config/swal"; +import { useParams, useRouter } from "next/navigation"; +import Link from "next/link"; +import { + CsvIcon, + ExcelIcon, + PdfIcon, + PptIcon, + WordIcon, +} from "@/components/icons/globals"; +import { + createMagazine, + getMagazineById, + updateMagazine, + uploadMagazineFile, +} from "@/service/magazine"; + +// const CustomEditor = dynamic( +// () => { +// return import("@/components/editor/custom-editor"); +// }, +// { ssr: false } +// ); + +interface FileWithPreview extends File { + preview: string; +} + +interface CategoryType { + id: number; + label: string; + value: number; +} +const categorySchema = z.object({ + id: z.number(), + label: z.string(), + value: z.number(), +}); + +const createArticleSchema = z.object({ + title: z.string().min(2, { + message: "Judul harus diisi", + }), + slug: z.string().min(2, { + message: "Slug harus diisi", + }), + description: z.string().min(2, { + message: "Deskripsi harus diisi", + }), + rows: z.array( + z.object({ + title: z.string().min(1, { + message: "Main Keyword must be at least 2 characters.", + }), + description: z.string().min(1, { + message: "Title must be at least 2 characters.", + }), + }) + ), +}); + +export default function EditMagazineForm(props: { isDetail: boolean }) { + const { isDetail } = props; + const animatedComponents = makeAnimated(); + const params = useParams(); + const id = params?.id; + const MySwal = withReactContent(Swal); + const router = useRouter(); + const editor = useRef(null); + const [files, setFiles] = useState([]); + + const { getRootProps, getInputProps } = useDropzone({ + onDrop: (acceptedFiles) => { + setFiles((prevFiles) => [ + ...prevFiles, + ...acceptedFiles.map((file) => Object.assign(file)), + ]); + }, + multiple: true, + accept: { + "application/pdf": [".pdf"], + "application/vnd.openxmlformats-officedocument.presentationml.presentation": + [".pptx"], + "application/vnd.ms-powerpoint": [".ppt"], + "application/vnd.openxmlformats-officedocument.wordprocessingml.document": + [".docx"], + "application/msword": [".doc"], + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [ + ".xlsx", + ], + "application/vnd.ms-excel": [".xls"], + "text/csv": [".csv"], + }, + }); + + const formOptions = { + resolver: zodResolver(createArticleSchema), + defaultValues: { title: "", description: "", category: [], tags: [] }, + }; + type UserSettingSchema = z.infer; + const { + register, + control, + handleSubmit, + formState: { errors }, + setValue, + getValues, + watch, + setError, + clearErrors, + } = useForm(formOptions); + + useEffect(() => { + initFetch(); + }, [id]); + + const initFetch = async () => { + const res = await getMagazineById(String(id)); + const data = res?.data?.data; + setValue("title", data?.title); + setValue("description", data?.description); + console.log("datasss", data); + }; + + const onSubmit = async (values: z.infer) => { + MySwal.fire({ + title: "Simpan Data", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Simpan", + }).then((result) => { + if (result.isConfirmed) { + save(values); + } + }); + }; + + const save = async (values: z.infer) => { + loading(); + const formData = { + id: Number(id), + title: values.title, + typeId: 1, + slug: values.slug, + statusId: 1, + // description: htmlToString(removeImgTags(values.description)), + description: values.description, + // rows: values.rows, + }; + console.log("formd", formData); + const response = await updateMagazine(String(id), formData); + + if (response?.error) { + error(response.message); + return false; + } + const magazineId = response?.data?.data?.id; + // if (files?.length > 0) { + // const formFiles = new FormData(); + + // for (const element of files) { + // formFiles.append("file", element); + // const resFile = await uploadMagazineFile(magazineId, formFiles); + // } + // } + + close(); + successSubmit("/admin/magazine"); + }; + + function successSubmit(redirect: string) { + MySwal.fire({ + title: "Sukses", + icon: "success", + confirmButtonColor: "#3085d6", + confirmButtonText: "OK", + }).then((result) => { + if (result.isConfirmed) { + router.push(redirect); + } + }); + } + + const watchTitle = watch("title"); + const generateSlug = (title: string) => { + return title + .toLowerCase() + .trim() + .replace(/[^\w\s-]/g, "") + .replace(/\s+/g, "-"); + }; + + useEffect(() => { + setValue("slug", generateSlug(watchTitle)); + }, [watchTitle]); + + const renderPreview = (file: File) => { + if (file.type === "application/pdf") { + return ; + } else if (file.type === "text/csv") { + return ; + } else if ( + file.type === + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || + file.type === "application/msword" + ) { + return ; + } else if ( + file.type === + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || + file.type === "application/vnd.ms-excel" + ) { + return ; + } else if ( + file.type === + "application/vnd.openxmlformats-officedocument.presentationml.presentation" || + file.type === "application/vnd.ms-powerpoint" + ) { + return ; + } else { + return "unknown"; + } + }; + + const handleRemoveFile = (file: FileWithPreview) => { + const uploadedFiles = files; + const filtered = uploadedFiles.filter((i) => i.name !== file.name); + setFiles([...filtered]); + }; + + const fileList = files.map((file, index) => ( +
+
+
{renderPreview(file)}
+ +
+

Nama File

+
+

{file.name}

+

+ {Math.round(file.size / 100) / 10 > 1000 ? ( + <>{(Math.round(file.size / 100) / 10000).toFixed(1)} + ) : ( + <>{(Math.round(file.size / 100) / 10).toFixed(1)} + )} + {" kb"} +

+
+

Judul

+ setValue(`rows.${index}.title`, e)} + labelPlacement="outside" + className="w-full " + classNames={{ + inputWrapper: [ + "border-1 rounded-lg", + "dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400", + ], + }} + variant="bordered" + /> +

Deskripsi

+