Skip to content

Commit ff7567d

Browse files
authored
refactor: remove ugly hack in sidebar actions (#3060)
Replaces the hack by passing `sidebarAction` directly to `navigateTo`, so the sidebar Action param is set atomically with the navigation.
1 parent 70191bf commit ff7567d

7 files changed

Lines changed: 34 additions & 54 deletions

File tree

src/hooks.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ export function useStateWithUrlSearchParam<Type>(
143143
// initializing URLSearchParams.
144144
const location = useLocation();
145145
const locationRef = useRef(location);
146+
// Keep locationRef in sync with the current location so that setters
147+
// always build on top of the latest URL (e.g. after a navigate() call).
148+
locationRef.current = location;
146149
const [searchParams, setSearchParams] = useSearchParams();
147150
const paramValues = searchParams.getAll(paramName);
148151

src/library-authoring/components/ComponentMenu.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
import { useRemoveItemsFromCollection } from '@src/library-authoring/data/apiHooks';
2222
import containerMessages from '@src/library-authoring/containers/messages';
2323
import { useLibraryRoutes } from '@src/library-authoring/routes';
24-
import { useRunOnNextRender } from '@src/utils';
2524
import { canEditComponent } from './ComponentEditorModal';
2625
import ComponentDeleter from './ComponentDeleter';
2726
import ComponentRemover from './ComponentRemover';
@@ -45,10 +44,9 @@ export const ComponentMenu = ({ usageKey, index }: Props) => {
4544
const {
4645
sidebarItemInfo,
4746
closeLibrarySidebar,
48-
setSidebarAction,
4947
openItemSidebar,
5048
} = useSidebarContext();
51-
const { insideCollection } = useLibraryRoutes();
49+
const { insideCollection, navigateTo } = useLibraryRoutes();
5250

5351
const canEdit = usageKey && canEditComponent(usageKey);
5452
const { showToast } = useContext(ToastContext);
@@ -79,19 +77,11 @@ export const ComponentMenu = ({ usageKey, index }: Props) => {
7977
openComponentEditor?.(usageKey);
8078
}, [usageKey, openItemSidebar, openComponentEditor]);
8179

82-
const scheduleJumpToCollection = useRunOnNextRender(() => {
83-
// TODO: Ugly hack to make sure sidebar shows add to collection section
84-
// This needs to run after all changes to url takes place to avoid conflicts.
85-
setTimeout(() => setSidebarAction(SidebarActions.JumpToManageCollections), 250);
86-
});
87-
8880
const showManageCollections = useCallback(() => {
89-
openItemSidebar(usageKey, SidebarBodyItemId.ComponentInfo);
90-
scheduleJumpToCollection();
81+
navigateTo({ selectedItemId: usageKey, sidebarAction: SidebarActions.JumpToManageCollections });
9182
}, [
92-
scheduleJumpToCollection,
9383
usageKey,
94-
openItemSidebar,
84+
navigateTo,
9585
]);
9686

9787
const containerType = containerId ? getBlockType(containerId) : 'collection';
@@ -143,7 +133,7 @@ export const ComponentMenu = ({ usageKey, index }: Props) => {
143133
</Dropdown.Item>
144134
)}
145135
</Dropdown.Menu>
146-
{isDeleteModalOpen && (
136+
{isDeleteModalOpen && /* istanbul ignore next */ (
147137
<ComponentDeleter
148138
usageKey={usageKey}
149139
close={closeDeleteModal}

src/library-authoring/containers/ContainerCard.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { useClipboard } from '@src/generic/clipboard';
1515
import { getBlockType } from '@src/generic/key-utils';
1616
import { type ContainerHit, Highlight, PublishStatus } from '@src/search-manager';
1717
import { ToastContext } from '@src/generic/toast-context';
18-
import { useRunOnNextRender } from '@src/utils';
1918

2019
import { useComponentPickerContext } from '@src/library-authoring/common/context/ComponentPickerContext';
2120
import { useOptionalLibraryContext } from '@src/library-authoring/common/context/LibraryContext';
@@ -50,7 +49,6 @@ export const ContainerMenu = ({ containerKey, displayName, index }: ContainerMen
5049
const {
5150
sidebarItemInfo,
5251
closeLibrarySidebar,
53-
setSidebarAction,
5452
} = useSidebarContext();
5553
const { copyToClipboard } = useClipboard();
5654

@@ -73,7 +71,7 @@ export const ContainerMenu = ({ containerKey, displayName, index }: ContainerMen
7371
closeLibrarySidebar();
7472
}
7573
showToast(intl.formatMessage(messages.removeComponentFromCollectionSuccess));
76-
}).catch(() => {
74+
}).catch(/* istanbul ignore next */ () => {
7775
showToast(intl.formatMessage(messages.removeComponentFromCollectionFailure));
7876
});
7977
};
@@ -86,16 +84,9 @@ export const ContainerMenu = ({ containerKey, displayName, index }: ContainerMen
8684
}
8785
};
8886

89-
const scheduleJumpToCollection = useRunOnNextRender(() => {
90-
// TODO: Ugly hack to make sure sidebar shows add to collection section
91-
// This needs to run after all changes to url takes place to avoid conflicts.
92-
setTimeout(() => setSidebarAction(SidebarActions.JumpToManageCollections));
93-
});
94-
9587
const showManageCollections = useCallback(() => {
96-
navigateTo({ selectedItemId: containerKey });
97-
scheduleJumpToCollection();
98-
}, [scheduleJumpToCollection, navigateTo, containerKey]);
88+
navigateTo({ selectedItemId: containerKey, sidebarAction: SidebarActions.JumpToManageCollections });
89+
}, [navigateTo, containerKey]);
9990

