2024-04-21 16:20:06 +00:00
|
|
|
"use client";
|
|
|
|
|
import {
|
2025-02-13 04:53:53 +00:00
|
|
|
TableCell,
|
|
|
|
|
TableRow,
|
|
|
|
|
Table,
|
|
|
|
|
TableHeader,
|
|
|
|
|
TableColumn,
|
|
|
|
|
TableBody,
|
|
|
|
|
Pagination,
|
|
|
|
|
Dropdown,
|
|
|
|
|
DropdownTrigger,
|
|
|
|
|
DropdownMenu,
|
|
|
|
|
DropdownItem,
|
|
|
|
|
Input,
|
|
|
|
|
User,
|
|
|
|
|
Card,
|
|
|
|
|
Divider,
|
|
|
|
|
Chip,
|
|
|
|
|
ChipProps,
|
2025-03-06 10:40:54 +00:00
|
|
|
Checkbox,
|
2025-04-16 08:51:12 +00:00
|
|
|
Switch,
|
2025-02-13 08:25:39 +00:00
|
|
|
} from "@heroui/react";
|
|
|
|
|
import { Button } from "@heroui/button";
|
2024-04-23 05:17:21 +00:00
|
|
|
import React, { Key, useCallback, useEffect, useMemo, useState } from "react";
|
2024-04-21 16:20:06 +00:00
|
|
|
import {
|
2025-02-13 04:53:53 +00:00
|
|
|
AddIcon,
|
|
|
|
|
CreateIconIon,
|
|
|
|
|
DeleteIcon,
|
|
|
|
|
DotsYIcon,
|
|
|
|
|
EyeFilledIcon,
|
|
|
|
|
EyeIconMdi,
|
2025-03-03 02:58:33 +00:00
|
|
|
SearchIcon,
|
2024-04-21 16:20:06 +00:00
|
|
|
} from "@/components/icons";
|
|
|
|
|
import Link from "next/link";
|
2025-04-16 08:51:12 +00:00
|
|
|
import {
|
|
|
|
|
changeIsApproval,
|
|
|
|
|
getAllUserLevels,
|
|
|
|
|
} from "@/services/user-levels/user-levels-service";
|
|
|
|
|
import { close, error, loading } from "@/config/swal";
|
2025-03-06 10:40:54 +00:00
|
|
|
import { stringify } from "querystring";
|
2025-05-28 06:56:41 +00:00
|
|
|
import { getUnixTimestamp } from "@/utils/global";
|
2024-04-21 16:20:06 +00:00
|
|
|
|
|
|
|
|
type UserObject = {
|
2025-02-13 04:53:53 +00:00
|
|
|
id: number;
|
|
|
|
|
name: string;
|
|
|
|
|
levelNumber: string;
|
|
|
|
|
aliasName: string;
|
|
|
|
|
parentLevelId: string;
|
|
|
|
|
provinceId: string;
|
|
|
|
|
status: string;
|
2025-04-16 08:51:12 +00:00
|
|
|
isApprovalActive: boolean;
|
2024-04-21 16:20:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function MasterUserLevelTable() {
|
2025-02-13 04:53:53 +00:00
|
|
|
const [totalPage, setTotalPage] = useState(1);
|
2025-03-06 10:40:54 +00:00
|
|
|
const [masterUserLevelTable, setMasterUserLevel] = useState<UserObject[]>([]);
|
2025-03-03 02:58:33 +00:00
|
|
|
const [search, setSearch] = useState("");
|
2025-03-06 10:40:54 +00:00
|
|
|
const [doSetup, setDoSetup] = useState(false);
|
|
|
|
|
const [userLevelAll, setUserLevelAll] = useState<UserObject[]>([]);
|
|
|
|
|
const [selectAllLevel, setSelectAllLevel] = useState(false);
|
|
|
|
|
const [selectedLevel, setSelectedLevel] = useState<string[]>([]);
|
2025-04-16 08:51:12 +00:00
|
|
|
const [isSelected, setIsSelected] = useState(true);
|
2025-02-13 04:53:53 +00:00
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
{ name: "No", uid: "no" },
|
|
|
|
|
{ name: "Name", uid: "name" },
|
2025-02-18 05:17:41 +00:00
|
|
|
{ name: "User Name", uid: "aliasName" },
|
|
|
|
|
{ name: "Level Number", uid: "levelNumber" },
|
|
|
|
|
{ name: "Parent", uid: "parentLevelId" },
|
2025-03-06 10:40:54 +00:00
|
|
|
{ name: "Action", uid: "actions" },
|
|
|
|
|
];
|
|
|
|
|
const columns2 = [
|
|
|
|
|
{ name: "No", uid: "no" },
|
|
|
|
|
{ name: "Setup", uid: "setup" },
|
|
|
|
|
{ name: "Name", uid: "name" },
|
|
|
|
|
{ name: "User Name", uid: "aliasName" },
|
|
|
|
|
{ name: "Level Number", uid: "levelNumber" },
|
|
|
|
|
{ name: "Parent", uid: "parentLevelId" },
|
2025-04-16 08:51:12 +00:00
|
|
|
{ name: "Need Approval", uid: "approvalActive" },
|
2025-02-13 04:53:53 +00:00
|
|
|
{ name: "Action", uid: "actions" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const [page, setPage] = useState(1);
|
|
|
|
|
|
2025-04-16 08:51:12 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
console.log("level", selectedLevel);
|
|
|
|
|
}, [selectedLevel]);
|
|
|
|
|
|
2025-02-13 04:53:53 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
fetchData();
|
2025-03-06 10:40:54 +00:00
|
|
|
}, [page, selectedLevel]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
fetchDataAll();
|
|
|
|
|
}, []);
|
2025-02-13 04:53:53 +00:00
|
|
|
|
|
|
|
|
async function fetchData() {
|
2025-02-18 05:17:41 +00:00
|
|
|
loading();
|
2025-02-13 04:53:53 +00:00
|
|
|
const request = {
|
|
|
|
|
page: page,
|
|
|
|
|
limit: 10,
|
2025-03-03 02:58:33 +00:00
|
|
|
search: search,
|
2025-05-28 06:56:41 +00:00
|
|
|
timeStamp: getUnixTimestamp(),
|
2025-02-13 04:53:53 +00:00
|
|
|
};
|
|
|
|
|
const res = await getAllUserLevels(request);
|
|
|
|
|
const data = res?.data?.data;
|
2025-04-16 08:51:12 +00:00
|
|
|
setTotalPage(Math.ceil(res?.data?.meta?.totalPage));
|
2025-02-18 05:17:41 +00:00
|
|
|
await initUserData(10, data);
|
|
|
|
|
close();
|
2025-02-13 04:53:53 +00:00
|
|
|
}
|
2025-03-06 10:40:54 +00:00
|
|
|
async function fetchDataAll() {
|
|
|
|
|
loading();
|
|
|
|
|
const request = {
|
|
|
|
|
page: 1,
|
|
|
|
|
limit: -1,
|
|
|
|
|
search: "",
|
2025-05-28 06:56:41 +00:00
|
|
|
timeStamp: getUnixTimestamp(),
|
2025-03-06 10:40:54 +00:00
|
|
|
};
|
|
|
|
|
const res = await getAllUserLevels(request);
|
|
|
|
|
const data = res?.data?.data;
|
|
|
|
|
setUserLevelAll(data);
|
2025-03-07 09:08:19 +00:00
|
|
|
const temp = [];
|
|
|
|
|
for (const element of data) {
|
|
|
|
|
if (element.isApprovalActive) {
|
|
|
|
|
temp.push(String(element.id));
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-16 08:51:12 +00:00
|
|
|
// setSelectedLevel(temp);
|
2025-03-06 10:40:54 +00:00
|
|
|
close();
|
|
|
|
|
}
|
2025-02-13 04:53:53 +00:00
|
|
|
|
2025-02-18 05:17:41 +00:00
|
|
|
async function initUserData(limit: number, data?: any) {
|
2025-02-13 04:53:53 +00:00
|
|
|
if (data) {
|
|
|
|
|
console.log(data);
|
|
|
|
|
const startIndex = limit * (page - 1);
|
|
|
|
|
let iterate = 0;
|
|
|
|
|
const newData = data.map((value: any) => {
|
|
|
|
|
iterate++;
|
|
|
|
|
value.no = startIndex + iterate;
|
|
|
|
|
return value;
|
|
|
|
|
});
|
2025-03-06 10:40:54 +00:00
|
|
|
setMasterUserLevel(newData);
|
2024-04-23 05:17:21 +00:00
|
|
|
}
|
2025-02-13 04:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-03 02:58:33 +00:00
|
|
|
let typingTimer: NodeJS.Timeout;
|
|
|
|
|
const doneTypingInterval = 1500;
|
|
|
|
|
|
|
|
|
|
const handleKeyUp = () => {
|
|
|
|
|
clearTimeout(typingTimer);
|
|
|
|
|
typingTimer = setTimeout(doneTyping, doneTypingInterval);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleKeyDown = () => {
|
|
|
|
|
clearTimeout(typingTimer);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async function doneTyping() {
|
|
|
|
|
fetchData();
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-06 10:40:54 +00:00
|
|
|
const doMapping = (status: boolean) => {
|
|
|
|
|
setSelectAllLevel(status);
|
|
|
|
|
if (status) {
|
|
|
|
|
const temp = [];
|
|
|
|
|
for (const element of userLevelAll) {
|
|
|
|
|
temp.push(String(element.id));
|
|
|
|
|
}
|
|
|
|
|
setSelectedLevel(temp);
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedLevel([]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSelectedLevel = (id: string, checked: boolean) => {
|
|
|
|
|
console.log("change", id, checked);
|
|
|
|
|
const temp = [...selectedLevel];
|
|
|
|
|
if (checked) {
|
|
|
|
|
temp.push(id);
|
|
|
|
|
setSelectedLevel(temp);
|
|
|
|
|
if (temp.length === userLevelAll.length) {
|
|
|
|
|
setSelectAllLevel(true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const newTemp = temp.filter((a) => a !== id);
|
|
|
|
|
setSelectedLevel(newTemp);
|
|
|
|
|
if (newTemp.length !== userLevelAll.length) {
|
|
|
|
|
setSelectAllLevel(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-13 04:53:53 +00:00
|
|
|
const renderCell = useCallback(
|
2025-03-06 10:40:54 +00:00
|
|
|
(masterUserLevel: UserObject, columnKey: Key) => {
|
|
|
|
|
const findParentName = (data: string | number) => {
|
|
|
|
|
let name = "-";
|
2025-02-13 04:53:53 +00:00
|
|
|
|
2025-03-06 10:40:54 +00:00
|
|
|
for (let i = 9; i < userLevelAll?.length; i++) {
|
|
|
|
|
const temp = userLevelAll[i];
|
|
|
|
|
if (temp.id === Number(data)) {
|
|
|
|
|
name = temp.name;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const cellValue = masterUserLevel[columnKey as keyof UserObject];
|
2025-02-13 04:53:53 +00:00
|
|
|
switch (columnKey) {
|
2025-02-18 05:17:41 +00:00
|
|
|
case "parentLevelId":
|
2025-04-16 08:51:12 +00:00
|
|
|
return (
|
|
|
|
|
<p className="text-black">
|
|
|
|
|
{findParentName(masterUserLevel.parentLevelId)}
|
|
|
|
|
</p>
|
|
|
|
|
);
|
2025-03-06 10:40:54 +00:00
|
|
|
|
|
|
|
|
case "setup":
|
|
|
|
|
return (
|
|
|
|
|
<Checkbox
|
|
|
|
|
key={masterUserLevel.id}
|
|
|
|
|
isSelected={selectedLevel?.includes(String(masterUserLevel.id))}
|
|
|
|
|
onValueChange={(e) =>
|
|
|
|
|
handleSelectedLevel(String(masterUserLevel.id), e)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
);
|
2025-04-16 08:51:12 +00:00
|
|
|
case "approvalActive":
|
|
|
|
|
return (
|
|
|
|
|
<p className="text-black">
|
|
|
|
|
{masterUserLevel.isApprovalActive ? "Yes" : "No"}
|
|
|
|
|
</p>
|
|
|
|
|
);
|
2025-02-13 04:53:53 +00:00
|
|
|
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>
|
2025-02-18 05:17:41 +00:00
|
|
|
{/* <DropdownItem key="Detail">
|
2025-02-13 04:53:53 +00:00
|
|
|
<Link href={`/admin/magazine/detail`}>
|
|
|
|
|
<EyeIconMdi className="inline mr-2 mb-1" />
|
|
|
|
|
Detail
|
|
|
|
|
</Link>
|
2025-02-18 05:17:41 +00:00
|
|
|
</DropdownItem> */}
|
2025-02-13 04:53:53 +00:00
|
|
|
<DropdownItem key="Edit">
|
2025-02-18 05:17:41 +00:00
|
|
|
<Link href={`/admin/user-level/edit/${masterUserLevel.id}`}>
|
2025-02-13 04:53:53 +00:00
|
|
|
<CreateIconIon className="inline mr-2 mb-1" />
|
|
|
|
|
Edit
|
|
|
|
|
</Link>
|
|
|
|
|
</DropdownItem>
|
|
|
|
|
<DropdownItem key="Delete">
|
|
|
|
|
<Link href={`#`}>
|
|
|
|
|
<DeleteIcon
|
|
|
|
|
width={20}
|
|
|
|
|
height={16}
|
|
|
|
|
className="inline mr-2 mb-1"
|
|
|
|
|
/>
|
|
|
|
|
Delete
|
|
|
|
|
</Link>
|
|
|
|
|
</DropdownItem>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
</Dropdown>
|
2024-04-21 16:20:06 +00:00
|
|
|
</div>
|
2025-02-13 04:53:53 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return cellValue;
|
|
|
|
|
}
|
|
|
|
|
},
|
2025-03-06 10:40:54 +00:00
|
|
|
[selectedLevel, userLevelAll, masterUserLevelTable]
|
2025-02-13 04:53:53 +00:00
|
|
|
);
|
|
|
|
|
|
2025-04-16 08:51:12 +00:00
|
|
|
const saveApproval = async () => {
|
|
|
|
|
const req = { ids: selectedLevel.join(","), isApprovalActive: isSelected };
|
|
|
|
|
const res = await changeIsApproval(req);
|
|
|
|
|
if (res?.error) {
|
|
|
|
|
error(res?.message);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
fetchData();
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-13 04:53:53 +00:00
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className="mx-3 my-5">
|
2025-03-06 10:40:54 +00:00
|
|
|
<div className="flex flex-col items-start rounded-2xl">
|
2025-03-07 09:08:19 +00:00
|
|
|
<div className="flex flex-row gap-3 mb-3 w-full justify-start items-end">
|
|
|
|
|
<div className="flex flex-col gap-1 w-auto justify-start">
|
2025-03-06 10:40:54 +00:00
|
|
|
<p className="font-semibold text-sm">Pencarian</p>
|
|
|
|
|
<Input
|
|
|
|
|
aria-label="Search"
|
|
|
|
|
classNames={{
|
|
|
|
|
inputWrapper: "bg-default-100",
|
|
|
|
|
input: "text-sm",
|
|
|
|
|
}}
|
2025-03-07 09:08:19 +00:00
|
|
|
className="w-[300px]"
|
2025-03-06 10:40:54 +00:00
|
|
|
labelPlacement="outside"
|
|
|
|
|
startContent={
|
|
|
|
|
<SearchIcon className="text-base text-default-400 pointer-events-none flex-shrink-0" />
|
|
|
|
|
}
|
|
|
|
|
type="text"
|
|
|
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
|
|
|
onKeyUp={handleKeyUp}
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2025-03-07 09:08:19 +00:00
|
|
|
<Button
|
|
|
|
|
color="primary"
|
|
|
|
|
onPress={() => setDoSetup(!doSetup)}
|
|
|
|
|
className="px-2"
|
|
|
|
|
>
|
|
|
|
|
Settings Approval
|
2025-03-06 10:40:54 +00:00
|
|
|
</Button>
|
|
|
|
|
{doSetup && (
|
2025-04-16 08:51:12 +00:00
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
Need Approval?
|
|
|
|
|
<Switch isSelected={isSelected} onValueChange={setIsSelected} />
|
|
|
|
|
{isSelected ? "Yes" : "No"}
|
|
|
|
|
<Button
|
|
|
|
|
color="success"
|
|
|
|
|
className="text-white"
|
|
|
|
|
onPress={saveApproval}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-03-06 10:40:54 +00:00
|
|
|
)}
|
2025-03-03 02:58:33 +00:00
|
|
|
</div>
|
2025-03-06 10:40:54 +00:00
|
|
|
|
2025-02-13 04:53:53 +00:00
|
|
|
<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 ",
|
|
|
|
|
}}
|
|
|
|
|
>
|
2025-03-06 10:40:54 +00:00
|
|
|
<TableHeader columns={doSetup ? columns2 : columns}>
|
2025-02-13 04:53:53 +00:00
|
|
|
{(column) => (
|
2025-03-06 10:40:54 +00:00
|
|
|
<TableColumn key={column.uid}>
|
|
|
|
|
{column.uid === "setup" ? (
|
|
|
|
|
<Checkbox
|
|
|
|
|
isSelected={selectAllLevel}
|
|
|
|
|
onValueChange={(e) => {
|
|
|
|
|
doMapping(e);
|
|
|
|
|
}}
|
|
|
|
|
></Checkbox>
|
|
|
|
|
) : (
|
|
|
|
|
column.name
|
|
|
|
|
)}
|
|
|
|
|
</TableColumn>
|
2025-02-13 04:53:53 +00:00
|
|
|
)}
|
|
|
|
|
</TableHeader>
|
|
|
|
|
<TableBody
|
|
|
|
|
items={masterUserLevelTable}
|
|
|
|
|
emptyContent={"No data to display."}
|
|
|
|
|
>
|
|
|
|
|
{(item) => (
|
|
|
|
|
<TableRow key={item.id}>
|
|
|
|
|
{(columnKey) => (
|
|
|
|
|
<TableCell>{renderCell(item, columnKey)}</TableCell>
|
|
|
|
|
)}
|
|
|
|
|
</TableRow>
|
|
|
|
|
)}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
2025-03-06 10:40:54 +00:00
|
|
|
<div className="mt-2 justify-center flex w-full">
|
2025-02-13 04:53:53 +00:00
|
|
|
<Pagination
|
|
|
|
|
isCompact
|
|
|
|
|
showControls
|
|
|
|
|
showShadow
|
|
|
|
|
color="primary"
|
|
|
|
|
classNames={{
|
|
|
|
|
base: "bg-transparent",
|
|
|
|
|
wrapper: "bg-transparent",
|
2025-05-31 14:52:58 +00:00
|
|
|
item: "w-fit px-3",
|
|
|
|
|
cursor: "w-fit px-3",
|
2025-02-13 04:53:53 +00:00
|
|
|
}}
|
|
|
|
|
page={page}
|
|
|
|
|
total={totalPage}
|
|
|
|
|
onChange={(page) => setPage(page)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
);
|
2024-04-21 16:20:06 +00:00
|
|
|
}
|