feat:userlevel form
This commit is contained in:
parent
e4dd1da844
commit
66aaa5f0b3
|
|
@ -1,12 +1,34 @@
|
||||||
|
import { AddIcon } from "@/components/icons";
|
||||||
import MappingUserLevel from "@/components/table/master/master-user-level/mapping-user-level";
|
import MappingUserLevel from "@/components/table/master/master-user-level/mapping-user-level";
|
||||||
import MasterUserLevelTable from "@/components/table/master/master-user-level/master-user-level-table";
|
import MasterUserLevelTable from "@/components/table/master/master-user-level/master-user-level-table";
|
||||||
|
import { Button } from "@heroui/button";
|
||||||
|
import Link from "next/link";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const AdminMasterUserLevel = () => {
|
const AdminMasterUserLevel = () => {
|
||||||
return (
|
return (
|
||||||
// <div><MasterUserLevelTable /></div>
|
// <div>
|
||||||
<div>
|
// <MasterUserLevelTable />
|
||||||
<MappingUserLevel />
|
// </div>
|
||||||
|
// <div>
|
||||||
|
// <MappingUserLevel />
|
||||||
|
// </div>
|
||||||
|
<div className="overflow-x-hidden overflow-y-scroll">
|
||||||
|
<div className="px-2 md:px-4 md:py-4 w-full">
|
||||||
|
<div className="bg-white shadow-lg dark:bg-[#18181b] rounded-xl py-3">
|
||||||
|
<Link href="/admin/master-user-level/create" className="mx-3">
|
||||||
|
<Button
|
||||||
|
size="md"
|
||||||
|
color="primary"
|
||||||
|
className="bg-[#F07C00] text-white"
|
||||||
|
>
|
||||||
|
Pengguna Baru
|
||||||
|
<AddIcon />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<MasterUserLevelTable />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import CreateMasterUserLevelForm from "@/components/form/master/master-user-level/master-user-level-form";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const AdminMasterUserLevelCreate = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<CreateMasterUserLevelForm />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminMasterUserLevelCreate;
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import EditUserLevelForm from "@/components/form/master/master-user-level/edit-user-level-form";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const AdminMasterUserLevelCreate = () => {
|
||||||
|
return <EditUserLevelForm />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminMasterUserLevelCreate;
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { AddIcon } from "@/components/icons";
|
||||||
|
import MappingUserLevel from "@/components/table/master/master-user-level/mapping-user-level";
|
||||||
|
import MasterUserLevelTable from "@/components/table/master/master-user-level/master-user-level-table";
|
||||||
|
import { Button } from "@heroui/button";
|
||||||
|
import Link from "next/link";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const AdminMasterUserLevel = () => {
|
||||||
|
return (
|
||||||
|
// <div>
|
||||||
|
// <MasterUserLevelTable />
|
||||||
|
// </div>
|
||||||
|
// <div>
|
||||||
|
// <MappingUserLevel />
|
||||||
|
// </div>
|
||||||
|
<div className="overflow-x-hidden overflow-y-scroll">
|
||||||
|
<div className="px-2 md:px-4 md:py-4 w-full">
|
||||||
|
<div className="bg-white shadow-lg dark:bg-[#18181b] rounded-xl py-3">
|
||||||
|
<Link href="/admin/user-level/create" className="mx-3">
|
||||||
|
<Button
|
||||||
|
size="md"
|
||||||
|
color="primary"
|
||||||
|
className="bg-[#F07C00] text-white"
|
||||||
|
>
|
||||||
|
Pengguna Baru
|
||||||
|
<AddIcon />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<MasterUserLevelTable />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminMasterUserLevel;
|
||||||
|
|
@ -29,6 +29,7 @@ import {
|
||||||
import ReactSelect from "react-select";
|
import ReactSelect from "react-select";
|
||||||
import makeAnimated from "react-select/animated";
|
import makeAnimated from "react-select/animated";
|
||||||
import {
|
import {
|
||||||
|
Calendar,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Chip,
|
Chip,
|
||||||
Modal,
|
Modal,
|
||||||
|
|
@ -36,13 +37,16 @@ import {
|
||||||
ModalContent,
|
ModalContent,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
Select,
|
Select,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectSection,
|
SelectSection,
|
||||||
useDisclosure,
|
useDisclosure,
|
||||||
} from "@heroui/react";
|
} from "@heroui/react";
|
||||||
import GenerateSingleArticleForm from "./generate-ai-single-form";
|
import GenerateSingleArticleForm from "./generate-ai-single-form";
|
||||||
import { htmlToString } from "@/utils/global";
|
import { convertDateFormatNoTime, htmlToString } from "@/utils/global";
|
||||||
import { close, error, loading } from "@/config/swal";
|
import { close, error, loading } from "@/config/swal";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -130,10 +134,7 @@ export default function CreateArticleForm() {
|
||||||
const [isScheduled, setIsScheduled] = useState(false);
|
const [isScheduled, setIsScheduled] = useState(false);
|
||||||
const [timeValue, setTimeValue] = useState("");
|
const [timeValue, setTimeValue] = useState("");
|
||||||
|
|
||||||
const [startDateValue, setStartDateValue] = useState({
|
const [startDateValue, setStartDateValue] = useState<any>(null);
|
||||||
startDate: null,
|
|
||||||
endDate: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
onDrop: (acceptedFiles) => {
|
onDrop: (acceptedFiles) => {
|
||||||
|
|
@ -766,15 +767,15 @@ export default function CreateArticleForm() {
|
||||||
{errors?.tags && (
|
{errors?.tags && (
|
||||||
<p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p>
|
<p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p>
|
||||||
)}
|
)}
|
||||||
{/* <div className="flex flex-col gap-2 mt-3">
|
<div className="flex flex-col gap-2 mt-3">
|
||||||
<Switch isSelected={isScheduled} onValueChange={setIsScheduled}>
|
<Switch isSelected={isScheduled} onValueChange={setIsScheduled}>
|
||||||
Publish dengan Jadwal
|
<p className="text-black">Publish dengan Jadwal</p>
|
||||||
</Switch>
|
</Switch>
|
||||||
{isScheduled && (
|
{isScheduled && (
|
||||||
<div className="flex flex-col lg:flex-row gap-3">
|
<div className="flex flex-col lg:flex-row gap-3">
|
||||||
<div className="w-full lg:w-[140px] flex flex-col gal-2 ">
|
<div className="w-full lg:w-[140px] flex flex-col gal-2 ">
|
||||||
<p className="text-sm">Tanggal</p>
|
<p className="text-sm">Tanggal</p>
|
||||||
<Datepicker
|
{/* <Datepicker
|
||||||
value={startDateValue}
|
value={startDateValue}
|
||||||
displayFormat="DD/MM/YYYY"
|
displayFormat="DD/MM/YYYY"
|
||||||
popoverDirection="down"
|
popoverDirection="down"
|
||||||
|
|
@ -782,9 +783,30 @@ export default function CreateArticleForm() {
|
||||||
useRange={false}
|
useRange={false}
|
||||||
onChange={(e: any) => setStartDateValue(e)}
|
onChange={(e: any) => setStartDateValue(e)}
|
||||||
inputClassName="z-50 w-full text-xs lg:text-sm bg-white dark bg-black border-1 border-gray-200 px-2 py-[6px] rounded-sm lg:rounded-lg h-[30px] lg:h-[40px] text-gray-600 dark:text-gray-300"
|
inputClassName="z-50 w-full text-xs lg:text-sm bg-white dark bg-black border-1 border-gray-200 px-2 py-[6px] rounded-sm lg:rounded-lg h-[30px] lg:h-[40px] text-gray-600 dark:text-gray-300"
|
||||||
/>
|
/> */}
|
||||||
|
<Popover
|
||||||
|
placement="bottom"
|
||||||
|
classNames={{ content: ["!bg-transparent", "p-0"] }}
|
||||||
|
>
|
||||||
|
<PopoverTrigger>
|
||||||
|
<Button
|
||||||
|
className="w-full !h-[30px] lg:h-[40px] border-1 rounded-lg text-black"
|
||||||
|
variant="bordered"
|
||||||
|
>
|
||||||
|
{startDateValue
|
||||||
|
? convertDateFormatNoTime(startDateValue)
|
||||||
|
: "-"}
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="bg-transparent">
|
||||||
|
<Calendar
|
||||||
|
value={startDateValue}
|
||||||
|
onChange={setStartDateValue}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-[140px] flex flex-col gal-2 ">
|
{/* <div className="w-[140px] flex flex-col gal-2 ">
|
||||||
<p className="text-sm">Waktu</p>
|
<p className="text-sm">Waktu</p>
|
||||||
<Input
|
<Input
|
||||||
type="time"
|
type="time"
|
||||||
|
|
@ -802,10 +824,10 @@ export default function CreateArticleForm() {
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row justify-end gap-3">
|
<div className="flex flex-row justify-end gap-3">
|
||||||
|
|
@ -813,7 +835,7 @@ export default function CreateArticleForm() {
|
||||||
color="primary"
|
color="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
isDisabled={
|
isDisabled={
|
||||||
(isScheduled && startDateValue.startDate == null) ||
|
(isScheduled && startDateValue == null) ||
|
||||||
(isScheduled && timeValue == "")
|
(isScheduled && timeValue == "")
|
||||||
}
|
}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,358 @@
|
||||||
|
"use client";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Input,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Select,
|
||||||
|
SelectItem,
|
||||||
|
SelectSection,
|
||||||
|
Slider,
|
||||||
|
Switch,
|
||||||
|
Tab,
|
||||||
|
Table,
|
||||||
|
Tabs,
|
||||||
|
Textarea,
|
||||||
|
User,
|
||||||
|
} from "@heroui/react";
|
||||||
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import { TimesIcon } from "@/components/icons";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useParams, 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 { Controller, useForm } from "react-hook-form";
|
||||||
|
import * as z from "zod";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import {
|
||||||
|
createUserLevels,
|
||||||
|
editUserLevels,
|
||||||
|
getAllUserLevels,
|
||||||
|
getUserLevels,
|
||||||
|
} from "@/services/user-levels/user-levels-service";
|
||||||
|
import ReactSelect from "react-select";
|
||||||
|
import makeAnimated from "react-select/animated";
|
||||||
|
|
||||||
|
const createArticleSchema = z.object({
|
||||||
|
name: z.string().min(2, {
|
||||||
|
message: "Required",
|
||||||
|
}),
|
||||||
|
aliasName: z.string().optional(),
|
||||||
|
group: z.string().min(2, {
|
||||||
|
message: "Required",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const groups = [
|
||||||
|
{ id: 1, name: "Mabes", value: "mabes", level: 1 },
|
||||||
|
{ id: 2, name: "Polda", value: "polda", level: 2 },
|
||||||
|
{ id: 3, name: "Satker", value: "satker", level: 2 },
|
||||||
|
{ id: 4, name: "Polres", value: "polres", level: 3 },
|
||||||
|
{ id: 5, name: "Subdiv", value: "subdiv", level: 3 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function EditUserLevelForm() {
|
||||||
|
const router = useRouter();
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const animatedComponents = makeAnimated();
|
||||||
|
const [needApproval, setNeedApproval] = useState(false);
|
||||||
|
const [parentList, setParentList] = useState<any>([]);
|
||||||
|
const [selectedParent, setSelectedParent] = useState<any>();
|
||||||
|
const params = useParams();
|
||||||
|
const id = params?.id;
|
||||||
|
|
||||||
|
const formOptions = {
|
||||||
|
resolver: zodResolver(createArticleSchema),
|
||||||
|
defaultValues: { name: "", group: "" },
|
||||||
|
};
|
||||||
|
type UserSettingSchema = z.infer<typeof createArticleSchema>;
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors, isValid },
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
watch,
|
||||||
|
setError,
|
||||||
|
clearErrors,
|
||||||
|
} = useForm<UserSettingSchema>(formOptions);
|
||||||
|
|
||||||
|
const watchName = watch("name");
|
||||||
|
const generateSlug = (title: string) => {
|
||||||
|
return title
|
||||||
|
.toLowerCase()
|
||||||
|
.trim()
|
||||||
|
.replace(/[^\w\s-]/g, "")
|
||||||
|
.replace(/\s+/g, "-");
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue("aliasName", generateSlug(watchName));
|
||||||
|
}, [watchName]);
|
||||||
|
|
||||||
|
const findSelectedLevel = (group: string) => {
|
||||||
|
const selectedLevel = groups.find((a) => a.value === group);
|
||||||
|
return selectedLevel ? selectedLevel : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const save = async (data: any) => {
|
||||||
|
const findParent = (group: string) => {
|
||||||
|
if (group === "mabes") {
|
||||||
|
return 0;
|
||||||
|
} else if (group === "polda" || group === "satker") {
|
||||||
|
if (group === "polda") {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 555;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return selectedParent?.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
name: data.name,
|
||||||
|
aliasName: data.aliasName,
|
||||||
|
levelNumber: findSelectedLevel(data.group)?.level,
|
||||||
|
isActive: true,
|
||||||
|
group: data.group,
|
||||||
|
parentLevelId: findParent(data.group),
|
||||||
|
provinceId: 0,
|
||||||
|
isApprovalActive: needApproval,
|
||||||
|
};
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await editUserLevels(String(id), request);
|
||||||
|
if (res.error) {
|
||||||
|
error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
successSubmit("/admin/user-level");
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCategory();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchCategory = async () => {
|
||||||
|
loading();
|
||||||
|
const request = {
|
||||||
|
limit: 10,
|
||||||
|
};
|
||||||
|
const res = await getAllUserLevels(request);
|
||||||
|
close();
|
||||||
|
if (res?.data?.data) {
|
||||||
|
setupParent(res?.data?.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupParent = (data: any) => {
|
||||||
|
const temp = [];
|
||||||
|
for (const element of data) {
|
||||||
|
temp.push({
|
||||||
|
id: element.id,
|
||||||
|
label: element.name,
|
||||||
|
value: element.aliasName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setParentList(temp);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedGroup = watch("group");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initFetch();
|
||||||
|
}, [parentList]);
|
||||||
|
|
||||||
|
const initFetch = async () => {
|
||||||
|
const res = await getUserLevels(String(id));
|
||||||
|
const data = res?.data?.data;
|
||||||
|
setValue("name", data?.name);
|
||||||
|
setValue("aliasName", data?.aliasName);
|
||||||
|
setValue("group", data?.group);
|
||||||
|
const parentId = parentList.find((a: any) => a.id === data?.parentLevelId);
|
||||||
|
setSelectedParent(parentId);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="flex flex-col lg:flex-row gap-8 text-black p-4 lg:p-8"
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
>
|
||||||
|
<div className="w-full lg:w-1/2 bg-white rounded-lg p-4 lg:p-8 flex flex-col gap-1 shadow-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
Name<span className="text-danger">*</span>
|
||||||
|
</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="name"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.name && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">{errors.name?.message}</p>
|
||||||
|
)}
|
||||||
|
<p className="text-sm mt-3">Alias Name</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="aliasName"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
id="alias"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
isReadOnly
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.aliasName && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">
|
||||||
|
{errors.aliasName?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<p className="text-sm mt-3">
|
||||||
|
Group<span className="text-danger">*</span>
|
||||||
|
</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="group"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Select
|
||||||
|
variant="bordered"
|
||||||
|
label=""
|
||||||
|
labelPlacement="outside"
|
||||||
|
selectedKeys={[value]}
|
||||||
|
onChange={onChange}
|
||||||
|
classNames={{
|
||||||
|
trigger: [
|
||||||
|
"border-1 rounded-lg",
|
||||||
|
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{groups.map((group) => (
|
||||||
|
<SelectItem key={group.value}>{group.name}</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.name && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">{errors.name?.message}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<p className="text-sm mt-3">Need Approval</p>
|
||||||
|
<Switch isSelected={needApproval} onValueChange={setNeedApproval}>
|
||||||
|
<p className="text-sm text-black">
|
||||||
|
{needApproval ? "Active" : "Inactive"}
|
||||||
|
</p>
|
||||||
|
</Switch>
|
||||||
|
{findSelectedLevel(selectedGroup)?.level === 3 && (
|
||||||
|
<>
|
||||||
|
<p className="text-sm mt-3">Parent</p>
|
||||||
|
<ReactSelect
|
||||||
|
className="basic-single text-black z-50"
|
||||||
|
classNames={{
|
||||||
|
control: (state: any) =>
|
||||||
|
"!rounded-lg bg-white !border-1 !border-gray-200 dark:!border-stone-500",
|
||||||
|
}}
|
||||||
|
classNamePrefix="select"
|
||||||
|
value={selectedParent}
|
||||||
|
onChange={setSelectedParent}
|
||||||
|
closeMenuOnSelect={false}
|
||||||
|
components={animatedComponents}
|
||||||
|
isClearable={true}
|
||||||
|
isSearchable={true}
|
||||||
|
isMulti={false}
|
||||||
|
placeholder=""
|
||||||
|
name="sub-module"
|
||||||
|
options={parentList}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-3 mt-5">
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
isDisabled={
|
||||||
|
findSelectedLevel(selectedGroup)?.level === 3 && !selectedParent
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
<Link href="/admin/master-user-level">
|
||||||
|
<Button color="danger">Kembali</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,413 +1,339 @@
|
||||||
'use client'
|
"use client";
|
||||||
import { Button } from "@heroui/button";
|
import {
|
||||||
import { Card, Checkbox, CheckboxGroup, Divider, Image, Input, Radio, RadioGroup, Select, SelectItem, SelectSection, Slider, Switch, Tab, Table, Tabs, Textarea, User } from "@heroui/react";
|
Button,
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
Input,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Select,
|
||||||
|
SelectItem,
|
||||||
|
SelectSection,
|
||||||
|
Slider,
|
||||||
|
Switch,
|
||||||
|
Tab,
|
||||||
|
Table,
|
||||||
|
Tabs,
|
||||||
|
Textarea,
|
||||||
|
User,
|
||||||
|
} from "@heroui/react";
|
||||||
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { TimesIcon } from "@/components/icons";
|
import { TimesIcon } from "@/components/icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { close, error, loading } from "@/config/swal";
|
import { close, error, loading } from "@/config/swal";
|
||||||
import Swal from 'sweetalert2';
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from 'sweetalert2-react-content';
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from "next/dynamic";
|
||||||
import { useForm } from "react-hook-form";
|
import { Controller, 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 { createUserLevels } from "@/services/user-levels/user-levels-service";
|
import {
|
||||||
|
createUserLevels,
|
||||||
|
getAllUserLevels,
|
||||||
|
} from "@/services/user-levels/user-levels-service";
|
||||||
|
import ReactSelect from "react-select";
|
||||||
|
import makeAnimated from "react-select/animated";
|
||||||
|
|
||||||
const LevelList = [
|
const createArticleSchema = z.object({
|
||||||
{ label: "Admin", value: "admin", id: 1 },
|
name: z.string().min(2, {
|
||||||
{ label: "Super-Admin", value: "super-admin", id: 2 },
|
message: "Required",
|
||||||
{ label: "Kurator", value: "kurator", id: 3 },
|
}),
|
||||||
{ label: "Supervisor", value: "supervisor", id: 4 },
|
aliasName: z.string().optional(),
|
||||||
];
|
group: z.string().min(2, {
|
||||||
|
message: "Required",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const moduleList = [
|
const groups = [
|
||||||
{ label: "Article", value: "article", id: 1 },
|
{ id: 1, name: "Mabes", value: "mabes", level: 1 },
|
||||||
{ label: "Caption", value: "caption", id: 2 },
|
{ id: 2, name: "Polda", value: "polda", level: 2 },
|
||||||
{ label: "Meme", value: "meme", id: 3 },
|
{ id: 3, name: "Satker", value: "satker", level: 2 },
|
||||||
{ label: "Video", value: "video", id: 4 },
|
{ id: 4, name: "Polres", value: "polres", level: 3 },
|
||||||
{ label: "Master Data", value: "master-data", id: 5 },
|
{ id: 5, name: "Subdiv", value: "subdiv", level: 3 },
|
||||||
];
|
|
||||||
|
|
||||||
const provinceList = [
|
|
||||||
{ label: "NTT", value: "1", id: 1 },
|
|
||||||
{ label: "NTB", value: "2", id: 2 },
|
|
||||||
{ label: "Aceh", value: "3", id: 3 },
|
|
||||||
{ label: "Jawa Timur", value: "4", id: 4 },
|
|
||||||
{ label: "Jawa Barat", value: "5", id: 5 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function CreateMasterUserLevelForm() {
|
export default function CreateMasterUserLevelForm() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const JoditEditor = dynamic(() => import('jodit-react'), { ssr: false });
|
const MySwal = withReactContent(Swal);
|
||||||
const MySwal = withReactContent(Swal);
|
const animatedComponents = makeAnimated();
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [needApproval, setNeedApproval] = useState(false);
|
||||||
const [tabs, setTabs] = useState<string>("personal-info")
|
const [parentList, setParentList] = useState<any>([]);
|
||||||
const editor = useRef(null);
|
const [selectedParent, setSelectedParent] = useState<any>();
|
||||||
const [content, setContent] = useState('');
|
|
||||||
const [haveChildren, setHaveChildren] = useState("no");
|
|
||||||
const [active, setTrue] = useState("true");
|
|
||||||
const [levelValue, setLevelValue] = useState<any>("");
|
|
||||||
const handleTab = (tab: any) => {
|
|
||||||
setTabs(tab);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleActive = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const formOptions = {
|
||||||
setTrue(e.target.value);
|
resolver: zodResolver(createArticleSchema),
|
||||||
};
|
defaultValues: { name: "", group: "" },
|
||||||
|
};
|
||||||
|
type UserSettingSchema = z.infer<typeof createArticleSchema>;
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors, isValid },
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
watch,
|
||||||
|
setError,
|
||||||
|
clearErrors,
|
||||||
|
} = useForm<UserSettingSchema>(formOptions);
|
||||||
|
|
||||||
const handleHaveChildren = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const watchName = watch("name");
|
||||||
setHaveChildren(e.target.value);
|
const generateSlug = (title: string) => {
|
||||||
};
|
return title
|
||||||
|
.toLowerCase()
|
||||||
|
.trim()
|
||||||
|
.replace(/[^\w\s-]/g, "")
|
||||||
|
.replace(/\s+/g, "-");
|
||||||
|
};
|
||||||
|
|
||||||
let [files, setFiles] = useState<File[]>([]);
|
useEffect(() => {
|
||||||
|
setValue("aliasName", generateSlug(watchName));
|
||||||
|
}, [watchName]);
|
||||||
|
|
||||||
const removeFile = (name: string) => {
|
const findSelectedLevel = (group: string) => {
|
||||||
const arrayFile: File[] = [];
|
const selectedLevel = groups.find((a) => a.value === group);
|
||||||
for (const element of files) {
|
return selectedLevel ? selectedLevel : null;
|
||||||
if (element.name !== name) {
|
};
|
||||||
arrayFile.push(element);
|
|
||||||
}
|
const save = async (data: any) => {
|
||||||
|
const findParent = (group: string) => {
|
||||||
|
if (group === "mabes") {
|
||||||
|
return 0;
|
||||||
|
} else if (group === "polda" || group === "satker") {
|
||||||
|
if (group === "polda") {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 555;
|
||||||
}
|
}
|
||||||
setFiles(arrayFile);
|
} else {
|
||||||
|
return selectedParent?.id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileChange = (event: any) => {
|
const request = {
|
||||||
const newFiles: FileList | null = event.target.files;
|
name: data.name,
|
||||||
if (newFiles) {
|
aliasName: data.aliasName,
|
||||||
const allowedExtensions = ['.doc', '.docx', '.pdf', '.ppt', '.pptx', '.xlsx', '.csv'];
|
levelNumber: findSelectedLevel(data.group)?.level,
|
||||||
let temp: File[] = [...files]; // Salin file-file yang sudah ada
|
isActive: true,
|
||||||
for (let i = 0; i < newFiles.length; i++) {
|
group: data.group,
|
||||||
const file = newFiles[i];
|
parentLevelId: findParent(data.group),
|
||||||
const fileExtension = file.name.split('.').pop()?.toLowerCase();
|
provinceId: 0,
|
||||||
if (fileExtension && allowedExtensions.includes(`.${fileExtension}`)) {
|
isApprovalActive: needApproval,
|
||||||
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);
|
loading();
|
||||||
|
const res = await createUserLevels(request);
|
||||||
|
if (res.error) {
|
||||||
|
error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
successSubmit("/admin/user-level");
|
||||||
|
};
|
||||||
|
|
||||||
const validationSchema = z.object({
|
async function onSubmit(data: any) {
|
||||||
name: z.string().min(1, { message: "Required" }),
|
MySwal.fire({
|
||||||
aliasName: z.string().min(1, { message: "Required" }),
|
title: "Save Data",
|
||||||
// levelNumber: z.string().min(1, { message: "Required" }),
|
text: "",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
cancelButtonColor: "#d33",
|
||||||
|
confirmButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "Save",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
save(data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const formOptions = { resolver: zodResolver(validationSchema) };
|
function successSubmit(redirect: string) {
|
||||||
type ArticleSchema = z.infer<typeof validationSchema>;
|
MySwal.fire({
|
||||||
|
title: "Sukses",
|
||||||
|
icon: "success",
|
||||||
|
confirmButtonColor: "#3085d6",
|
||||||
|
confirmButtonText: "OK",
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
router.push(redirect);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(formOptions);
|
useEffect(() => {
|
||||||
|
fetchCategory();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const save = async (data: any) => {
|
const fetchCategory = async () => {
|
||||||
const selectedLevel = Number(Array.from(levelValue).pop());
|
loading();
|
||||||
const request = {
|
const request = {
|
||||||
name: data.name,
|
limit: 10,
|
||||||
aliasName: data.aliasName,
|
};
|
||||||
levelNumber: selectedLevel,
|
const res = await getAllUserLevels(request);
|
||||||
isActive: active,
|
close();
|
||||||
};
|
if (res?.data?.data) {
|
||||||
|
setupParent(res?.data?.data);
|
||||||
console.log(request);
|
|
||||||
loading();
|
|
||||||
const res = await createUserLevels(request);
|
|
||||||
if (res.error) {
|
|
||||||
error(res.message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close();
|
|
||||||
successSubmit("/admin/master/master-user-level")
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
async function onSubmit(data: any) {
|
const setupParent = (data: any) => {
|
||||||
MySwal.fire({
|
const temp = [];
|
||||||
title: "Save Data",
|
for (const element of data) {
|
||||||
text: "",
|
temp.push({
|
||||||
icon: "warning",
|
id: element.id,
|
||||||
showCancelButton: true,
|
label: element.name,
|
||||||
cancelButtonColor: "#d33",
|
value: element.aliasName,
|
||||||
confirmButtonColor: "#3085d6",
|
});
|
||||||
confirmButtonText: "Save",
|
}
|
||||||
}).then((result) => {
|
setParentList(temp);
|
||||||
if (result.isConfirmed) {
|
};
|
||||||
save(data);
|
|
||||||
|
const selectedGroup = watch("group");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="flex flex-col lg:flex-row gap-8 text-black p-8"
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
>
|
||||||
|
<div className="w-full lg:w-1/2 bg-white rounded-lg p-8 flex flex-col gap-1 shadow-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
Name<span className="text-danger">*</span>
|
||||||
|
</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="name"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.name && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">{errors.name?.message}</p>
|
||||||
|
)}
|
||||||
|
<p className="text-sm mt-3">Alias Name</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="aliasName"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
id="alias"
|
||||||
|
placeholder=""
|
||||||
|
label=""
|
||||||
|
isReadOnly
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.aliasName && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">
|
||||||
|
{errors.aliasName?.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<p className="text-sm mt-3">
|
||||||
|
Group<span className="text-danger">*</span>
|
||||||
|
</p>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="group"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<Select
|
||||||
|
variant="bordered"
|
||||||
|
label=""
|
||||||
|
labelPlacement="outside"
|
||||||
|
selectedKeys={[value]}
|
||||||
|
onChange={onChange}
|
||||||
|
classNames={{
|
||||||
|
trigger: [
|
||||||
|
"border-1 rounded-lg",
|
||||||
|
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{groups.map((group) => (
|
||||||
|
<SelectItem key={group.value}>{group.name}</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors?.name && (
|
||||||
|
<p className="text-red-400 text-sm mb-3">{errors.name?.message}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<p className="text-sm mt-3">Need Approval</p>
|
||||||
|
<Switch isSelected={needApproval} onValueChange={setNeedApproval}>
|
||||||
|
<p className="text-sm text-black">
|
||||||
|
{needApproval ? "Active" : "Inactive"}
|
||||||
|
</p>
|
||||||
|
</Switch>
|
||||||
|
{findSelectedLevel(selectedGroup)?.level === 3 && (
|
||||||
|
<>
|
||||||
|
<p className="text-sm mt-3">Parent</p>
|
||||||
|
<ReactSelect
|
||||||
|
className="basic-single text-black z-50"
|
||||||
|
classNames={{
|
||||||
|
control: (state: any) =>
|
||||||
|
"!rounded-lg bg-white !border-1 !border-gray-200 dark:!border-stone-500",
|
||||||
|
}}
|
||||||
|
classNamePrefix="select"
|
||||||
|
onChange={setSelectedParent}
|
||||||
|
closeMenuOnSelect={false}
|
||||||
|
components={animatedComponents}
|
||||||
|
isClearable={true}
|
||||||
|
isSearchable={true}
|
||||||
|
isMulti={false}
|
||||||
|
placeholder=""
|
||||||
|
name="sub-module"
|
||||||
|
options={parentList}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-3 mt-5">
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
isDisabled={
|
||||||
|
findSelectedLevel(selectedGroup)?.level === 3 && !selectedParent
|
||||||
}
|
}
|
||||||
});
|
>
|
||||||
}
|
Simpan
|
||||||
|
</Button>
|
||||||
function successSubmit(redirect: string) {
|
<Link href="/admin/master-user-level">
|
||||||
MySwal.fire({
|
<Button color="danger">Kembali</Button>
|
||||||
title: 'Sukses',
|
</Link>
|
||||||
icon: 'success',
|
</div>
|
||||||
confirmButtonColor: '#3085d6',
|
</div>
|
||||||
confirmButtonText: 'OK',
|
</form>
|
||||||
}).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="Nama"
|
|
||||||
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="Alias Name"
|
|
||||||
id="aliasName"
|
|
||||||
{...register("aliasName")}
|
|
||||||
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.aliasName?.message && (
|
|
||||||
<p className="text-red-400 text-sm">
|
|
||||||
{errors.aliasName?.message}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="mt-3 ">
|
|
||||||
<p className="text-black text-sm mb-1 font-semibold">Level Number</p>
|
|
||||||
<Select
|
|
||||||
variant="bordered"
|
|
||||||
labelPlacement="outside"
|
|
||||||
placeholder="Select Polda"
|
|
||||||
selectedKeys={levelValue}
|
|
||||||
onSelectionChange={setLevelValue}
|
|
||||||
className="w-full"
|
|
||||||
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"],
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectSection showDivider title="List Level">
|
|
||||||
{LevelList.map((list: any) => (
|
|
||||||
<SelectItem key={list.id} value={list.id}>
|
|
||||||
{list.label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectSection>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
{/* <div className="mt-3 ">
|
|
||||||
<p className="text-black text-sm mb-1 font-semibold">Parent LevelId</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="mt-3 ">
|
|
||||||
<p className="text-black text-sm mb-1 font-semibold">Provinsi</p>
|
|
||||||
<Select
|
|
||||||
variant="bordered"
|
|
||||||
selectionMode="single"
|
|
||||||
labelPlacement="outside"
|
|
||||||
placeholder="Select"
|
|
||||||
className="font-semibold"
|
|
||||||
items={provinceList}
|
|
||||||
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="Provinsi">
|
|
||||||
{provinceList.map((list) => (
|
|
||||||
<SelectItem key={list.id} value={list.id}>
|
|
||||||
{list.label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectSection>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div className="text-black">
|
|
||||||
<p className=" text-black ">Status</p>
|
|
||||||
<RadioGroup
|
|
||||||
orientation="horizontal"
|
|
||||||
id="radio-banned"
|
|
||||||
className="text-gray-950 mb-2"
|
|
||||||
onChange={handleActive}
|
|
||||||
defaultValue={active}
|
|
||||||
>
|
|
||||||
<Radio
|
|
||||||
classNames={{
|
|
||||||
label: "!text-black",
|
|
||||||
}}
|
|
||||||
value="true"
|
|
||||||
>
|
|
||||||
Active
|
|
||||||
</Radio>
|
|
||||||
<Radio
|
|
||||||
classNames={{
|
|
||||||
label: "!text-black",
|
|
||||||
}}
|
|
||||||
value="false"
|
|
||||||
>
|
|
||||||
Inactive
|
|
||||||
</Radio>
|
|
||||||
</RadioGroup>
|
|
||||||
</div> */}
|
|
||||||
<div className="flex flex-row gap-3 my-3">
|
|
||||||
<Link href="/admin/master/master-user-level">
|
|
||||||
<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 >
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,26 @@ export const MasterRoleIcon = ({
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
export const MasterUserLevelIcon = ({
|
||||||
|
size,
|
||||||
|
height = 24,
|
||||||
|
width = 24,
|
||||||
|
fill = "currentColor",
|
||||||
|
...props
|
||||||
|
}: IconSvgProps) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width={size || width}
|
||||||
|
height={size || height}
|
||||||
|
viewBox="0 0 640 512"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M192 256c61.9 0 112-50.1 112-112S253.9 32 192 32S80 82.1 80 144s50.1 112 112 112m76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C51.6 288 0 339.6 0 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2M480 256c53 0 96-43 96-96s-43-96-96-96s-96 43-96 96s43 96 96 96m48 32h-3.8c-13.9 4.8-28.6 8-44.2 8s-30.3-3.2-44.2-8H432c-20.4 0-39.2 5.9-55.7 15.4c24.4 26.3 39.7 61.2 39.7 99.8v38.4c0 2.2-.5 4.3-.6 6.4H592c26.5 0 48-21.5 48-48c0-61.9-50.1-112-112-112"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
export const MasterCategoryIcon = ({
|
export const MasterCategoryIcon = ({
|
||||||
size,
|
size,
|
||||||
height = 24,
|
height = 24,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
MagazineIcon,
|
MagazineIcon,
|
||||||
MasterCategoryIcon,
|
MasterCategoryIcon,
|
||||||
MasterRoleIcon,
|
MasterRoleIcon,
|
||||||
|
MasterUserLevelIcon,
|
||||||
MasterUsersIcon,
|
MasterUsersIcon,
|
||||||
MinusCircleIcon,
|
MinusCircleIcon,
|
||||||
StaticPageIcon,
|
StaticPageIcon,
|
||||||
|
|
@ -243,6 +244,20 @@ const sideBarDummyData = [
|
||||||
statusName: "Active",
|
statusName: "Active",
|
||||||
childModule: null,
|
childModule: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 23,
|
||||||
|
name: "Master User Level",
|
||||||
|
moduleId: 656,
|
||||||
|
moduleName: "Form Validation",
|
||||||
|
modulePathUrl: "/admin/user-level",
|
||||||
|
parentId: -1,
|
||||||
|
icon: <MasterUserLevelIcon />,
|
||||||
|
position: 1,
|
||||||
|
statusId: 1,
|
||||||
|
childMenu: [],
|
||||||
|
statusName: "Active",
|
||||||
|
childModule: null,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const SidebarMobile: React.FC<SidebarProps> = ({ updateSidebarData }) => {
|
const SidebarMobile: React.FC<SidebarProps> = ({ updateSidebarData }) => {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
MagazineIcon,
|
MagazineIcon,
|
||||||
MasterCategoryIcon,
|
MasterCategoryIcon,
|
||||||
MasterRoleIcon,
|
MasterRoleIcon,
|
||||||
|
MasterUserLevelIcon,
|
||||||
MasterUsersIcon,
|
MasterUsersIcon,
|
||||||
MinusCircleIcon,
|
MinusCircleIcon,
|
||||||
StaticPageIcon,
|
StaticPageIcon,
|
||||||
|
|
@ -319,6 +320,20 @@ const sideBarDummyData = [
|
||||||
statusName: "Active",
|
statusName: "Active",
|
||||||
childModule: null,
|
childModule: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 23,
|
||||||
|
name: "Master User Level",
|
||||||
|
moduleId: 656,
|
||||||
|
moduleName: "Form Validation",
|
||||||
|
modulePathUrl: "/admin/user-level",
|
||||||
|
parentId: -1,
|
||||||
|
icon: <MasterUserLevelIcon />,
|
||||||
|
position: 1,
|
||||||
|
statusId: 1,
|
||||||
|
childMenu: [],
|
||||||
|
statusName: "Active",
|
||||||
|
childModule: null,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const Sidebar: React.FC<SidebarProps> = ({ updateSidebarData }) => {
|
const Sidebar: React.FC<SidebarProps> = ({ updateSidebarData }) => {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import {
|
||||||
} from "@/components/icons";
|
} from "@/components/icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { getAllUserLevels } from "@/services/user-levels/user-levels-service";
|
import { getAllUserLevels } from "@/services/user-levels/user-levels-service";
|
||||||
|
import { close, loading } from "@/config/swal";
|
||||||
|
|
||||||
type UserObject = {
|
type UserObject = {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -41,12 +42,6 @@ type UserObject = {
|
||||||
status: string;
|
status: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusColorMap = {
|
|
||||||
active: "success",
|
|
||||||
paused: "danger",
|
|
||||||
vacation: "warning",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function MasterUserLevelTable() {
|
export default function MasterUserLevelTable() {
|
||||||
const [totalPage, setTotalPage] = useState(1);
|
const [totalPage, setTotalPage] = useState(1);
|
||||||
const [masterUserLevelTable, setmasterUserLevel] = useState<UserObject[]>([]);
|
const [masterUserLevelTable, setmasterUserLevel] = useState<UserObject[]>([]);
|
||||||
|
|
@ -56,11 +51,11 @@ export default function MasterUserLevelTable() {
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
{ name: "Name", uid: "name" },
|
{ name: "Name", uid: "name" },
|
||||||
{ name: "User Name", uid: "alias_name" },
|
{ name: "User Name", uid: "aliasName" },
|
||||||
{ name: "Level Number", uid: "level_number" },
|
{ name: "Level Number", uid: "levelNumber" },
|
||||||
{ name: "Parent Level", uid: "parent_level_id" },
|
{ name: "Parent", uid: "parentLevelId" },
|
||||||
{ name: "Province", uid: "province_id" },
|
// { name: "Province", uid: "province_id" },
|
||||||
{ name: "Status", uid: "is_active" },
|
// { name: "Status", uid: "is_active" },
|
||||||
{ name: "Action", uid: "actions" },
|
{ name: "Action", uid: "actions" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -71,6 +66,7 @@ export default function MasterUserLevelTable() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
|
loading();
|
||||||
const request = {
|
const request = {
|
||||||
page: page,
|
page: page,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
|
@ -78,10 +74,11 @@ export default function MasterUserLevelTable() {
|
||||||
const res = await getAllUserLevels(request);
|
const res = await getAllUserLevels(request);
|
||||||
const data = res?.data?.data;
|
const data = res?.data?.data;
|
||||||
setTotalPage(Math.ceil(res?.data?.total / 10));
|
setTotalPage(Math.ceil(res?.data?.total / 10));
|
||||||
initUserData(10, data);
|
await initUserData(10, data);
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initUserData(limit: number, data?: any) {
|
async function initUserData(limit: number, data?: any) {
|
||||||
if (data) {
|
if (data) {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
const startIndex = limit * (page - 1);
|
const startIndex = limit * (page - 1);
|
||||||
|
|
@ -91,43 +88,34 @@ export default function MasterUserLevelTable() {
|
||||||
value.no = startIndex + iterate;
|
value.no = startIndex + iterate;
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
console.log("Data ::", newData);
|
|
||||||
setmasterUserLevel(newData);
|
setmasterUserLevel(newData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findParentName = (data: string | number) => {
|
||||||
|
let name = "-";
|
||||||
|
|
||||||
|
for (let i = 9; i < masterUserLevelTable?.length; i++) {
|
||||||
|
const temp = masterUserLevelTable[i];
|
||||||
|
if (temp.id === Number(data)) {
|
||||||
|
name = temp.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
const renderCell = useCallback(
|
const renderCell = useCallback(
|
||||||
(masterUserLevel: TableRow, columnKey: Key) => {
|
(masterUserLevel: TableRow, columnKey: Key) => {
|
||||||
const cellValue = masterUserLevel[columnKey as keyof UserObject];
|
const cellValue = masterUserLevel[columnKey as keyof UserObject];
|
||||||
const statusColorMap: Record<string, ChipProps["color"]> = {
|
|
||||||
active: "success",
|
|
||||||
cancel: "danger",
|
|
||||||
pending: "warning",
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
case "no":
|
case "no":
|
||||||
return <div>{masterUserLevel.id}</div>;
|
return <div>{masterUserLevel.id}</div>;
|
||||||
|
|
||||||
case "name":
|
case "parentLevelId":
|
||||||
return <div className="w-[150px]">{masterUserLevel.name}</div>;
|
return <p className="text-black">{findParentName(cellValue)}</p>;
|
||||||
|
|
||||||
case "alias_Name":
|
|
||||||
return <div className="">{masterUserLevel.aliasName}</div>;
|
|
||||||
case "is_active":
|
|
||||||
return (
|
|
||||||
<Chip
|
|
||||||
className="capitalize "
|
|
||||||
color={statusColorMap[masterUserLevel.status]}
|
|
||||||
size="lg"
|
|
||||||
variant="flat"
|
|
||||||
>
|
|
||||||
<div className="flex flex-row items-center gap-2 justify-center">
|
|
||||||
{cellValue}
|
|
||||||
</div>
|
|
||||||
</Chip>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "actions":
|
case "actions":
|
||||||
return (
|
return (
|
||||||
<div className="relative flex justify-star items-center gap-2">
|
<div className="relative flex justify-star items-center gap-2">
|
||||||
|
|
@ -138,14 +126,14 @@ export default function MasterUserLevelTable() {
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownItem key="Detail">
|
{/* <DropdownItem key="Detail">
|
||||||
<Link href={`/admin/magazine/detail`}>
|
<Link 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 key="Edit">
|
<DropdownItem key="Edit">
|
||||||
<Link href={`#`}>
|
<Link href={`/admin/user-level/edit/${masterUserLevel.id}`}>
|
||||||
<CreateIconIon className="inline mr-2 mb-1" />
|
<CreateIconIon className="inline mr-2 mb-1" />
|
||||||
Edit
|
Edit
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -169,18 +157,18 @@ export default function MasterUserLevelTable() {
|
||||||
return cellValue;
|
return cellValue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[masterUserLevelTable]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mx-3 my-5">
|
<div className="mx-3 my-5">
|
||||||
<Link href="/admin/master/master-user-level/create">
|
{/* <Link href="/admin/master/master-user-level/create">
|
||||||
<Button className="my-3 bg-blue-600 text-white">
|
<Button className="my-3 bg-blue-600 text-white">
|
||||||
<CreateIconIon />
|
<CreateIconIon />
|
||||||
Create New User Level
|
Create New User Level
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link> */}
|
||||||
<div className="flex flex-col items-center rounded-2xl">
|
<div className="flex flex-col items-center rounded-2xl">
|
||||||
<Table
|
<Table
|
||||||
// selectionMode="multiple"
|
// selectionMode="multiple"
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
import { httpGet, httpPost } from "../http-config/http-base-services";
|
import {
|
||||||
|
httpDeleteInterceptor,
|
||||||
|
httpGet,
|
||||||
|
httpPost,
|
||||||
|
httpPut,
|
||||||
|
} from "@/service/http-config/axios-base-service";
|
||||||
|
|
||||||
export async function getAllUserLevels(data: any) {
|
export async function getAllUserLevels(data: any) {
|
||||||
const headers = {
|
const headers = {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpGet(`user-levels`, headers,);
|
return await httpGet(`user-levels?limit=${data.limit || ""}`, headers);
|
||||||
|
}
|
||||||
|
export async function getUserLevels(id: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGet(`user-levels/${id}`, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAccountById(id: string) {
|
export async function getAccountById(id: string) {
|
||||||
|
|
@ -14,7 +23,6 @@ export async function getAccountById(id: string) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpGet(`user-account/findById/${id}`, headers);
|
return await httpGet(`user-account/findById/${id}`, headers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createUserLevels(request: any) {
|
export async function createUserLevels(request: any) {
|
||||||
|
|
@ -24,3 +32,9 @@ export async function createUserLevels(request: any) {
|
||||||
return await httpPost(`user-levels`, headers, request);
|
return await httpPost(`user-levels`, headers, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function editUserLevels(id: string, request: any) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPut(`user-levels/${id}`, headers, request);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue