Files
homarr/apps/nextjs/src/components/board/sections/section-actions.tsx
T

111 lines
3.3 KiB
TypeScript

import { useCallback } from "react";
import { useCurrentLayout } from "@homarr/boards/context";
import { useUpdateBoard } from "@homarr/boards/updater";
import type { Board } from "~/app/[locale]/boards/_types";
interface MoveAndResizeInnerSection {
innerSectionId: string;
xOffset: number;
yOffset: number;
width: number;
height: number;
}
interface MoveInnerSectionToSection {
innerSectionId: string;
sectionId: string;
xOffset: number;
yOffset: number;
width: number;
height: number;
}
export const useSectionActions = () => {
const { updateBoard } = useUpdateBoard();
const currentLayoutId = useCurrentLayout();
const moveAndResizeInnerSection = useCallback(
({ innerSectionId, ...positionProps }: MoveAndResizeInnerSection) => {
updateBoard((previous) => ({
...previous,
sections: previous.sections.map((section) => {
// Return same section if section is not the one we're moving
if (section.id !== innerSectionId) return section;
if (section.kind !== "container") return section;
return {
...section,
layouts: section.layouts.map((layout) => {
if (layout.layoutId !== currentLayoutId) return layout;
return {
...layout,
...positionProps,
};
}),
};
}),
}));
},
[currentLayoutId, updateBoard],
);
const moveInnerSectionToSection = useCallback(
({ innerSectionId, sectionId, ...positionProps }: MoveInnerSectionToSection) => {
updateBoard((previous) => {
if (wouldCreateSectionCycle(previous, { innerSectionId, sectionId, layoutId: currentLayoutId })) {
return previous;
}
return {
...previous,
sections: previous.sections.map((section) => {
// Return section without changes when not the section we're moving
if (section.id !== innerSectionId) return section;
if (section.kind !== "container") return section;
return {
...section,
layouts: section.layouts.map((layout) => {
if (layout.layoutId !== currentLayoutId) return layout;
return {
...layout,
...positionProps,
parentSectionId: sectionId,
};
}),
};
}),
};
});
},
[currentLayoutId, updateBoard],
);
return {
moveAndResizeInnerSection,
moveInnerSectionToSection,
};
};
export const wouldCreateSectionCycle = (
board: Board,
{ innerSectionId, sectionId, layoutId }: { innerSectionId: string; sectionId: string; layoutId: string },
) => {
const visitedSectionIds = new Set<string>();
let currentSectionId: string | null = sectionId;
while (currentSectionId) {
if (currentSectionId === innerSectionId) return true;
if (visitedSectionIds.has(currentSectionId)) return true;
visitedSectionIds.add(currentSectionId);
const currentSection = board.sections.find((section) => section.id === currentSectionId);
if (currentSection?.kind !== "container") return false;
currentSectionId = currentSection.layouts.find((layout) => layout.layoutId === layoutId)?.parentSectionId ?? null;
}
return false;
};