176e81cd76
Fixes: #19152 ## Summary goBackFromSidePanel returned early without writing the new (empty) stack to the store, leaving stale navigation state. And it caused openRecordInSidePanel to think the record was already open and skip reopening. <img width="587" height="405" alt="image" src="https://github.com/user-attachments/assets/eb36f4c6-43ca-4c08-891a-c592ff673837" /> ## Before https://github.com/user-attachments/assets/03d1e24a-6d1e-4efc-93c1-72be0bc31a89 ## After When close the side panel with Escape, now it can be opened by clicking arrow button again. https://github.com/user-attachments/assets/ae700d41-4f81-4d1a-af9a-f97f31f489a6 --------- Co-authored-by: Devessier <baptiste@devessier.fr>
178 lines
5.7 KiB
TypeScript
178 lines
5.7 KiB
TypeScript
import { useCallback } from 'react';
|
|
|
|
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
|
import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState';
|
|
import { sidePanelNavigationMorphItemsByPageState } from '@/side-panel/states/sidePanelNavigationMorphItemsByPageState';
|
|
import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState';
|
|
import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState';
|
|
import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState';
|
|
import { sidePanelSubPageStackComponentState } from '@/side-panel/states/sidePanelSubPageStackComponentState';
|
|
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
|
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
|
import { isNonEmptyArray } from '@sniptt/guards';
|
|
import { useStore } from 'jotai';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
|
|
export const useSidePanelHistory = () => {
|
|
const store = useStore();
|
|
const { closeSidePanelMenu } = useSidePanelMenu();
|
|
|
|
const cleanupCurrentPage = useCallback(() => {
|
|
const currentNavigationStack = store.get(
|
|
sidePanelNavigationStackState.atom,
|
|
);
|
|
|
|
const currentMorphItems = store.get(
|
|
sidePanelNavigationMorphItemsByPageState.atom,
|
|
);
|
|
|
|
if (currentNavigationStack.length > 0) {
|
|
const removedItem = currentNavigationStack.at(-1);
|
|
|
|
if (isDefined(removedItem)) {
|
|
const newMorphItems = new Map(currentMorphItems);
|
|
newMorphItems.delete(removedItem.pageId);
|
|
store.set(sidePanelNavigationMorphItemsByPageState.atom, newMorphItems);
|
|
|
|
store.set(
|
|
sidePanelSubPageStackComponentState.atomFamily({
|
|
instanceId: removedItem.pageId,
|
|
}),
|
|
[],
|
|
);
|
|
|
|
const morphItems = currentMorphItems.get(removedItem.pageId);
|
|
if (isNonEmptyArray(morphItems)) {
|
|
store.set(
|
|
activeTabIdComponentState.atomFamily({
|
|
instanceId: getShowPageTabListComponentId({
|
|
pageId: removedItem.pageId,
|
|
targetObjectId: morphItems[0].recordId,
|
|
}),
|
|
}),
|
|
null,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}, [store]);
|
|
|
|
const goBackFromSidePanel = useCallback(() => {
|
|
cleanupCurrentPage();
|
|
|
|
const currentNavigationStack = store.get(
|
|
sidePanelNavigationStackState.atom,
|
|
);
|
|
|
|
const newNavigationStack = currentNavigationStack.slice(0, -1);
|
|
const lastNavigationStackItem = newNavigationStack.at(-1);
|
|
|
|
store.set(sidePanelNavigationStackState.atom, newNavigationStack);
|
|
|
|
if (!isDefined(lastNavigationStackItem)) {
|
|
closeSidePanelMenu();
|
|
return;
|
|
}
|
|
|
|
store.set(sidePanelPageState.atom, lastNavigationStackItem.page);
|
|
|
|
store.set(sidePanelPageInfoState.atom, {
|
|
title: lastNavigationStackItem.pageTitle,
|
|
Icon: lastNavigationStackItem.pageIcon,
|
|
instanceId: lastNavigationStackItem.pageId,
|
|
});
|
|
|
|
store.set(hasUserSelectedSidePanelListItemState.atom, false);
|
|
}, [cleanupCurrentPage, closeSidePanelMenu, store]);
|
|
|
|
const goBackOneSubPageOrMainPage = useCallback(() => {
|
|
const currentPageInfo = store.get(sidePanelPageInfoState.atom);
|
|
|
|
const subPageStack = store.get(
|
|
sidePanelSubPageStackComponentState.atomFamily({
|
|
instanceId: currentPageInfo.instanceId,
|
|
}),
|
|
);
|
|
|
|
if (isNonEmptyArray(subPageStack)) {
|
|
store.set(
|
|
sidePanelSubPageStackComponentState.atomFamily({
|
|
instanceId: currentPageInfo.instanceId,
|
|
}),
|
|
subPageStack.slice(0, -1),
|
|
);
|
|
return;
|
|
}
|
|
|
|
goBackFromSidePanel();
|
|
}, [goBackFromSidePanel, store]);
|
|
|
|
const navigateSidePanelHistory = useCallback(
|
|
(pageIndex: number) => {
|
|
const currentNavigationStack = store.get(
|
|
sidePanelNavigationStackState.atom,
|
|
);
|
|
|
|
const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1);
|
|
|
|
store.set(sidePanelNavigationStackState.atom, newNavigationStack);
|
|
|
|
const newNavigationStackItem = newNavigationStack.at(-1);
|
|
|
|
if (!isDefined(newNavigationStackItem)) {
|
|
throw new Error(
|
|
`No side panel navigation stack item found for index ${pageIndex}`,
|
|
);
|
|
}
|
|
|
|
store.set(sidePanelPageState.atom, newNavigationStackItem.page);
|
|
store.set(sidePanelPageInfoState.atom, {
|
|
title: newNavigationStackItem.pageTitle,
|
|
Icon: newNavigationStackItem.pageIcon,
|
|
instanceId: newNavigationStackItem.pageId,
|
|
});
|
|
const currentMorphItems = store.get(
|
|
sidePanelNavigationMorphItemsByPageState.atom,
|
|
);
|
|
|
|
for (const [pageId, morphItems] of currentMorphItems.entries()) {
|
|
if (!newNavigationStack.some((item) => item.pageId === pageId)) {
|
|
store.set(
|
|
sidePanelSubPageStackComponentState.atomFamily({
|
|
instanceId: pageId,
|
|
}),
|
|
[],
|
|
);
|
|
|
|
store.set(
|
|
activeTabIdComponentState.atomFamily({
|
|
instanceId: getShowPageTabListComponentId({
|
|
pageId,
|
|
targetObjectId: morphItems[0].recordId,
|
|
}),
|
|
}),
|
|
null,
|
|
);
|
|
}
|
|
}
|
|
|
|
const newMorphItems = new Map(
|
|
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
|
newNavigationStack.some((item) => item.pageId === pageId),
|
|
),
|
|
);
|
|
|
|
store.set(sidePanelNavigationMorphItemsByPageState.atom, newMorphItems);
|
|
|
|
store.set(hasUserSelectedSidePanelListItemState.atom, false);
|
|
},
|
|
[store],
|
|
);
|
|
|
|
return {
|
|
goBackFromSidePanel,
|
|
goBackOneSubPageOrMainPage,
|
|
navigateSidePanelHistory,
|
|
};
|
|
};
|