From c5bd84cca916f58e24022b8dd00d87729968ec5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Myran?= Date: Tue, 24 Jun 2025 13:57:42 +0200 Subject: [PATCH 1/4] Add functionality to hide pages with no visible components on repeating group with multiPage --- .../RepeatingGroupEditContext.tsx | 51 +++++++++++++++---- src/layout/RepeatingGroup/utils.ts | 18 +++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/layout/RepeatingGroup/EditContainer/RepeatingGroupEditContext.tsx b/src/layout/RepeatingGroup/EditContainer/RepeatingGroupEditContext.tsx index 0b59845965..97112d3a8a 100644 --- a/src/layout/RepeatingGroup/EditContainer/RepeatingGroupEditContext.tsx +++ b/src/layout/RepeatingGroup/EditContainer/RepeatingGroupEditContext.tsx @@ -7,6 +7,7 @@ import { useRepeatingGroup } from 'src/layout/RepeatingGroup/Providers/Repeating import { RepGroupHooks } from 'src/layout/RepeatingGroup/utils'; import { LayoutNode } from 'src/utils/layout/LayoutNode'; import { LayoutPage } from 'src/utils/layout/LayoutPage'; +import { isHidden, NodesInternal } from 'src/utils/layout/NodesContext'; import { useNodeItem } from 'src/utils/layout/useNodeItem'; interface RepeatingGroupEditRowContext { @@ -26,26 +27,58 @@ const { Provider, useCtx } = createContext({ function useRepeatingGroupEditRowState( node: LayoutNode<'RepeatingGroup'>, ): RepeatingGroupEditRowContext & { setMultiPageIndex: (index: number) => void } { - const edit = useNodeItem(node, (i) => i.edit); - const lastPage = RepGroupHooks.useLastMultiPageIndex(node) ?? 0; + const edit = useNodeItem(node, (item) => item.edit); const multiPageEnabled = edit?.multiPage ?? false; - const [multiPageIndex, setMultiPageIndex] = useState(0); + + const children = RepGroupHooks.useChildIdsWithMultiPage(node); + + const hiddenState = NodesInternal.useMemoSelector((state) => + children.map(({ id, multiPageIndex }) => ({ + nodeId: id, + page: multiPageIndex, + hidden: isHidden(state, 'node', id), + })), + ); + + const visiblePages = [...new Set(hiddenState.filter(({ hidden }) => !hidden).map(({ page }) => page ?? 0))]; + const firstVisiblePage = Math.min(...visiblePages); + const lastVisiblePage = Math.max(...visiblePages); + + const [multiPageIndex, setMultiPageIndex] = useState(firstVisiblePage); + + const findNextVisiblePage = useCallback( + (start: number, step: number): number | undefined => { + for (let page = start; step > 0 ? page <= lastVisiblePage : page >= firstVisiblePage; page += step) { + if (hiddenState.some((state) => state.page === page && !state.hidden)) { + return page; + } + } + return undefined; + }, + [firstVisiblePage, hiddenState, lastVisiblePage], + ); const nextMultiPage = useCallback(() => { - setMultiPageIndex((prev) => Math.min(prev + 1, lastPage)); - }, [lastPage]); + const nextPage = findNextVisiblePage(multiPageIndex + 1, 1); + if (nextPage !== undefined) { + setMultiPageIndex(nextPage); + } + }, [findNextVisiblePage, multiPageIndex]); const prevMultiPage = useCallback(() => { - setMultiPageIndex((prev) => Math.max(prev - 1, 0)); - }, []); + const prevPage = findNextVisiblePage(multiPageIndex - 1, -1); + if (prevPage !== undefined) { + setMultiPageIndex(prevPage); + } + }, [findNextVisiblePage, multiPageIndex]); return { multiPageEnabled, multiPageIndex, nextMultiPage, prevMultiPage, - hasNextMultiPage: multiPageEnabled && multiPageIndex < lastPage, - hasPrevMultiPage: multiPageEnabled && multiPageIndex > 0, + hasNextMultiPage: multiPageEnabled && multiPageIndex < lastVisiblePage, + hasPrevMultiPage: multiPageEnabled && multiPageIndex > firstVisiblePage, setMultiPageIndex, }; } diff --git a/src/layout/RepeatingGroup/utils.ts b/src/layout/RepeatingGroup/utils.ts index 3739639282..38c9a2d6b8 100644 --- a/src/layout/RepeatingGroup/utils.ts +++ b/src/layout/RepeatingGroup/utils.ts @@ -207,4 +207,22 @@ export const RepGroupHooks = { return childIds; }, + + useChildIdsWithMultiPage( + node: LayoutNode<'RepeatingGroup'> | undefined, + ): { id: string; multiPageIndex: number | undefined }[] { + const component = useLayoutLookups().getComponent(node?.baseId, 'RepeatingGroup'); + const idMutator = useComponentIdMutator(); + if (!component?.edit?.multiPage) { + return component?.children.map(idMutator).map((id) => ({ id, multiPageIndex: undefined })) ?? []; + } + + const children: { id: string; multiPageIndex: number | undefined }[] = []; + for (const id of component.children) { + const [multiPageIndex, baseId] = id.split(':', 2); + children.push({ id: idMutator(baseId), multiPageIndex: parseInt(multiPageIndex) }); + } + + return children; + }, }; From 08be597c41985e413268254461c4c3280cfb9cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Myran?= Date: Fri, 27 Jun 2025 09:56:59 +0200 Subject: [PATCH 2/4] Add support for text resources for navigation_multipage_next_button and navigation_multipage_back_button --- .../RepeatingGroupsEditContainer.tsx | 16 ++++++++++++---- src/layout/RepeatingGroup/config.ts | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/layout/RepeatingGroup/EditContainer/RepeatingGroupsEditContainer.tsx b/src/layout/RepeatingGroup/EditContainer/RepeatingGroupsEditContainer.tsx index 24d4ddd676..42a38c340b 100644 --- a/src/layout/RepeatingGroup/EditContainer/RepeatingGroupsEditContainer.tsx +++ b/src/layout/RepeatingGroup/EditContainer/RepeatingGroupsEditContainer.tsx @@ -175,7 +175,7 @@ function RepeatingGroupsEditContainerInternal({ {hasPrevMultiPage && ( )} {hasNextMultiPage && ( )} @@ -200,11 +196,7 @@ function RepeatingGroupsEditContainerInternal({ color='second' onClick={() => nextMultiPage()} > - +