diff --git a/app/admin/master/master-menu/menu-data/create/page.tsx b/app/admin/master/master-menu/menu-data/create/page.tsx new file mode 100644 index 0000000..966e952 --- /dev/null +++ b/app/admin/master/master-menu/menu-data/create/page.tsx @@ -0,0 +1,12 @@ +import CreateMagazineForm from '@/components/form/magazine/magazine-form' +import CreateMenuDataForm from '@/components/form/master/master-menu/menu-data/menu-data-form' +import MagazineTable from '@/components/table/magazine/magazine-table' +import React from 'react' + +const AdminMenuDataCreate = () => { + return ( +
+ ) +} + +export default AdminMenuDataCreate \ No newline at end of file diff --git a/app/admin/master/master-menu/menu-data/page.tsx b/app/admin/master/master-menu/menu-data/page.tsx new file mode 100644 index 0000000..b780a00 --- /dev/null +++ b/app/admin/master/master-menu/menu-data/page.tsx @@ -0,0 +1,11 @@ +import MagazineTable from '@/components/table/magazine/magazine-table' +import MenuDataTable from '@/components/table/master/master-menu/menu-data/menu-data-table' +import React from 'react' + +const AdminMenuData = () => { + return ( +
+ ) +} + +export default AdminMenuData \ No newline at end of file diff --git a/app/admin/master/master-module/create/page.tsx b/app/admin/master/master-module/create/page.tsx new file mode 100644 index 0000000..8b7a4e2 --- /dev/null +++ b/app/admin/master/master-module/create/page.tsx @@ -0,0 +1,13 @@ +import CreateMagazineForm from '@/components/form/magazine/magazine-form' +import CreateMenuDataForm from '@/components/form/master/master-menu/menu-data/menu-data-form' +import CreateMasterModuleForm from '@/components/form/master/master-module/master-module-form' +import MagazineTable from '@/components/table/magazine/magazine-table' +import React from 'react' + +const AdminMasterModuleCreate = () => { + return ( +
+ ) +} + +export default AdminMasterModuleCreate \ No newline at end of file diff --git a/app/admin/master/master-module/page.tsx b/app/admin/master/master-module/page.tsx new file mode 100644 index 0000000..75eb767 --- /dev/null +++ b/app/admin/master/master-module/page.tsx @@ -0,0 +1,12 @@ +import MagazineTable from '@/components/table/magazine/magazine-table' +import MenuDataTable from '@/components/table/master/master-menu/menu-data/menu-data-table' +import MasterModuleTable from '@/components/table/master/master-module/master-module-table' +import React from 'react' + +const AdminMasterModule = () => { + return ( +
+ ) +} + +export default AdminMasterModule \ No newline at end of file diff --git a/components/form/magazine/magazine-form.tsx b/components/form/magazine/magazine-form.tsx index e8eed6f..94f3e13 100644 --- a/components/form/magazine/magazine-form.tsx +++ b/components/form/magazine/magazine-form.tsx @@ -12,6 +12,7 @@ import dynamic from 'next/dynamic'; import { useForm } from "react-hook-form"; import * as z from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; +import parse from 'html-react-parser'; export default function CreateMagazineForm() { const router = useRouter(); @@ -68,13 +69,17 @@ export default function CreateMagazineForm() { const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm(formOptions); const save = async (data: any) => { - + const parsedContent = parse(content); + console.log(parsedContent); const request = { title: data.title, slug: data.slug, articleBody: data.articleBody, status: 1, }; + + console.log(request); + // loading(); // // const res = await saveManualContext(request); // if (res.error) { @@ -176,6 +181,16 @@ export default function CreateMagazineForm() { )} + +
+

Description

+ setContent(newContent)} + className="dark:text-black" + /> +

Upload File (Opsional)

@@ -223,15 +238,6 @@ export default function CreateMagazineForm() { )) }
-
-

Description

