feat:add create, table magazine, master menu-data, master-module
This commit is contained in:
parent
0bf1aaec3e
commit
56a401f1a2
|
|
@ -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 (
|
||||||
|
<div><CreateMenuDataForm /></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminMenuDataCreate
|
||||||
|
|
@ -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 (
|
||||||
|
<div><MenuDataTable /></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminMenuData
|
||||||
|
|
@ -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 (
|
||||||
|
<div><CreateMasterModuleForm /></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminMasterModuleCreate
|
||||||
|
|
@ -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 (
|
||||||
|
<div><MasterModuleTable /></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminMasterModule
|
||||||
|
|
@ -12,6 +12,7 @@ import dynamic from 'next/dynamic';
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import parse from 'html-react-parser';
|
||||||
|
|
||||||
export default function CreateMagazineForm() {
|
export default function CreateMagazineForm() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -68,13 +69,17 @@ export default function CreateMagazineForm() {
|
||||||
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(formOptions);
|
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(formOptions);
|
||||||
|
|
||||||
const save = async (data: any) => {
|
const save = async (data: any) => {
|
||||||
|
const parsedContent = parse(content);
|
||||||
|
console.log(parsedContent);
|
||||||
const request = {
|
const request = {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
slug: data.slug,
|
slug: data.slug,
|
||||||
articleBody: data.articleBody,
|
articleBody: data.articleBody,
|
||||||
status: 1,
|
status: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(request);
|
||||||
|
|
||||||
// loading();
|
// loading();
|
||||||
// // const res = await saveManualContext(request);
|
// // const res = await saveManualContext(request);
|
||||||
// if (res.error) {
|
// if (res.error) {
|
||||||
|
|
@ -176,6 +181,16 @@ export default function CreateMagazineForm() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-1">
|
||||||
|
<p className="text-black text-sm font-semibold my-2">Description</p>
|
||||||
|
<JoditEditor
|
||||||
|
ref={editor}
|
||||||
|
value={content}
|
||||||
|
onChange={(newContent) => setContent(newContent)}
|
||||||
|
className="dark:text-black"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<p className="text-sm text-black mt-2 pb-1 pt-3">Upload File (Opsional)</p>
|
<p className="text-sm text-black mt-2 pb-1 pt-3">Upload File (Opsional)</p>
|
||||||
<div className="w-full bg-transparent">
|
<div className="w-full bg-transparent">
|
||||||
<div className="flex items-center justify-center w-full ">
|
<div className="flex items-center justify-center w-full ">
|
||||||
|
|
@ -223,15 +238,6 @@ export default function CreateMagazineForm() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1">
|
|
||||||
<p className="text-black text-sm font-semibold my-2">Description</p>
|
|
||||||
<JoditEditor
|
|
||||||
ref={editor}
|
|
||||||
value={content}
|
|
||||||
onChange={(newContent) => setContent(newContent)}
|
|
||||||
className="dark:text-black"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row gap-3 my-3">
|
<div className="flex flex-row gap-3 my-3">
|
||||||
<Link href="/admin/magazine">
|
<Link href="/admin/magazine">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,397 @@
|
||||||
|
'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 moduleList = [
|
||||||
|
{ 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 CreateMenuDataForm() {
|
||||||
|
const router = useRouter();
|
||||||
|
const JoditEditor = dynamic(() => import('jodit-react'), { ssr: false });
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const [tabs, setTabs] = useState<string>("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<HTMLInputElement>) => {
|
||||||
|
setActive(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleHaveChildren = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setHaveChildren(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
let [files, setFiles] = useState<File[]>([]);
|
||||||
|
|
||||||
|
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" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const formOptions = { resolver: zodResolver(validationSchema) };
|
||||||
|
type ArticleSchema = z.infer<typeof validationSchema>;
|
||||||
|
|
||||||
|
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(formOptions);
|
||||||
|
|
||||||
|
const save = async (data: any) => {
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
name: data.name,
|
||||||
|
description: data.description,
|
||||||
|
moduleList: moduleList,
|
||||||
|
status: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(request);
|
||||||
|
|
||||||
|
// loading();
|
||||||
|
// // const res = await saveManualContext(request);
|
||||||
|
// if (res.error) {
|
||||||
|
// error(res.message);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
close();
|
||||||
|
successSubmit("/admin/master/master-menu/menu-data")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="mx-3 my-5">
|
||||||
|
<div className="flex flex-col gap-3 mb-4">
|
||||||
|
<Card className="w-full bg-white">
|
||||||
|
<div className="w-full mr-2 p-5 ">
|
||||||
|
<form method="POST" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<>
|
||||||
|
<div className="flex flex-row gap-1">
|
||||||
|
<div className="w-6/12 justify-start items-start mt-2 gap-3">
|
||||||
|
<div className="flex flex-col ">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
label="Name"
|
||||||
|
id="name"
|
||||||
|
{...register("name")}
|
||||||
|
placeholder="Input Name"
|
||||||
|
labelPlacement="outside"
|
||||||
|
className=" font-semibold"
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
input: "!text-black hover:!text-white focus:!text-white",
|
||||||
|
inputWrapper: "max-h-[40px] bg-transparant border text-white",
|
||||||
|
}}
|
||||||
|
startContent={
|
||||||
|
<div className="pointer-events-none flex items-center">
|
||||||
|
<span className="text-default-400 text-small"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{errors.name?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.name?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mt-3">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
label="Description"
|
||||||
|
id="description"
|
||||||
|
{...register("description")}
|
||||||
|
placeholder="Input Description"
|
||||||
|
labelPlacement="outside"
|
||||||
|
className=" font-semibold"
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
input: "!text-black hover:!text-white focus:!text-white",
|
||||||
|
inputWrapper: "max-h-[40px] bg-transparant border text-white",
|
||||||
|
}}
|
||||||
|
startContent={
|
||||||
|
<div className="pointer-events-none flex items-center">
|
||||||
|
<span className="text-default-400 text-small"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 ">
|
||||||
|
<p className="text-black text-sm mb-1 font-semibold">Main Module</p>
|
||||||
|
<Select
|
||||||
|
variant="bordered"
|
||||||
|
selectionMode="single"
|
||||||
|
labelPlacement="outside"
|
||||||
|
placeholder="Select"
|
||||||
|
className="font-semibold"
|
||||||
|
items={moduleList}
|
||||||
|
classNames={{
|
||||||
|
mainWrapper: "rounded",
|
||||||
|
listboxWrapper:
|
||||||
|
"bg-white w-full !text-indigo-500 text-center font-bold",
|
||||||
|
popoverContent: "bg-white !text-indigo-500",
|
||||||
|
trigger:
|
||||||
|
"border-1 border-gray-200 hover:!bg-gray-100 !text-black",
|
||||||
|
}}
|
||||||
|
listboxProps={{
|
||||||
|
itemClasses: {
|
||||||
|
base: [
|
||||||
|
"!text-left",
|
||||||
|
"!bg-white",
|
||||||
|
"text-indigo-500 ",
|
||||||
|
"data-[selectable=true]:!text-indigo-500",
|
||||||
|
"data-[pressed=true]:text-indigo-500",
|
||||||
|
"data-[hover=true]:!text-indigo-300",
|
||||||
|
],
|
||||||
|
wrapper: ["!bg-white border-none"],
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderValue={(items) => {
|
||||||
|
return items.map((item) => (
|
||||||
|
<span key={item.props?.value} className="text-black text-xs">
|
||||||
|
{item.textValue}
|
||||||
|
</span>
|
||||||
|
));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectSection showDivider title="Module">
|
||||||
|
{moduleList.map((list) => (
|
||||||
|
<SelectItem key={list.id} value={list.id}>
|
||||||
|
{list.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectSection>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="text-black mt-3">
|
||||||
|
<label className="text-black text-sm dark:text-black">Have sub module ?</label>
|
||||||
|
<RadioGroup
|
||||||
|
orientation="horizontal"
|
||||||
|
id="radio-banned"
|
||||||
|
className="text-gray-950 pt-2"
|
||||||
|
onChange={handleHaveChildren}
|
||||||
|
defaultValue={haveChildren}
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
description: "!text-black",
|
||||||
|
base: "!text-black",
|
||||||
|
wrapper: "!text-black",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="no"
|
||||||
|
>
|
||||||
|
No
|
||||||
|
</Radio>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="yes"
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
{haveChildren === "yes" && (
|
||||||
|
<div className="mt-3 ">
|
||||||
|
<p className="text-black text-sm mb-1 font-semibold">Sub Module</p>
|
||||||
|
<Select
|
||||||
|
variant="bordered"
|
||||||
|
selectionMode="single"
|
||||||
|
labelPlacement="outside"
|
||||||
|
placeholder="Select"
|
||||||
|
className="font-semibold"
|
||||||
|
items={moduleList}
|
||||||
|
classNames={{
|
||||||
|
mainWrapper: "rounded",
|
||||||
|
listboxWrapper:
|
||||||
|
"bg-white w-full !text-indigo-500 text-center font-bold",
|
||||||
|
popoverContent: "bg-white !text-indigo-500",
|
||||||
|
trigger:
|
||||||
|
"border-1 border-gray-200 hover:!bg-gray-100 !text-black",
|
||||||
|
}}
|
||||||
|
listboxProps={{
|
||||||
|
itemClasses: {
|
||||||
|
base: [
|
||||||
|
"!text-left",
|
||||||
|
"!bg-white",
|
||||||
|
"text-indigo-500 ",
|
||||||
|
"data-[selectable=true]:!text-indigo-500",
|
||||||
|
"data-[pressed=true]:text-indigo-500",
|
||||||
|
"data-[hover=true]:!text-indigo-300",
|
||||||
|
],
|
||||||
|
wrapper: ["!bg-white border-none"],
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
renderValue={(items) => {
|
||||||
|
return items.map((item) => (
|
||||||
|
<span key={item.props?.value} className="text-black text-xs">
|
||||||
|
{item.textValue}
|
||||||
|
</span>
|
||||||
|
));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectSection showDivider title="Module">
|
||||||
|
{moduleList.map((list) => (
|
||||||
|
<SelectItem key={list.id} value={list.id}>
|
||||||
|
{list.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectSection>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="text-black mt-3">
|
||||||
|
<label className="text-black text-sm dark:text-black">Status</label>
|
||||||
|
<RadioGroup
|
||||||
|
orientation="horizontal"
|
||||||
|
id="radio-banned"
|
||||||
|
className="text-gray-950 pt-2"
|
||||||
|
onChange={handleActive}
|
||||||
|
defaultValue={active}
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
description: "!text-black",
|
||||||
|
base: "!text-black",
|
||||||
|
wrapper: "!text-black",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="no"
|
||||||
|
>
|
||||||
|
Active
|
||||||
|
</Radio>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="yes"
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-3 my-3">
|
||||||
|
<Link href="/admin/master/master-menu/menu-data">
|
||||||
|
<Button
|
||||||
|
variant="bordered"
|
||||||
|
className="bg-white border-grey-100 rounded-full text-[#8E5C18] mr-5"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>{" "}
|
||||||
|
</Link>
|
||||||
|
<Button
|
||||||
|
className="w-[50px]"
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
type="submit">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12 ">
|
||||||
|
<div className="flex items-center justify-center justify-items-center h-full">
|
||||||
|
<Image
|
||||||
|
width={400}
|
||||||
|
alt="NextUI hero Image"
|
||||||
|
src="/account-category.jpg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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<string>("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<HTMLInputElement>) => {
|
||||||
|
setActive(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleHaveChildren = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setHaveChildren(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
let [files, setFiles] = useState<File[]>([]);
|
||||||
|
|
||||||
|
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<typeof validationSchema>;
|
||||||
|
|
||||||
|
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(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 (
|
||||||
|
<div className="mx-3 my-5">
|
||||||
|
<div className="flex flex-col gap-3 mb-4">
|
||||||
|
<Card className="w-full bg-white">
|
||||||
|
<div className="w-full mr-2 p-5 ">
|
||||||
|
<form method="POST" onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<>
|
||||||
|
<div className="flex flex-row gap-1">
|
||||||
|
<div className="w-6/12 justify-start items-start mt-2 gap-3">
|
||||||
|
<div className="flex flex-col ">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
label="Name"
|
||||||
|
id="name"
|
||||||
|
{...register("name")}
|
||||||
|
placeholder="Input Name"
|
||||||
|
labelPlacement="outside"
|
||||||
|
className=" font-semibold"
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
input: "!text-black hover:!text-white focus:!text-white",
|
||||||
|
inputWrapper: "max-h-[40px] bg-transparant border text-white",
|
||||||
|
}}
|
||||||
|
startContent={
|
||||||
|
<div className="pointer-events-none flex items-center">
|
||||||
|
<span className="text-default-400 text-small"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{errors.name?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.name?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mt-3">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
label="Description"
|
||||||
|
id="description"
|
||||||
|
{...register("description")}
|
||||||
|
placeholder="Input Description"
|
||||||
|
labelPlacement="outside"
|
||||||
|
className=" font-semibold"
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
input: "!text-black hover:!text-white focus:!text-white",
|
||||||
|
inputWrapper: "max-h-[40px] bg-transparant border text-white",
|
||||||
|
}}
|
||||||
|
startContent={
|
||||||
|
<div className="pointer-events-none flex items-center">
|
||||||
|
<span className="text-default-400 text-small"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mt-3">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
label="pathUrl"
|
||||||
|
id="pathUrl"
|
||||||
|
{...register("pathUrl")}
|
||||||
|
placeholder="Input PathUrl"
|
||||||
|
labelPlacement="outside"
|
||||||
|
className=" font-semibold"
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
input: "!text-black hover:!text-white focus:!text-white",
|
||||||
|
inputWrapper: "max-h-[40px] bg-transparant border text-white",
|
||||||
|
}}
|
||||||
|
startContent={
|
||||||
|
<div className="pointer-events-none flex items-center">
|
||||||
|
<span className="text-default-400 text-small"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-black mt-3">
|
||||||
|
<label className="text-black text-sm dark:text-black">Status</label>
|
||||||
|
<RadioGroup
|
||||||
|
orientation="horizontal"
|
||||||
|
id="radio-banned"
|
||||||
|
className="text-gray-950 pt-2"
|
||||||
|
onChange={handleActive}
|
||||||
|
defaultValue={active}
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
description: "!text-black",
|
||||||
|
base: "!text-black",
|
||||||
|
wrapper: "!text-black",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="no"
|
||||||
|
>
|
||||||
|
Active
|
||||||
|
</Radio>
|
||||||
|
<Radio
|
||||||
|
classNames={{
|
||||||
|
label: "!text-black",
|
||||||
|
}}
|
||||||
|
value="yes"
|
||||||
|
>
|
||||||
|
Inactive
|
||||||
|
</Radio>
|
||||||
|
</RadioGroup>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-3 my-3">
|
||||||
|
<Link href="/admin/master/master-menu/menu-data">
|
||||||
|
<Button
|
||||||
|
variant="bordered"
|
||||||
|
className="bg-white border-grey-100 rounded-full text-[#8E5C18] mr-5"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>{" "}
|
||||||
|
</Link>
|
||||||
|
<Button
|
||||||
|
className="w-[50px]"
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
type="submit">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-6/12 ">
|
||||||
|
<div className="flex items-center justify-center justify-items-center h-full">
|
||||||
|
<Image
|
||||||
|
width={400}
|
||||||
|
alt="NextUI hero Image"
|
||||||
|
src="/account-category.jpg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -142,33 +142,25 @@ export default function MagazineTable() {
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href={`/admin/magazine/detail`}
|
href={`/admin/magazine/detail`}
|
||||||
>
|
>
|
||||||
<EyeIconMdi className="inline mr-2 mb-1" />
|
<EyeIconMdi className="inline mr-2 mb-1" />
|
||||||
Detail
|
Detail
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href={`#`}
|
href={`#`}
|
||||||
>
|
>
|
||||||
<CreateIconIon className="inline mr-2 mb-1" />
|
<CreateIconIon className="inline mr-2 mb-1" />
|
||||||
Edit
|
Edit
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href={`#`}
|
href={`#`}
|
||||||
>
|
>
|
||||||
|
|
@ -179,9 +171,7 @@ export default function MagazineTable() {
|
||||||
/>
|
/>
|
||||||
Delete
|
Delete
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -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<string, ChipProps["color"]> = {
|
||||||
|
active: "success",
|
||||||
|
cancel: "danger",
|
||||||
|
pending: "warning",
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (columnKey) {
|
||||||
|
case "no":
|
||||||
|
return (
|
||||||
|
<div>{menuData.id}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "name":
|
||||||
|
return (
|
||||||
|
<div className="w-[150px]">{menuData.name}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "description":
|
||||||
|
return (
|
||||||
|
<div className="">{menuData.description}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "status":
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
className="capitalize "
|
||||||
|
color={statusColorMap[menuData.status]}
|
||||||
|
size="lg"
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
|
<div className="flex flex-row items-center gap-2 justify-center">
|
||||||
|
{cellValue}
|
||||||
|
</div>
|
||||||
|
</Chip>
|
||||||
|
);
|
||||||
|
|
||||||
|
case "actions":
|
||||||
|
return (
|
||||||
|
<div className="relative flex justify-star items-center gap-2">
|
||||||
|
<Dropdown className="lg:min-w-[150px] bg-black text-white shadow border ">
|
||||||
|
<DropdownTrigger>
|
||||||
|
<Button isIconOnly size="lg" variant="light">
|
||||||
|
<DotsYIcon className="text-default-300" />
|
||||||
|
</Button>
|
||||||
|
</DropdownTrigger>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`/admin/magazine/detail`}
|
||||||
|
>
|
||||||
|
<EyeIconMdi className="inline mr-2 mb-1" />
|
||||||
|
Detail
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`#`}
|
||||||
|
>
|
||||||
|
<CreateIconIon className="inline mr-2 mb-1" />
|
||||||
|
Edit
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`#`}
|
||||||
|
>
|
||||||
|
<DeleteIcon
|
||||||
|
width={20}
|
||||||
|
height={16}
|
||||||
|
className="inline mr-2 mb-1"
|
||||||
|
/>
|
||||||
|
Delete
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return cellValue;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mx-3 my-5">
|
||||||
|
<Link href="/admin/master/master-menu/menu-data/create" >
|
||||||
|
<Button className="my-3 bg-blue-600 text-white" ><CreateIconIon />Add Master Menu</Button>
|
||||||
|
</Link>
|
||||||
|
<div className="flex flex-col items-center rounded-2xl">
|
||||||
|
<Table
|
||||||
|
// selectionMode="multiple"
|
||||||
|
aria-label="micro issue table"
|
||||||
|
className="rounded-xl"
|
||||||
|
classNames={{
|
||||||
|
th: "bg-white dark:bg-black text-black dark:text-white border-b-1 text-md",
|
||||||
|
base: "bg-white dark:bg-black border",
|
||||||
|
wrapper: "min-h-[50px] bg-transpararent text-black dark:text-white ",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableHeader columns={columns}>
|
||||||
|
{(column) => (
|
||||||
|
<TableColumn key={column.uid}>{column.name}</TableColumn>
|
||||||
|
)}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody items={menuDataTable} emptyContent={"No data to display."}>
|
||||||
|
{(item) => (
|
||||||
|
<TableRow key={item.id}>
|
||||||
|
{(columnKey) => (
|
||||||
|
<TableCell>{renderCell(item, columnKey)}</TableCell>
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -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<string, ChipProps["color"]> = {
|
||||||
|
active: "success",
|
||||||
|
cancel: "danger",
|
||||||
|
pending: "warning",
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (columnKey) {
|
||||||
|
case "no":
|
||||||
|
return (
|
||||||
|
<div>{masterModule.id}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "name":
|
||||||
|
return (
|
||||||
|
<div className="w-[150px]">{masterModule.name}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "description":
|
||||||
|
return (
|
||||||
|
<div className="">{masterModule.description}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case "status":
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
className="capitalize "
|
||||||
|
color={statusColorMap[masterModule.status]}
|
||||||
|
size="lg"
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
|
<div className="flex flex-row items-center gap-2 justify-center">
|
||||||
|
{cellValue}
|
||||||
|
</div>
|
||||||
|
</Chip>
|
||||||
|
);
|
||||||
|
|
||||||
|
case "actions":
|
||||||
|
return (
|
||||||
|
<div className="relative flex justify-star items-center gap-2">
|
||||||
|
<Dropdown className="lg:min-w-[150px] bg-black text-white shadow border ">
|
||||||
|
<DropdownTrigger>
|
||||||
|
<Button isIconOnly size="lg" variant="light">
|
||||||
|
<DotsYIcon className="text-default-300" />
|
||||||
|
</Button>
|
||||||
|
</DropdownTrigger>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`/admin/magazine/detail`}
|
||||||
|
>
|
||||||
|
<EyeIconMdi className="inline mr-2 mb-1" />
|
||||||
|
Detail
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`#`}
|
||||||
|
>
|
||||||
|
<CreateIconIon className="inline mr-2 mb-1" />
|
||||||
|
Edit
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={`#`}
|
||||||
|
>
|
||||||
|
<DeleteIcon
|
||||||
|
width={20}
|
||||||
|
height={16}
|
||||||
|
className="inline mr-2 mb-1"
|
||||||
|
/>
|
||||||
|
Delete
|
||||||
|
</Link>
|
||||||
|
</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return cellValue;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mx-3 my-5">
|
||||||
|
<Link href="/admin/master/master-module/create" >
|
||||||
|
<Button className="my-3 bg-blue-600 text-white" ><CreateIconIon />Add Master Module</Button>
|
||||||
|
</Link>
|
||||||
|
<div className="flex flex-col items-center rounded-2xl">
|
||||||
|
<Table
|
||||||
|
// selectionMode="multiple"
|
||||||
|
aria-label="micro issue table"
|
||||||
|
className="rounded-xl"
|
||||||
|
classNames={{
|
||||||
|
th: "bg-white dark:bg-black text-black dark:text-white border-b-1 text-md",
|
||||||
|
base: "bg-white dark:bg-black border",
|
||||||
|
wrapper: "min-h-[50px] bg-transpararent text-black dark:text-white ",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableHeader columns={columns}>
|
||||||
|
{(column) => (
|
||||||
|
<TableColumn key={column.uid}>{column.name}</TableColumn>
|
||||||
|
)}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody items={masterModuleTable} emptyContent={"No data to display."}>
|
||||||
|
{(item) => (
|
||||||
|
<TableRow key={item.id}>
|
||||||
|
{(columnKey) => (
|
||||||
|
<TableCell>{renderCell(item, columnKey)}</TableCell>
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "14.0.2",
|
"eslint-config-next": "14.0.2",
|
||||||
"framer-motion": "^10.18.0",
|
"framer-motion": "^10.18.0",
|
||||||
|
"html-react-parser": "^5.1.10",
|
||||||
"intl-messageformat": "^10.5.0",
|
"intl-messageformat": "^10.5.0",
|
||||||
"jodit-react": "^4.0.25",
|
"jodit-react": "^4.0.25",
|
||||||
"next": "14.0.2",
|
"next": "14.0.2",
|
||||||
|
|
@ -3401,6 +3402,57 @@
|
||||||
"node": ">=6.0.0"
|
"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": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.581",
|
"version": "1.4.581",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
|
@ -3420,6 +3472,17 @@
|
||||||
"node": ">=10.13.0"
|
"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": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.22.3",
|
"version": "1.22.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -4283,6 +4346,53 @@
|
||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/ignore": {
|
||||||
"version": "5.2.4",
|
"version": "5.2.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -4323,6 +4433,11 @@
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/internal-slot": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -5439,6 +5554,11 @@
|
||||||
"react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x"
|
"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": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.5.7",
|
"version": "2.5.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -5902,6 +6022,22 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/styled-jsx": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
"eslint": "8.48.0",
|
"eslint": "8.48.0",
|
||||||
"eslint-config-next": "14.0.2",
|
"eslint-config-next": "14.0.2",
|
||||||
"framer-motion": "^10.18.0",
|
"framer-motion": "^10.18.0",
|
||||||
|
"html-react-parser": "^5.1.10",
|
||||||
"intl-messageformat": "^10.5.0",
|
"intl-messageformat": "^10.5.0",
|
||||||
"jodit-react": "^4.0.25",
|
"jodit-react": "^4.0.25",
|
||||||
"next": "14.0.2",
|
"next": "14.0.2",
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Loading…
Reference in New Issue