187 lines
5.3 KiB
TypeScript
187 lines
5.3 KiB
TypeScript
import { isDefined } from 'twenty-shared/utils';
|
|
|
|
import { navigationMenuItemsDraftState } from '@/navigation-menu-item/states/navigationMenuItemsDraftState';
|
|
import { getPositionBetween } from '@/navigation-menu-item/utils/getPositionBetween';
|
|
import { isNavigationMenuItemFolder } from '@/navigation-menu-item/utils/isNavigationMenuItemFolder';
|
|
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
|
|
|
import { useWorkspaceSectionItems } from './useWorkspaceSectionItems';
|
|
|
|
export const useNavigationMenuItemMoveRemove = () => {
|
|
const setNavigationMenuItemsDraft = useSetAtomState(
|
|
navigationMenuItemsDraftState,
|
|
);
|
|
const items = useWorkspaceSectionItems();
|
|
const visibleItemIds = new Set(items.map((item) => item.id));
|
|
|
|
const moveUp = (navigationMenuItemId: string) => {
|
|
setNavigationMenuItemsDraft((draft) => {
|
|
if (!draft) {
|
|
return draft;
|
|
}
|
|
|
|
const currentItem = draft.find(
|
|
(item) => item.id === navigationMenuItemId,
|
|
);
|
|
if (!currentItem) {
|
|
return draft;
|
|
}
|
|
|
|
const folderId = currentItem.folderId ?? null;
|
|
const siblings = draft
|
|
.filter(
|
|
(item) =>
|
|
(item.folderId ?? null) === folderId && visibleItemIds.has(item.id),
|
|
)
|
|
.sort((a, b) => a.position - b.position);
|
|
|
|
const currentIndex = siblings.findIndex(
|
|
(item) => item.id === navigationMenuItemId,
|
|
);
|
|
if (currentIndex <= 0) {
|
|
return draft;
|
|
}
|
|
|
|
const prev = siblings[currentIndex - 1];
|
|
const prevPrev = siblings[currentIndex - 2];
|
|
const newPosition = getPositionBetween(prevPrev?.position, prev.position);
|
|
|
|
return draft.map((item) =>
|
|
item.id === navigationMenuItemId
|
|
? { ...item, position: newPosition }
|
|
: item,
|
|
);
|
|
});
|
|
};
|
|
|
|
const moveDown = (navigationMenuItemId: string) => {
|
|
setNavigationMenuItemsDraft((draft) => {
|
|
if (!draft) {
|
|
return draft;
|
|
}
|
|
|
|
const currentItem = draft.find(
|
|
(item) => item.id === navigationMenuItemId,
|
|
);
|
|
if (!currentItem) {
|
|
return draft;
|
|
}
|
|
|
|
const folderId = currentItem.folderId ?? null;
|
|
const siblings = draft
|
|
.filter(
|
|
(item) =>
|
|
(item.folderId ?? null) === folderId && visibleItemIds.has(item.id),
|
|
)
|
|
.sort((a, b) => a.position - b.position);
|
|
|
|
const currentIndex = siblings.findIndex(
|
|
(item) => item.id === navigationMenuItemId,
|
|
);
|
|
if (currentIndex < 0 || currentIndex >= siblings.length - 1) {
|
|
return draft;
|
|
}
|
|
|
|
const next = siblings[currentIndex + 1];
|
|
const nextNext = siblings[currentIndex + 2];
|
|
const newPosition = getPositionBetween(next.position, nextNext?.position);
|
|
|
|
return draft.map((item) =>
|
|
item.id === navigationMenuItemId
|
|
? { ...item, position: newPosition }
|
|
: item,
|
|
);
|
|
});
|
|
};
|
|
|
|
const remove = (navigationMenuItemId: string) => {
|
|
setNavigationMenuItemsDraft((draft) => {
|
|
if (!draft) {
|
|
return draft;
|
|
}
|
|
|
|
const itemToRemove = draft.find(
|
|
(item) => item.id === navigationMenuItemId,
|
|
);
|
|
if (!itemToRemove) {
|
|
return draft;
|
|
}
|
|
|
|
const isFolder = isNavigationMenuItemFolder(itemToRemove);
|
|
|
|
if (isFolder) {
|
|
return draft.filter(
|
|
(item) =>
|
|
item.id !== navigationMenuItemId &&
|
|
item.folderId !== navigationMenuItemId,
|
|
);
|
|
}
|
|
|
|
return draft.filter((item) => item.id !== navigationMenuItemId);
|
|
});
|
|
};
|
|
|
|
const moveToFolder = (
|
|
navigationMenuItemId: string,
|
|
targetFolderId: string | null,
|
|
) => {
|
|
setNavigationMenuItemsDraft((draft) => {
|
|
if (!draft) {
|
|
return draft;
|
|
}
|
|
|
|
const itemToMove = draft.find((item) => item.id === navigationMenuItemId);
|
|
if (!itemToMove) {
|
|
return draft;
|
|
}
|
|
|
|
const isFolder = isNavigationMenuItemFolder(itemToMove);
|
|
if (isFolder && targetFolderId === navigationMenuItemId) {
|
|
return draft;
|
|
}
|
|
|
|
if (isFolder && isDefined(targetFolderId)) {
|
|
const descendantFolderIds = new Set<string>();
|
|
const collectDescendants = (folderId: string) => {
|
|
draft
|
|
?.filter(
|
|
(item) =>
|
|
isNavigationMenuItemFolder(item) && item.folderId === folderId,
|
|
)
|
|
.forEach((item) => {
|
|
descendantFolderIds.add(item.id);
|
|
collectDescendants(item.id);
|
|
});
|
|
};
|
|
collectDescendants(navigationMenuItemId);
|
|
if (descendantFolderIds.has(targetFolderId)) {
|
|
return draft;
|
|
}
|
|
}
|
|
|
|
const itemsInTargetFolder = draft.filter((item) =>
|
|
targetFolderId === null
|
|
? !isDefined(item.folderId)
|
|
: item.folderId === targetFolderId,
|
|
);
|
|
const maxPositionInTarget =
|
|
itemsInTargetFolder.length > 0
|
|
? Math.max(...itemsInTargetFolder.map((item) => item.position))
|
|
: -1;
|
|
const newPosition = maxPositionInTarget + 1;
|
|
|
|
return draft.map((item) =>
|
|
item.id === navigationMenuItemId
|
|
? {
|
|
...item,
|
|
folderId: targetFolderId ?? undefined,
|
|
position: newPosition,
|
|
}
|
|
: item,
|
|
);
|
|
});
|
|
};
|
|
|
|
return { moveUp, moveDown, remove, moveToFolder };
|
|
};
|