- setContent(newContent)} - className="dark:text-black" - /> -
{" "} + + +
+
+
+
+ NextUI hero Image +
+
+ + + + + + + + + ) +} diff --git a/components/form/master/master-module/master-module-form.tsx b/components/form/master/master-module/master-module-form.tsx new file mode 100644 index 0000000..a08aa9b --- /dev/null +++ b/components/form/master/master-module/master-module-form.tsx @@ -0,0 +1,294 @@ +'use client' +import { Button } from "@nextui-org/button"; +import { Card, Checkbox, CheckboxGroup, Divider, Image, Input, Radio, RadioGroup, Select, SelectItem, SelectSection, Slider, Switch, Tab, Table, Tabs, Textarea, User } from "@nextui-org/react"; +import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { TimesIcon } from "@/components/icons"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { close, error, loading } from "@/config/swal"; +import Swal from 'sweetalert2'; +import withReactContent from 'sweetalert2-react-content'; +import dynamic from 'next/dynamic'; +import { useForm } from "react-hook-form"; +import * as z from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; + +const platform = [ + { label: "Article", value: "article", id: 1 }, + { label: "Caption", value: "caption", id: 2 }, + { label: "Meme", value: "meme", id: 3 }, + { label: "Video", value: "video", id: 4 }, + { label: "Master Data", value: "master-data", id: 5 }, +]; + +export default function CreateMasterModuleForm() { + const router = useRouter(); + const JoditEditor = dynamic(() => import('jodit-react'), { ssr: false }); + const MySwal = withReactContent(Swal); + const [isVisible, setIsVisible] = useState(false); + const [tabs, setTabs] = useState("personal-info") + const editor = useRef(null); + const [content, setContent] = useState(''); + const [haveChildren, setHaveChildren] = useState("no"); + const [active, setActive] = useState("1"); + const handleTab = (tab: any) => { + setTabs(tab); + }; + + const handleActive = (e: React.ChangeEvent) => { + setActive(e.target.value); + }; + + const handleHaveChildren = (e: React.ChangeEvent) => { + setHaveChildren(e.target.value); + }; + + let [files, setFiles] = useState([]); + + const removeFile = (name: string) => { + const arrayFile: File[] = []; + for (const element of files) { + if (element.name !== name) { + arrayFile.push(element); + } + } + setFiles(arrayFile); + }; + + const handleFileChange = (event: any) => { + const newFiles: FileList | null = event.target.files; + if (newFiles) { + const allowedExtensions = ['.doc', '.docx', '.pdf', '.ppt', '.pptx', '.xlsx', '.csv']; + let temp: File[] = [...files]; // Salin file-file yang sudah ada + for (let i = 0; i < newFiles.length; i++) { + const file = newFiles[i]; + const fileExtension = file.name.split('.').pop()?.toLowerCase(); + if (fileExtension && allowedExtensions.includes(`.${fileExtension}`)) { + temp.push(file); + } else { + alert('Format file tidak valid. Hanya file .doc, .docx, .ppt, .pptx, .xlsx, .csv atau .pdf yang diperbolehkan.'); + } + } + setFiles(temp); + } + }; + + const toggleVisibility = () => setIsVisible(!isVisible); + + const validationSchema = z.object({ + name: z.string().min(1, { message: "Required" }), + description: z.string().min(1, { message: "Required" }), + pathUrl: z.string().min(1, { message: "Required" }), + }); + + const formOptions = { resolver: zodResolver(validationSchema) }; + type ArticleSchema = z.infer; + + const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm(formOptions); + + const save = async (data: any) => { + + const request = { + name: data.name, + description: data.description, + pathUrl: data.pathUrl, + status: 1, + }; + + console.log(request); + // loading(); + // // const res = await saveManualContext(request); + // if (res.error) { + // error(res.message); + // return false; + // } + close(); + successSubmit("/admin/master/master-module") + } + + async function onSubmit(data: any) { + MySwal.fire({ + title: "Save Data", + text: "", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#d33", + confirmButtonColor: "#3085d6", + confirmButtonText: "Save", + }).then((result) => { + if (result.isConfirmed) { + save(data); + } + }); + } + + function successSubmit(redirect: string) { + MySwal.fire({ + title: 'Sukses', + icon: 'success', + confirmButtonColor: '#3085d6', + confirmButtonText: 'OK', + }).then((result) => { + if (result.isConfirmed) { + router.push(redirect); + } + }); + } + + return ( +
+
+ +
+
+ <> +
+
+
+ + +
+ } + /> + {errors.name?.message && ( +

+ {errors.name?.message} +

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

+ {errors.description?.message} +

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

+ {errors.description?.message} +

+ )} +
+
+ + + + Active + + + Inactive + + +
+
+ + {" "} + + +
+
+
+
+ NextUI hero Image +
+
+
+ + + + + + + + ) +} diff --git a/components/table/magazine/magazine-table.tsx b/components/table/magazine/magazine-table.tsx index cc98c8c..a4948eb 100644 --- a/components/table/magazine/magazine-table.tsx +++ b/components/table/magazine/magazine-table.tsx @@ -142,33 +142,25 @@ export default function MagazineTable() { - Detail - - Edit - - @@ -179,9 +171,7 @@ export default function MagazineTable() { /> Delete - - diff --git a/components/table/master/master-menu/menu-data/menu-data-table.tsx b/components/table/master/master-menu/menu-data/menu-data-table.tsx new file mode 100644 index 0000000..7f8f43d --- /dev/null +++ b/components/table/master/master-menu/menu-data/menu-data-table.tsx @@ -0,0 +1,231 @@ +"use client"; +import { + TableCell, + TableRow, + Table, + TableHeader, + TableColumn, + TableBody, + Pagination, + Dropdown, + DropdownTrigger, + DropdownMenu, + DropdownItem, + Input, + User, + Card, + Divider, + Chip, + ChipProps, +} from "@nextui-org/react"; +import { Button } from "@nextui-org/button"; +import React, { Key, useCallback, useMemo, useState } from "react"; +import { + AddIcon, + CreateIconIon, + DeleteIcon, + DotsYIcon, + EyeFilledIcon, + EyeIconMdi, +} from "@/components/icons"; +import Link from "next/link"; + +type UserObject = { + id: number; + name: string; + status: string; + description: string; + moduleName: string; + pathUrl: string; +}; + +const statusColorMap = { + active: "success", + paused: "danger", + vacation: "warning", +}; + + +export default function MenuDataTable() { + type TableRow = (typeof menuDataTable)[0]; + + const columns = [ + { name: "No", uid: "no" }, + { name: "Name", uid: "name" }, + { name: "Description", uid: "description" }, + { name: "Module Name", uid: "moduleName" }, + { name: "Path URL", uid: "pathUrl" }, + { name: "Status", uid: "status" }, + { name: "Action", uid: "actions" }, + ]; + + const menuDataTable = [ + { + id: 1, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + moduleName: "Multipool Acts", + pathUrl: "/admin/acts", + }, + { + id: 2, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + moduleName: "Multipool Acts", + pathUrl: "/admin/acts", + }, + { + id: 3, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + moduleName: "Multipool Acts", + pathUrl: "/admin/acts", + }, + { + id: 4, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + moduleName: "Multipool Acts", + pathUrl: "/admin/acts", + }, + { + id: 5, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + moduleName: "Multipool Acts", + pathUrl: "/admin/acts", + }, + ]; + + const renderCell = useCallback((menuData: TableRow, columnKey: Key) => { + const cellValue = menuData[columnKey as keyof UserObject]; + const statusColorMap: Record = { + active: "success", + cancel: "danger", + pending: "warning", + }; + + switch (columnKey) { + case "no": + return ( +
{menuData.id}
+ ) + + case "name": + return ( +
{menuData.name}
+ ) + + case "description": + return ( +
{menuData.description}
+ ) + + case "status": + return ( + +
+ {cellValue} +
+
+ ); + + case "actions": + return ( +
+ + + + + + + + + Detail + + + + + + Edit + + + + + + Delete + + + + +
+ ); + + default: + return cellValue; + } + }, []); + + return ( + <> +
+ + + +
+ + + {(column) => ( + {column.name} + )} + + + {(item) => ( + + {(columnKey) => ( + {renderCell(item, columnKey)} + )} + + )} + +
+
+
+ + + ); +} diff --git a/components/table/master/master-module/master-module-table.tsx b/components/table/master/master-module/master-module-table.tsx new file mode 100644 index 0000000..3bad23b --- /dev/null +++ b/components/table/master/master-module/master-module-table.tsx @@ -0,0 +1,224 @@ +"use client"; +import { + TableCell, + TableRow, + Table, + TableHeader, + TableColumn, + TableBody, + Pagination, + Dropdown, + DropdownTrigger, + DropdownMenu, + DropdownItem, + Input, + User, + Card, + Divider, + Chip, + ChipProps, +} from "@nextui-org/react"; +import { Button } from "@nextui-org/button"; +import React, { Key, useCallback, useMemo, useState } from "react"; +import { + AddIcon, + CreateIconIon, + DeleteIcon, + DotsYIcon, + EyeFilledIcon, + EyeIconMdi, +} from "@/components/icons"; +import Link from "next/link"; + +type UserObject = { + id: number; + name: string; + status: string; + description: string; + pathUrl: string; +}; + +const statusColorMap = { + active: "success", + paused: "danger", + vacation: "warning", +}; + + +export default function MasterModuleTable() { + type TableRow = (typeof masterModuleTable)[0]; + + const columns = [ + { name: "No", uid: "no" }, + { name: "Name", uid: "name" }, + { name: "Description", uid: "description" }, + { name: "Path URL", uid: "pathUrl" }, + { name: "Status", uid: "status" }, + { name: "Action", uid: "actions" }, + ]; + + const masterModuleTable = [ + { + id: 1, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + pathUrl: "/admin/acts", + }, + { + id: 2, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + pathUrl: "/admin/acts", + }, + { + id: 3, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + pathUrl: "/admin/acts", + }, + { + id: 4, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + pathUrl: "/admin/acts", + }, + { + id: 5, + name: "AI Journalist ", + status: "active", + description: "AI Journalist", + pathUrl: "/admin/acts", + }, + ]; + + const renderCell = useCallback((masterModule: TableRow, columnKey: Key) => { + const cellValue = masterModule[columnKey as keyof UserObject]; + const statusColorMap: Record = { + active: "success", + cancel: "danger", + pending: "warning", + }; + + switch (columnKey) { + case "no": + return ( +
{masterModule.id}
+ ) + + case "name": + return ( +
{masterModule.name}
+ ) + + case "description": + return ( +
{masterModule.description}
+ ) + + case "status": + return ( + +
+ {cellValue} +
+
+ ); + + case "actions": + return ( +
+ + + + + + + + + Detail + + + + + + Edit + + + + + + Delete + + + + +
+ ); + + default: + return cellValue; + } + }, []); + + return ( + <> +
+ + + +
+ + + {(column) => ( + {column.name} + )} + + + {(item) => ( + + {(columnKey) => ( + {renderCell(item, columnKey)} + )} + + )} + +
+
+
+ + + ); +} diff --git a/package-lock.json b/package-lock.json index 64674b1..fdd840a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "eslint": "8.48.0", "eslint-config-next": "14.0.2", "framer-motion": "^10.18.0", + "html-react-parser": "^5.1.10", "intl-messageformat": "^10.5.0", "jodit-react": "^4.0.25", "next": "14.0.2", @@ -3401,6 +3402,57 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.581", "license": "ISC" @@ -3420,6 +3472,17 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.22.3", "license": "MIT", @@ -4283,6 +4346,53 @@ "node": ">= 0.4" } }, + "node_modules/html-dom-parser": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-5.0.8.tgz", + "integrity": "sha512-vuWiX9EXgu8CJ5m9EP5c7bvBmNSuQVnrY8tl0z0ZX96Uth1IPlYH/8W8VZ/hBajFf18EN+j2pukbCNd01HEd1w==", + "dependencies": { + "domhandler": "5.0.3", + "htmlparser2": "9.1.0" + } + }, + "node_modules/html-react-parser": { + "version": "5.1.10", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-5.1.10.tgz", + "integrity": "sha512-gV22PvLij4wdEdtrZbGVC7Zy2OVWnQ0bYhX63S196ZRSx4+K0TuutCreHSXr+saUia8KeKB+2TYziVfijpH4Tw==", + "dependencies": { + "domhandler": "5.0.3", + "html-dom-parser": "5.0.8", + "react-property": "2.0.2", + "style-to-js": "1.1.12" + }, + "peerDependencies": { + "@types/react": "17 || 18", + "react": "0.14 || 15 || 16 || 17 || 18" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "license": "MIT", @@ -4323,6 +4433,11 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/inline-style-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", + "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==" + }, "node_modules/internal-slot": { "version": "1.0.6", "license": "MIT", @@ -5439,6 +5554,11 @@ "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" } }, + "node_modules/react-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.2.tgz", + "integrity": "sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug==" + }, "node_modules/react-remove-scroll": { "version": "2.5.7", "license": "MIT", @@ -5902,6 +6022,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.12.tgz", + "integrity": "sha512-tv+/FkgNYHI2fvCoBMsqPHh5xovwiw+C3X0Gfnss/Syau0Nr3IqGOJ9XiOYXoPnToHVbllKFf5qCNFJGwFg5mg==", + "dependencies": { + "style-to-object": "1.0.6" + } + }, + "node_modules/style-to-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", + "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", + "dependencies": { + "inline-style-parser": "0.2.3" + } + }, "node_modules/styled-jsx": { "version": "5.1.1", "license": "MIT", diff --git a/package.json b/package.json index 463b515..e160325 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "eslint": "8.48.0", "eslint-config-next": "14.0.2", "framer-motion": "^10.18.0", + "html-react-parser": "^5.1.10", "intl-messageformat": "^10.5.0", "jodit-react": "^4.0.25", "next": "14.0.2", diff --git a/public/account-category.jpg b/public/account-category.jpg new file mode 100644 index 0000000..a99ff23 Binary files /dev/null and b/public/account-category.jpg differ