feat: 조직도 트리 dnd 작업

This commit is contained in:
2025-04-21 20:19:50 +09:00
parent e99fc06181
commit 5d942f735e
6 changed files with 63 additions and 8 deletions
+1 -1
View File
@@ -4,4 +4,4 @@ export {
type OrganizationTree,
type OrganizationFormData,
} from "./model/organization-interface";
export { generateOrganizationTreeData } from "./lib/utils";
export { generateOrganizationTreeData, handleDropNode } from "./lib/utils";
+55 -1
View File
@@ -1,4 +1,4 @@
import type { NodeModel } from "@minoru/react-dnd-treeview";
import type { DropOptions, NodeModel } from "@minoru/react-dnd-treeview";
import type { OrganizationTree } from "../model/organization-interface";
export const generateOrganizationTreeData = (
@@ -21,3 +21,57 @@ export const generateOrganizationTreeData = (
return acc;
}, []);
};
export const generateNewOrganizationTreeData = (
treeData: NodeModel<OrganizationTree>[],
options: DropOptions<OrganizationTree>,
): OrganizationTree | null => {
const { dragSourceId, dragSource, dropTargetId } = 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 treeNode: OrganizationTree = {
...dragSource.data,
upOgnzSn: dropTargetId === 0 ? null : (dropTargetId as number),
sortSeq: newSortSeq,
};
const result: OrganizationTree = {
...treeNode,
children:
childNodes?.map((child) => ({
...child.data,
ognzNm: child.data?.ognzNm ?? "",
upOgnzSn: child.data?.upOgnzSn === 0 ? null : (dragSourceId as number),
sortSeq: child.data?.sortSeq ?? 1,
})) ?? [],
};
return result;
};
export const handleDropNode =
(callback: (newTree: OrganizationTree) => void) =>
(
newTree: NodeModel<OrganizationTree>[],
options: DropOptions<OrganizationTree>,
) => {
const newTreeData = generateNewOrganizationTreeData(newTree, options);
if (!newTreeData) return;
callback(newTreeData);
};
@@ -16,7 +16,7 @@ export const organizationFormSchema = organizationSchema.omit({
export type Organization = z.infer<typeof organizationSchema>;
export type OrganizationFormData = z.infer<typeof organizationFormSchema>;
export type OrganizationTree = Organization & {
children: OrganizationTree[];
children?: OrganizationTree[];
};
export interface OrganizationService {
@@ -10,8 +10,9 @@ import { Button } from "@common/components/ui";
import { DndTree, EditableNode } from "@/widgets/dnd-tree";
import {
OrganizationApi,
generateOrganizationTreeData,
organizationFormSchema,
generateOrganizationTreeData,
handleDropNode,
type OrganizationFormData,
type OrganizationTree,
} from "@/entities/organization";
@@ -198,7 +199,7 @@ function OrganizationPage() {
/>
)}
handleSelectNode={handleNodeSelect}
handleDropNode={() => {}}
handleDropNode={handleDropNode(console.log)}
updateNodeName={async (id, name) => {
await updateOrganizationName({ ognzSn: id as number, name });
}}
@@ -5,7 +5,7 @@ import { cn } from "@common/components/lib";
import { EditableNode } from "./editable-node";
interface TreeData extends Record<string, unknown> {
children: unknown[];
children?: unknown[];
}
type CustomNodeProps<T extends TreeData> = {
@@ -72,7 +72,7 @@ function CustomNode<T extends TreeData>({
) : (
<>
<div className="flex items-center" onClick={handleSelect}>
{data && data.children.length > 0 && (
{data && data.children && data.children.length > 0 && (
<i
className={cn(
"diveicon di-arrow-forward mr-2 text-base text-label",
+1 -1
View File
@@ -15,7 +15,7 @@ import { cn } from "@common/components/lib";
import { CustomNode } from "./custom-node";
interface TreeData extends Record<string, unknown> {
children: unknown[];
children?: unknown[];
}
type EditableNodeProps = { depth: number };