mirror of
https://github.com/strapi/strapi.git
synced 2025-10-17 19:13:25 +00:00
chore: useScopedPersistentState custom hook
This commit is contained in:
parent
8ecdda9ea1
commit
83c9d185c6
@ -7,7 +7,7 @@ import { useIntl } from 'react-intl';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import { useGetLicenseTrialTimeLeftQuery } from '../../src/services/admin';
|
||||
import { usePersistentState } from '../hooks/usePersistentState';
|
||||
import { useScopedPersistentState } from '../hooks/usePersistentState';
|
||||
|
||||
const BannerBackground = styled(Flex)`
|
||||
background: linear-gradient(
|
||||
@ -101,7 +101,7 @@ const Banner = ({ isTrialEndedRecently }: { isTrialEndedRecently: boolean }) =>
|
||||
const UpsellBanner = () => {
|
||||
const { license } = useLicenseLimits();
|
||||
|
||||
const [cachedTrialEndsAt, setCachedTrialEndsAt] = usePersistentState<string | undefined>(
|
||||
const [cachedTrialEndsAt, setCachedTrialEndsAt] = useScopedPersistentState<string | undefined>(
|
||||
'STRAPI_FREE_TRIAL_ENDS_AT',
|
||||
undefined
|
||||
);
|
||||
|
@ -18,11 +18,16 @@ jest.mock('../../../src/services/admin', () => ({
|
||||
trialEndsAt: '2025-05-15T00:00:00.000Z',
|
||||
},
|
||||
})),
|
||||
useInitQuery: jest.fn(() => ({
|
||||
data: {
|
||||
uuid: 'test-uuid',
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('UpsellBanner', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDS_AT');
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid');
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
@ -82,7 +87,7 @@ describe('UpsellBanner', () => {
|
||||
data: {},
|
||||
}));
|
||||
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT', '2025-05-21T09:50:00.000Z');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid', '2025-05-21T09:50:00.000Z');
|
||||
jest.setSystemTime(new Date(2025, 4, 22));
|
||||
|
||||
render(<UpsellBanner />);
|
||||
@ -114,7 +119,7 @@ describe('UpsellBanner', () => {
|
||||
data: {},
|
||||
}));
|
||||
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT', '2025-05-10T09:50:00.000Z');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid', '2025-05-10T09:50:00.000Z');
|
||||
jest.setSystemTime(new Date(2025, 4, 22));
|
||||
|
||||
render(<UpsellBanner />);
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import { usePersistentState } from '../usePersistentState';
|
||||
import { usePersistentState, useScopedPersistentState } from '../usePersistentState';
|
||||
|
||||
jest.mock('../../services/admin', () => ({
|
||||
useInitQuery: jest.fn(() => ({
|
||||
data: {
|
||||
uuid: 'test-uuid',
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('usePersistentState', () => {
|
||||
it('should return the value passed to set in the local storage', async () => {
|
||||
@ -15,3 +23,18 @@ describe('usePersistentState', () => {
|
||||
expect(updatedValue).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useScopedPersistentState', () => {
|
||||
it('should return the value passed to set in the local storage with a scoped key', async () => {
|
||||
const { result } = renderHook(() => useScopedPersistentState('key', 0));
|
||||
const [value, setValue] = result.current;
|
||||
expect(value).toBe(0);
|
||||
|
||||
act(() => {
|
||||
setValue(1);
|
||||
});
|
||||
const [updatedValue] = result.current;
|
||||
expect(localStorage.getItem('key:test-uuid')).toBeDefined();
|
||||
expect(updatedValue).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useInitQuery } from '../services/admin';
|
||||
|
||||
const usePersistentState = <T>(key: string, defaultValue: T) => {
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
const stickyValue = window.localStorage.getItem(key);
|
||||
@ -23,4 +25,14 @@ const usePersistentState = <T>(key: string, defaultValue: T) => {
|
||||
return [value, setValue] as const;
|
||||
};
|
||||
|
||||
export { usePersistentState };
|
||||
// Same as usePersistentState, but scoped to the current instance of Strapi
|
||||
// useful for storing state that should not be shared across different instances of Strapi running on localhost
|
||||
const useScopedPersistentState = <T>(key: string, defaultValue: T) => {
|
||||
const { data: initData } = useInitQuery();
|
||||
const { uuid } = initData ?? {};
|
||||
|
||||
const namespacedKey = `${key}:${uuid}`;
|
||||
return usePersistentState<T>(namespacedKey, defaultValue);
|
||||
};
|
||||
|
||||
export { usePersistentState, useScopedPersistentState };
|
||||
|
@ -7,7 +7,7 @@ import { useIntl } from 'react-intl';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { useLicenseLimits } from '../../../../../ee/admin/src/hooks/useLicenseLimits';
|
||||
import { usePersistentState } from '../../../hooks/usePersistentState';
|
||||
import { useScopedPersistentState } from '../../../hooks/usePersistentState';
|
||||
|
||||
const StyledModalContent = styled(Modal.Content)`
|
||||
max-width: 51.6rem;
|
||||
@ -30,11 +30,11 @@ const StyledButton = styled(Button)`
|
||||
export const FreeTrialEndedModal = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const [open, setOpen] = useState(true);
|
||||
const [previouslyOpen, setPreviouslyOpen] = usePersistentState(
|
||||
const [previouslyOpen, setPreviouslyOpen] = useScopedPersistentState(
|
||||
'STRAPI_FREE_TRIAL_ENDED_MODAL',
|
||||
false
|
||||
);
|
||||
const [cachedTrialEndsAt] = usePersistentState<string | undefined>(
|
||||
const [cachedTrialEndsAt] = useScopedPersistentState<string | undefined>(
|
||||
'STRAPI_FREE_TRIAL_ENDS_AT',
|
||||
undefined
|
||||
);
|
||||
|
@ -7,7 +7,7 @@ import styled from 'styled-components';
|
||||
|
||||
import { useLicenseLimits } from '../../../../../ee/admin/src/hooks/useLicenseLimits';
|
||||
import lightIllustration from '../../../assets/images/free-trial.png';
|
||||
import { usePersistentState } from '../../../hooks/usePersistentState';
|
||||
import { useScopedPersistentState } from '../../../hooks/usePersistentState';
|
||||
|
||||
const StyledModalContent = styled(Modal.Content)`
|
||||
max-width: 51.6rem;
|
||||
@ -34,7 +34,7 @@ const StyledButton = styled(Button)`
|
||||
export const FreeTrialWelcomeModal = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const [open, setOpen] = useState(true);
|
||||
const [previouslyOpen, setPreviouslyOpen] = usePersistentState(
|
||||
const [previouslyOpen, setPreviouslyOpen] = useScopedPersistentState(
|
||||
'STRAPI_FREE_TRIAL_WELCOME_MODAL',
|
||||
false
|
||||
);
|
||||
|
@ -18,12 +18,17 @@ jest.mock('../../../../../src/services/admin', () => ({
|
||||
trialEndsAt: '2025-05-15T00:00:00.000Z',
|
||||
},
|
||||
})),
|
||||
useInitQuery: jest.fn(() => ({
|
||||
data: {
|
||||
uuid: 'test-uuid',
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('FreeTrialEndedModal', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDS_AT');
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDED_MODAL');
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid');
|
||||
localStorage.removeItem('STRAPI_FREE_TRIAL_ENDED_MODAL:test-uuid');
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
@ -36,7 +41,7 @@ describe('FreeTrialEndedModal', () => {
|
||||
});
|
||||
|
||||
it('should render when trial ended less than 7 days ago and modal never appeared before', async () => {
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT', '2025-05-21T09:50:00.000Z');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid', '2025-05-21T09:50:00.000Z');
|
||||
|
||||
// @ts-expect-error – mock
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
@ -53,8 +58,8 @@ describe('FreeTrialEndedModal', () => {
|
||||
});
|
||||
|
||||
it('should not render when trial ended less than 7 days ago but modal already appeared before', async () => {
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT', '2025-05-21T09:50:00.000Z');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDED_MODAL', 'true');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDS_AT:test-uuid', '2025-05-21T09:50:00.000Z');
|
||||
localStorage.setItem('STRAPI_FREE_TRIAL_ENDED_MODAL:test-uuid', 'true');
|
||||
|
||||
// @ts-expect-error – mock
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
|
@ -3,6 +3,14 @@ import { render, screen, waitFor } from '@tests/utils';
|
||||
import { useLicenseLimits } from '../../../../../../ee/admin/src/hooks/useLicenseLimits';
|
||||
import { FreeTrialWelcomeModal } from '../FreeTrialWelcomeModal';
|
||||
|
||||
jest.mock('../../../../services/admin', () => ({
|
||||
useInitQuery: jest.fn(() => ({
|
||||
data: {
|
||||
uuid: 'test-uuid',
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../../ee/admin/src/hooks/useLicenseLimits', () => ({
|
||||
useLicenseLimits: jest.fn(() => ({
|
||||
license: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user