10091
const openContainer = useCallback(() => {
10192
navigateTo({ containerId: containerKey });

src/library-authoring/routes.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
useSearchParams,
1212
} from 'react-router-dom';
1313
import { ContainerType, getBlockType } from '../generic/key-utils';
14+
import { SidebarActions } from './common/context/SidebarContext';
1415

1516
export const BASE_ROUTE = '/library/:libraryId';
1617

@@ -72,6 +73,7 @@ export type NavigateToData = {
7273
containerId?: string;
7374
contentType?: ContentType;
7475
index?: number;
76+
sidebarAction?: SidebarActions;
7577
};
7678

7779
export type LibraryRoutesData = {
@@ -136,6 +138,7 @@ export const useLibraryRoutes = (): LibraryRoutesData => {
136138
containerId,
137139
contentType,
138140
index,
141+
sidebarAction,
139142
}: NavigateToData = {}) => {
140143
const routeParams = {
141144
...params,
@@ -255,12 +258,17 @@ export const useLibraryRoutes = (): LibraryRoutesData => {
255258
routeParams.index = undefined;
256259
}
257260

258-
// Also remove the `sa` (sidebar action) search param if it exists.
259-
searchParams.delete(LibQueryParamKeys.SidebarActions);
261+
// Set or clear the sidebar action search param.
262+
if (sidebarAction) {
263+
searchParams.set(LibQueryParamKeys.SidebarActions, sidebarAction);
264+
} else {
265+
searchParams.delete(LibQueryParamKeys.SidebarActions);
266+
}
260267

261268
const newPath = generatePath(BASE_ROUTE + route, routeParams);
262269
// Prevent unnecessary navigation if the path is the same.
263-
if (newPath !== pathname) {
270+
// Always navigate when sidebarAction is provided to ensure the search param is updated.
271+
if (newPath !== pathname || sidebarAction) {
264272
navigate({
265273
pathname: newPath,
266274
search: searchParams.toString(),

src/library-authoring/section-subsections/LibraryContainerChildren.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { ToastContext } from '../../generic/toast-context';
3131
import TagCount from '../../generic/tag-count';
3232
import { useLibraryRoutes } from '../routes';
3333
import { SidebarActions, SidebarBodyItemId, useSidebarContext } from '../common/context/SidebarContext';
34-
import { skipIfUnwantedTarget, useRunOnNextRender } from '../../utils';
34+
import { skipIfUnwantedTarget } from '../../utils';
3535
import { ContainerMenu } from '../containers/ContainerCard';
3636

3737
interface LibraryContainerChildrenProps {
@@ -59,7 +59,7 @@ const ContainerRow = ({
5959
const { showToast } = useContext(ToastContext);
6060
const updateMutation = useUpdateContainer(container.originalId, containerKey);
6161
const { showOnlyPublished } = usePublishedFilterContext();
62-
const { setSidebarAction, openItemSidebar } = useSidebarContext();
62+
const { navigateTo } = useLibraryRoutes();
6363

6464
const handleSaveDisplayName = async (newDisplayName: string) => {
6565
try {
@@ -72,17 +72,9 @@ const ContainerRow = ({
7272
}
7373
};
7474

75-
/* istanbul ignore next */
76-
const scheduleJumpToTags = useRunOnNextRender(() => {
77-
// TODO: Ugly hack to make sure sidebar shows manage tags section
78-
// This needs to run after all changes to url takes place to avoid conflicts.
79-
setTimeout(() => setSidebarAction(SidebarActions.JumpToManageTags), 250);
80-
});
81-
8275
const jumpToManageTags = useCallback(() => {
83-
openItemSidebar(container.originalId, SidebarBodyItemId.ContainerInfo);
84-
scheduleJumpToTags();
85-
}, [openItemSidebar, scheduleJumpToTags, container.originalId]);
76+
navigateTo({ selectedItemId: container.originalId, sidebarAction: SidebarActions.JumpToManageTags });
77+
}, [navigateTo, container.originalId]);
8678

8779
return (
8880
<>
@@ -145,6 +137,7 @@ export const LibraryContainerChildren = ({ containerKey, readOnly }: LibraryCont
145137
const containerType = getBlockType(containerKey);
146138
const handleReorder = useCallback(() => async (newOrder?: LibraryContainerMetadataWithUniqueId[]) => {
147139
if (!newOrder) {
140+
/* istanbul ignore next */
148141
return;
149142
}
150143
const childrenKeys = newOrder.map((o) => o.originalId);

src/library-authoring/units/LibraryUnitBlocks.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { InplaceTextEditor } from '@src/generic/inplace-text-editor';
2424
import Loading from '@src/generic/Loading';
2525
import TagCount from '@src/generic/tag-count';
2626
import { ToastContext } from '@src/generic/toast-context';
27-
import { skipIfUnwantedTarget, useRunOnNextRender } from '@src/utils';
27+
import { skipIfUnwantedTarget } from '@src/utils';
2828
import { usePublishedFilterContext } from '@src/library-authoring/common/context/PublishedFilterContext';
2929
import { useOptionalLibraryContext } from '../common/context/LibraryContext';
3030
import ComponentMenu from '../components';
@@ -38,6 +38,7 @@ import { LibraryBlock } from '../LibraryBlock';
3838
import messages from './messages';
3939
import { SidebarActions, SidebarBodyItemId, useSidebarContext } from '../common/context/SidebarContext';
4040
import { canEditComponent } from '../components/ComponentEditorModal';
41+
import { useLibraryRoutes } from '../routes';
4142

4243
/** Components that need large min height in preview */
4344
const LARGE_COMPONENTS = [
@@ -64,7 +65,7 @@ const BlockHeader = ({ block, index, readOnly }: ComponentBlockProps) => {
6465
const intl = useIntl();
6566
const { showOnlyPublished } = usePublishedFilterContext();
6667
const { showToast } = useContext(ToastContext);
67-
const { setSidebarAction, openItemSidebar } = useSidebarContext();
68+
const { navigateTo } = useLibraryRoutes();
6869

6970
const updateMutation = useUpdateXBlockFields(block.originalId);
7071

@@ -82,17 +83,9 @@ const BlockHeader = ({ block, index, readOnly }: ComponentBlockProps) => {
8283
};
8384

8485
/* istanbul ignore next */
85-
const scheduleJumpToTags = useRunOnNextRender(() => {
86-
// TODO: Ugly hack to make sure sidebar shows manage tags section
87-
// This needs to run after all changes to url takes place to avoid conflicts.
88-
setTimeout(() => setSidebarAction(SidebarActions.JumpToManageTags), 250);
89-
});
90-
91-
/* istanbul ignore next */
92-
const jumpToManageTags = () => {
93-
openItemSidebar(block.originalId, SidebarBodyItemId.ComponentInfo);
94-
scheduleJumpToTags();
95-
};
86+
const jumpToManageTags = useCallback(() => {
87+
navigateTo({ selectedItemId: block.originalId, sidebarAction: SidebarActions.JumpToManageTags });
88+
}, [navigateTo, block.originalId]);
9689

9790
return (
9891
<>

src/utils.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export function setupYupExtensions() {
183183
}
184184
});
185185

186+
/* istanbul ignore next */
186187
if (errors.length > 0) {
187188
throw new Yup.ValidationError(errors);
188189
}
@@ -324,6 +325,7 @@ export const getFileSizeToClosestByte = (fileSize: any) => {
324325
* A generic hook to run callback on next render cycle.
325326
* @param {} callback - Callback function that needs to be run later
326327
*/
328+
/* istanbul ignore next */
327329
export const useRunOnNextRender = (callback: () => void) => {
328330
const [scheduled, setScheduled] = useState(false);
329331

0 commit comments

Comments
 (0)