Skip to content

Commit

Permalink
progress on saving entity
Browse files Browse the repository at this point in the history
  • Loading branch information
Kluskey committed Oct 8, 2024
1 parent 402df2a commit 0f5937d
Showing 1 changed file with 80 additions and 35 deletions.
115 changes: 80 additions & 35 deletions mirror-2/components/entity-tree/entity-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,69 @@ import { TwoWayInput } from '@/components/two-way-input';
import { z } from 'zod';
import { PlusCircle } from 'lucide-react';

type Entity = Database['public']['Tables']['entities']['Row'];
type EntityWithPopulatedChildren = Omit<Entity, 'children'> & {
key: string,
title: string,
icon?: any,
children: EntityWithPopulatedChildren[]; // children now contain an array of Entity objects
};

type TreeDataNodeWithEntityData = TreeDataNode & { name: string, id: string }

function transformDbEntityStructureWithPopulatedChildren(entities: Entity[]): TreeDataNodeWithEntityData[] {
const entityMap = new Map<string, EntityWithPopulatedChildren & { childIds: string[] }>();
const assignedChildIds = new Set<string>(); // Track all child IDs to remove from the main array
function transformDbEntityStructureWithPopulatedChildren(entities) {
const entityMap = new Map();
const assignedChildIds = new Set();

// Create a map for easy lookup of entities by ID, and keep the original children as string IDs
entities.forEach((entity) => {
const entityWithChildren: EntityWithPopulatedChildren & { childIds: string[] } = {
// Step 1: Populate the map with entities and their child IDs
entities.forEach(entity => {
const entityWithChildren = {
...entity,
children: [], // Initialize as an empty array for the populated children
children: [], // Will hold actual child objects
key: entity.id,
title: entity.name,
childIds: entity.children ? (entity.children as string[]) : [] // Temporarily store child IDs
childIds: Array.isArray(entity.children) ? [...entity.children] : [] // Clone to avoid mutation
};
entityMap.set(entity.id, entityWithChildren);
});

// Now replace childIds with the actual EntityWithPopulatedChildren objects
entityMap.forEach((entityWithChildren) => {
if (entityWithChildren.childIds.length > 0) {
entityWithChildren.children = entityWithChildren.childIds.map((childId) => {
const childEntity = entityMap.get(childId)!;
assignedChildIds.add(childId); // Mark this ID as assigned to a parent
return childEntity; // Get the actual child entity
});
// Step 2: Assign children to their respective parents, preventing duplication
entityMap.forEach(entity => {
if (entity.childIds.length > 0) {
entity.children = entity.childIds
.filter(childId => {
if (assignedChildIds.has(childId)) {
console.warn(`Child with ID ${childId} is already assigned to another parent. Skipping assignment to parent ID ${entity.id}.`);
return false; // Exclude to prevent duplication
}
return true; // Include this child
})
.map(childId => {
assignedChildIds.add(childId); // Mark as assigned
const childEntity = entityMap.get(childId);
if (!childEntity) {
console.warn(`Child entity with ID ${childId} not found.`);
return null;
}
return childEntity;
})
.filter(child => child !== null); // Remove any nulls
}
});

// Filter out entities that were assigned as children (remove duplicates)
// Step 3: Identify root entities (those not assigned as children and marked as root)
const rootEntities = Array.from(entityMap.values()).filter(
(entity) => !assignedChildIds.has(entity.id) // Keep only the root-level entities
entity => !assignedChildIds.has(entity.id) && entity.is_root
);

// Return the filtered entities without the temporary `childIds` field
return rootEntities.map(({ childIds, ...entity }) => entity);
// Step 4: Clean up temporary fields recursively
function cleanEntity(entity) {
const { childIds, ...rest } = entity;
if (rest.children.length > 0) {
rest.children = rest.children.map(child => cleanEntity(child));
}
return rest;
}

const cleanedRootEntities = rootEntities.map(cleanEntity);

return cleanedRootEntities;
}


const EntityTree: React.FC = () => {
const [treeData, setTreeData] = useState<any>([]);

Expand All @@ -84,6 +101,7 @@ const EntityTree: React.FC = () => {
useEffect(() => {
if (entities && entities.length > 0) {
const data = transformDbEntityStructureWithPopulatedChildren(entities)
// debugger
setTreeData(data)
// updateState({ entities, type: 'set-tree', itemId: '' });
}
Expand All @@ -100,10 +118,7 @@ const EntityTree: React.FC = () => {
const dragKey = info.dragNode.key;
const dropPos = info.node.pos.split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // the drop position relative to the drop node, inside 0, top -1, bottom 1

// for updating db


let dragParent: any = null;

const loop = (
data: TreeDataNode[],
Expand All @@ -119,17 +134,40 @@ const EntityTree: React.FC = () => {
}
}
};


// Function to find the parent of the drag node
const findParentNode = (data, childKey: React.Key) => {
for (let i = 0; i < data.length; i++) {
if (data && data[i] && data[i].children) {
const children = data[i].children
const hasChild = children?.some(child => child.key === childKey);
if (hasChild) {
dragParent = data[i]; // Found the parent node
return; // Exit once found
}
findParentNode(children, childKey);
}
}
};

// Find the parent of the dragged node
findParentNode(treeData, dragKey); // `treeData` is your current tree structure

console.log('Parent of dragged node:', dragParent);

const data = [...treeData];

// Find dragObject
let dragObj: TreeDataNode;
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragParent.children = arr
dragObj = item;
});

if (!info.dropToGap) {
console.log('content drop', data)
console.log('content drop to new parent', data)
// Drop on the content
loop(data, dropKey, (item) => {
item.children = item.children || [];
Expand All @@ -140,13 +178,16 @@ const EntityTree: React.FC = () => {
// update the node and dragnode in DB
if (info.node && info.node['id'] && info.node.children) {
const childIds = info.node.children.map(child => child['id'])
// debugger
updateEntity({ id: info.node['id'], updateData: { children: childIds } })
}
if (info.dragNode && info.dragNode['id'] && info.dragNode.children) {
const childIds = info.dragNode.children.map(child => child['id'])
updateEntity({ id: info.dragNode['id'], updateData: { children: info.dragNode.children } })
// debugger
updateEntity({ id: info.dragNode['id'], updateData: { children: childIds } })
}


} else {
console.log('gap drop', data)

Expand All @@ -163,18 +204,22 @@ const EntityTree: React.FC = () => {
// Drop on the bottom of the drop node
ar.splice(i! + 1, 0, dragObj!);
}
debugger
// debugger // not yet
// update the node and dragnode in DB
if (info.node && info.node['id'] && info.node.children) {
const childIds = info.node.children.map(child => child['id'])
updateEntity({ id: info.node['id'], updateData: { children: childIds } })
}
if (info.dragNode && info.dragNode['id'] && info.dragNode.children) {
const childIds = info.dragNode.children.map(child => child['id'])
updateEntity({ id: info.dragNode['id'], updateData: { children: info.dragNode.children } })
updateEntity({ id: info.dragNode['id'], updateData: { children: childIds } })
}
}

// update the dragParent to remove the child from its children array
const childIds = dragParent.children.map(child => child['id'])
updateEntity({ id: dragParent.id, updateData: { children: childIds } })

setTreeData(data);

};
Expand Down

0 comments on commit 0f5937d

Please sign in to comment.