Skip to content

Commit

Permalink
feat: Persist navigation settings (#7144)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed May 24, 2024
1 parent 81c6caf commit 68427f8
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,7 @@ import CorsIcon from '@mui/icons-material/StorageOutlined';
import BillingIcon from '@mui/icons-material/CreditCardOutlined';
import SignOutIcon from '@mui/icons-material/ExitToApp';
import { ReactComponent as ProjectIcon } from 'assets/icons/projectIconSmall.svg';
import {
type FC,
type ReactNode,
useCallback,
useEffect,
useState,
} from 'react';
import { type FC, type ReactNode, useCallback, useEffect } from 'react';
import { getCondensedRoutes, getRoutes } from '../../../menu/routes';
import { useAdminRoutes } from '../../../admin/useAdminRoutes';
import { filterByConfig, mapRouteLink } from 'component/common/util';
Expand All @@ -64,6 +58,7 @@ import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import GitHubIcon from '@mui/icons-material/GitHub';
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
import { basePath } from 'utils/formatPath';
import { useLocalStorageState } from 'hooks/useLocalStorageState';

export const StyledProjectIcon = styled(ProjectIcon)(({ theme }) => ({
fill: theme.palette.neutral.main,
Expand Down Expand Up @@ -276,7 +271,10 @@ const useShowBadge = () => {
};

const useNavigationMode = () => {
const [mode, setMode] = useState<'mini' | 'full'>('full');
const [mode, setMode] = useLocalStorageState<'mini' | 'full'>(
'navigation-mode:v1',
'full',
);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'b' && (event.metaKey || event.ctrlKey)) {
Expand Down
61 changes: 61 additions & 0 deletions frontend/src/hooks/useLocalStorageState.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useLocalStorageState } from './useLocalStorageState';
import { createLocalStorage } from '../utils/createLocalStorage';
import { render } from 'utils/testRenderer';
import { screen, waitFor } from '@testing-library/react';
import type { FC } from 'react';

const TestComponent: FC<{
keyName: string;
initialValue: any;
}> = ({ keyName, initialValue }) => {
const [value, setValue] = useLocalStorageState(keyName, initialValue);

return (
<div>
<span data-testid='storedValue'>{value}</span>
<button
type='submit'
onClick={() => setValue('updatedValue')}
data-testid='updateButton'
/>
</div>
);
};

describe('useLocalStorageState', () => {
beforeEach(() => {
window.localStorage.clear();
});

it('should initialize with the initial value if local storage is empty', () => {
render(<TestComponent keyName='testKey' initialValue='initialValue' />);

expect(screen.getByTestId('storedValue').textContent).toBe(
'initialValue',
);
});

it('updates the local storage and state when value changes', async () => {
render(<TestComponent keyName='testKey' initialValue='initialValue' />);

screen.getByTestId('updateButton').click();

expect(screen.getByTestId('storedValue').textContent).toBe(
'updatedValue',
);
await waitFor(() => {
const { value } = createLocalStorage('testKey', {});
expect(value).toStrictEqual('updatedValue');
});
});

it('initializes with the value from local storage if available', async () => {
createLocalStorage('testKey', {}).setValue('storedValue');

render(<TestComponent keyName='testKey' initialValue='initialValue' />);

expect(screen.getByTestId('storedValue').textContent).toBe(
'storedValue',
);
});
});
18 changes: 18 additions & 0 deletions frontend/src/hooks/useLocalStorageState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect, useState } from 'react';
import { createLocalStorage } from '../utils/createLocalStorage';

export const useLocalStorageState = <T extends object | string>(
key: string,
initialValue: T,
) => {
const { value: initialStoredValue, setValue: setStoredValue } =
createLocalStorage<T>(key, initialValue);

const [localValue, setLocalValue] = useState<T>(initialStoredValue);

useEffect(() => {
setStoredValue(localValue);
}, [localValue]);

return [localValue, setLocalValue] as const;
};
2 changes: 1 addition & 1 deletion frontend/src/utils/createLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { basePath } from './formatPath';
import { getLocalStorageItem, setLocalStorageItem } from './storage';

export const createLocalStorage = <T extends object>(
export const createLocalStorage = <T extends object | string>(
key: string,
initialValue: T,
) => {
Expand Down

0 comments on commit 68427f8

Please sign in to comment.