diff --git a/package-lock.json b/package-lock.json index ca871744..36779dd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@tinymce/tinymce-react": "^4.3.2", "@zextras/carbonio-design-system": "^4.2.0", "@zextras/carbonio-ui-preview": "^1.2.3", - "darkreader": "^4.9.77", + "darkreader": "^4.9.79", "history": "^5.3.0", "i18next": "^22.5.1", "i18next-http-backend": "^2.5.0", @@ -7715,9 +7715,9 @@ } }, "node_modules/darkreader": { - "version": "4.9.77", - "resolved": "https://registry.npmjs.org/darkreader/-/darkreader-4.9.77.tgz", - "integrity": "sha512-PHv6pOEFIdoiQxJewUxnbrcB7aJsTgiECws9KNNxEpk2bma1CZNaweFALyADfmosAaoDlJaxvbpzXMxcc0T+jA==", + "version": "4.9.79", + "resolved": "https://registry.npmjs.org/darkreader/-/darkreader-4.9.79.tgz", + "integrity": "sha512-FZ/8qP2WuZ3eJTFhaTIoQhTW/OdwBZLbh6Rsl0BjSXXLvl2VNEqQ5C/uBFtcJPtnYMH1xgbQAjzzz68s/FS8Ng==", "funding": { "type": "opencollective", "url": "https://opencollective.com/darkreader/donate" diff --git a/package.json b/package.json index dc08f7a6..ae542680 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "@tinymce/tinymce-react": "^4.3.2", "@zextras/carbonio-design-system": "^4.2.0", "@zextras/carbonio-ui-preview": "^1.2.3", - "darkreader": "^4.9.77", + "darkreader": "^4.9.79", "history": "^5.3.0", "i18next": "^22.5.1", "i18next-http-backend": "^2.5.0", diff --git a/src/boot/use-get-primary-color.test.tsx b/src/boot/use-get-primary-color.test.tsx new file mode 100644 index 00000000..c0a68ac7 --- /dev/null +++ b/src/boot/use-get-primary-color.test.tsx @@ -0,0 +1,190 @@ +/* + * SPDX-FileCopyrightText: 2024 Zextras + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import React from 'react'; + +import { act, screen } from '@testing-library/react'; +import { produce } from 'immer'; + +import { useGetPrimaryColor } from './use-get-primary-color'; +import { DARK_READER_PROP_KEY, SHELL_APP_ID } from '../constants'; +import * as useLocalStorage from '../shell/hooks/useLocalStorage'; +import { useAccountStore } from '../store/account'; +import { useLoginConfigStore } from '../store/login/store'; +import { setup } from '../test/utils'; + +const PrimaryColorComponent = (): React.JSX.Element => { + const primary = useGetPrimaryColor(); + return
{`color: ${primary}`}
; +}; + +describe('Use get primary color', () => { + it('should return the carbonioWebUiPrimaryColor config when available and dark mode is disabled', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + const carbonioWebUiPrimaryColorConfig = '#bbbbbb'; + const carbonioWebUiDarkPrimaryColorConfig = '#cccccc'; + useLoginConfigStore.setState((s) => ({ + ...s, + carbonioWebUiPrimaryColor: carbonioWebUiPrimaryColorConfig, + carbonioWebUiDarkPrimaryColor: carbonioWebUiDarkPrimaryColorConfig, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'disabled' } + ]; + }) + ); + + setup(); + + expect(await screen.findByText(`color: ${carbonioWebUiPrimaryColorConfig}`)).toBeVisible(); + }); + + it('should return the carbonioWebUiDarkPrimaryColor config when available and dark mode is enabled', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + const carbonioWebUiPrimaryColorConfig = '#bbbbbb'; + const carbonioWebUiDarkPrimaryColorConfig = '#cccccc'; + useLoginConfigStore.setState((s) => ({ + ...s, + carbonioWebUiPrimaryColor: carbonioWebUiPrimaryColorConfig, + carbonioWebUiDarkPrimaryColor: carbonioWebUiDarkPrimaryColorConfig, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'enabled' } + ]; + }) + ); + + setup(); + + expect(await screen.findByText(`color: ${carbonioWebUiDarkPrimaryColorConfig}`)).toBeVisible(); + }); + + it('should return the carbonioWebUiPrimaryColor config when available and carbonioWebUiDarkPrimaryColor is not available and dark mode is enabled', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + const carbonioWebUiPrimaryColorConfig = '#bbbbbb'; + useLoginConfigStore.setState((s) => ({ + ...s, + carbonioWebUiPrimaryColor: carbonioWebUiPrimaryColorConfig, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'enabled' } + ]; + }) + ); + + setup(); + + expect(await screen.findByText(`color: ${carbonioWebUiPrimaryColorConfig}`)).toBeVisible(); + }); + + it('should return the carbonioWebUiDarkPrimaryColor config when available and carbonioWebUiPrimaryColor is not available and dark mode is disabled', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + const carbonioWebUiDarkPrimaryColorConfig = '#cccccc'; + useLoginConfigStore.setState((s) => ({ + ...s, + carbonioWebUiDarkPrimaryColor: carbonioWebUiDarkPrimaryColorConfig, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'disabled' } + ]; + }) + ); + + setup(); + + expect(await screen.findByText(`color: ${carbonioWebUiDarkPrimaryColorConfig}`)).toBeVisible(); + }); + + it('should use localStore color as fallback until config color is received', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + setup(); + + expect(await screen.findByText(`color: ${localStorageColor}`)).toBeVisible(); + + const carbonioWebUiPrimaryColorConfig = '#bbbbbb'; + const carbonioWebUiDarkPrimaryColorConfig = '#cccccc'; + act(() => { + useLoginConfigStore.setState((s) => ({ + ...s, + carbonioWebUiPrimaryColor: carbonioWebUiPrimaryColorConfig, + carbonioWebUiDarkPrimaryColor: carbonioWebUiDarkPrimaryColorConfig, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'disabled' } + ]; + }) + ); + }); + expect(await screen.findByText(`color: ${carbonioWebUiPrimaryColorConfig}`)).toBeVisible(); + }); + + it('should use localStore color as fallback until configs are received and return undefined if carbonioWebUiPrimaryColor is not received', async () => { + const localStorageColor = '#aabbaa'; + const mockUseLocalStorage = jest.spyOn(useLocalStorage, 'useLocalStorage'); + + mockUseLocalStorage.mockReturnValue([{ light: localStorageColor }, jest.fn()]); + + setup(); + + expect(await screen.findByText(`color: ${localStorageColor}`)).toBeVisible(); + + act(() => { + useLoginConfigStore.setState((s) => ({ + ...s, + loaded: true + })); + + useAccountStore.setState( + produce((state) => { + state.settings.props = [ + { name: DARK_READER_PROP_KEY, zimlet: SHELL_APP_ID, _content: 'disabled' } + ]; + }) + ); + }); + expect(await screen.findByText(`color: undefined`)).toBeVisible(); + }); +}); diff --git a/src/boot/use-get-primary-color.tsx b/src/boot/use-get-primary-color.tsx index 3c127803..d9940c5a 100644 --- a/src/boot/use-get-primary-color.tsx +++ b/src/boot/use-get-primary-color.tsx @@ -5,7 +5,6 @@ */ import { useEffect, useMemo } from 'react'; -import { useTheme } from '@zextras/carbonio-design-system'; import { size } from 'lodash'; import { LOCAL_STORAGE_LAST_PRIMARY_KEY } from '../constants'; @@ -17,9 +16,9 @@ export function useGetPrimaryColor(): string | undefined { const [localStorageLastPrimary, setLocalStorageLastPrimary] = useLocalStorage< Partial> | undefined >(LOCAL_STORAGE_LAST_PRIMARY_KEY, undefined); - const { carbonioWebUiPrimaryColor, carbonioWebUiDarkPrimaryColor } = useLoginConfigStore(); + const { carbonioWebUiPrimaryColor, carbonioWebUiDarkPrimaryColor, loaded } = + useLoginConfigStore(); const { darkModeEnabled, darkReaderStatus } = useDarkMode(); - const theme = useTheme(); const primaryColor = useMemo(() => { if ( @@ -31,24 +30,21 @@ export function useGetPrimaryColor(): string | undefined { } return carbonioWebUiPrimaryColor || carbonioWebUiDarkPrimaryColor; } - if (localStorageLastPrimary && size(localStorageLastPrimary) > 0) { + if (localStorageLastPrimary && size(localStorageLastPrimary) > 0 && !loaded) { return ( (darkModeEnabled && (localStorageLastPrimary.dark || localStorageLastPrimary.light)) || localStorageLastPrimary.light || localStorageLastPrimary.dark ); } - if (theme) { - return theme.palette.primary.regular; - } return undefined; }, [ carbonioWebUiDarkPrimaryColor, carbonioWebUiPrimaryColor, darkModeEnabled, darkReaderStatus, - localStorageLastPrimary, - theme + loaded, + localStorageLastPrimary ]); useEffect(() => {