173 lines
4.5 KiB
TypeScript
173 lines
4.5 KiB
TypeScript
import type { DropOptions, NodeModel } from "@minoru/react-dnd-treeview";
|
|
import type {
|
|
TreeUserOrganization,
|
|
TreeUser,
|
|
} from "@/entities/user-organization";
|
|
import type { TreeMenu, TreeNode } from "../model/tree-menu-interface";
|
|
|
|
export const generateMenuTreeData = (
|
|
data: TreeMenu[],
|
|
): NodeModel<TreeMenu>[] => {
|
|
return data.reduce<NodeModel<TreeMenu>[]>((acc, menu) => {
|
|
const node: NodeModel<TreeMenu> = {
|
|
id: menu.menuCd ?? 0,
|
|
parent: menu.parentId ?? 0,
|
|
text: menu.menuKornNm,
|
|
droppable: true,
|
|
data: menu,
|
|
};
|
|
|
|
acc.push(node);
|
|
|
|
if (menu.children?.length) {
|
|
acc.push(...generateMenuTreeData(menu.children));
|
|
}
|
|
|
|
return acc;
|
|
}, []);
|
|
};
|
|
|
|
export const generateNewMenuTreeData = (
|
|
treeData: NodeModel<TreeMenu>[],
|
|
options: DropOptions<TreeMenu>,
|
|
): TreeNode | null => {
|
|
const { dragSourceId, dragSource, dropTargetId, dropTarget } = options;
|
|
|
|
if (!dragSource?.data) return null;
|
|
|
|
const siblings = treeData.filter((node) => node.parent === dropTargetId);
|
|
|
|
const dragSourceIndex = siblings.findIndex(
|
|
(node) => node.id === dragSourceId,
|
|
);
|
|
|
|
const prevSibling = siblings[dragSourceIndex - 1];
|
|
|
|
const newSortSeq =
|
|
dragSourceIndex === 0 ? 1 : (prevSibling?.data?.sortSeq ?? 0) + 1;
|
|
|
|
const childNodes = treeData.filter(
|
|
(node) => node.parent === dragSourceId && node.data,
|
|
);
|
|
|
|
const baseNode = (node: NodeModel<TreeMenu>): TreeNode => {
|
|
if (!node.data) return {};
|
|
return {
|
|
menuCd: node.data?.menuCd,
|
|
name: node.data?.menuKornNm,
|
|
icon: node.data?.iconNm,
|
|
};
|
|
};
|
|
|
|
const treeNode: TreeNode = {
|
|
...baseNode(dragSource),
|
|
parentId: dropTargetId === 0 ? null : (dropTargetId as number),
|
|
sortSeq: newSortSeq,
|
|
levelNo: (dropTarget?.data?.levelNo ?? 0) + 1,
|
|
};
|
|
|
|
const result: TreeNode = {
|
|
...treeNode,
|
|
children: childNodes.map((child) => ({
|
|
...baseNode(child),
|
|
parentId: child.data?.parentId === 0 ? null : (dropTargetId as number),
|
|
sortSeq: child.data?.sortSeq,
|
|
levelNo: (treeNode?.levelNo ?? 0) + 1,
|
|
})),
|
|
};
|
|
|
|
return result;
|
|
};
|
|
|
|
export const handleSelectNode =
|
|
(callback: (node: NodeModel<TreeMenu>) => void) =>
|
|
(node: NodeModel<TreeMenu>) => {
|
|
callback(node);
|
|
};
|
|
|
|
export const handleDropNode =
|
|
(callback: (newTree: TreeNode) => void) =>
|
|
(newTree: NodeModel<TreeMenu>[], options: DropOptions<TreeMenu>) => {
|
|
const newTreeData = generateNewMenuTreeData(newTree, options);
|
|
if (!newTreeData) return;
|
|
callback(newTreeData);
|
|
};
|
|
|
|
export const handleNodeTextChange =
|
|
(treeData: NodeModel<TreeMenu>[]) =>
|
|
(callback: (newTree: NodeModel<TreeMenu>[]) => void) =>
|
|
(id: NodeModel["id"], value: string) => {
|
|
const newTree = treeData.map((node) => {
|
|
if (node.id === id) {
|
|
return {
|
|
...node,
|
|
text: value,
|
|
};
|
|
}
|
|
|
|
return node;
|
|
});
|
|
callback(newTree);
|
|
};
|
|
|
|
export const generateUserOrganizationTreeData = (
|
|
organizations: TreeUserOrganization[],
|
|
): NodeModel<TreeUserOrganization | TreeUser>[] => {
|
|
return organizations.reduce<NodeModel<TreeUserOrganization | TreeUser>[]>(
|
|
(acc, org) => {
|
|
const orgNode: NodeModel<TreeUserOrganization> = {
|
|
id: org.ognzSn,
|
|
parent: org.upOgnzSn ?? 0,
|
|
text: org.ognzNm,
|
|
data: org,
|
|
droppable: false,
|
|
};
|
|
|
|
acc.push(orgNode);
|
|
|
|
if (org.children?.length) {
|
|
acc.push(...generateUserOrganizationTreeData(org.children));
|
|
}
|
|
|
|
if (org.users?.length) {
|
|
acc.push(
|
|
...org.users.map((user) => ({
|
|
id: user.userUnqId,
|
|
parent: org.ognzSn,
|
|
text: user.userNm,
|
|
data: user,
|
|
droppable: false,
|
|
})),
|
|
);
|
|
}
|
|
|
|
return acc;
|
|
},
|
|
[],
|
|
);
|
|
};
|
|
|
|
export const filterUserOrganizationTreeDataByKeyword = (
|
|
treeData: NodeModel<TreeUserOrganization | TreeUser>[],
|
|
keyword: string,
|
|
): NodeModel<TreeUserOrganization | TreeUser>[] => {
|
|
return Array.from(
|
|
treeData.reduce((matchedNodes, node) => {
|
|
if (node.data && "ognzSn" in node.data) return matchedNodes; // 조직 노드는 필터링 제외
|
|
if (!node.text.includes(keyword)) return matchedNodes;
|
|
|
|
matchedNodes.add(node);
|
|
|
|
let parentId = node.parent;
|
|
while (parentId) {
|
|
const parentNode = treeData.find((n) => n.id === parentId);
|
|
if (!parentNode) break;
|
|
matchedNodes.add(parentNode);
|
|
parentId = parentNode.parent;
|
|
}
|
|
|
|
return matchedNodes;
|
|
}, new Set<NodeModel<TreeUserOrganization | TreeUser>>()),
|
|
);
|
|
};
|