From 5482104312ce3e6b6974a1ef206c05e51b194630 Mon Sep 17 00:00:00 2001 From: mateusz-winiarczyk <mateusz.winiarczyk@appunite.com> Date: Wed, 27 Mar 2024 15:03:02 +0100 Subject: [PATCH] feat(project): deploy and project adjustments (MIN-304) --- .env | 5 --- index.d.ts | 7 ++++ next.config.js | 8 ++--- pages/_document.tsx | 15 +++++++++ public/config.js | 6 ++++ setupTests.ts | 9 +++++ .../OverviewImagesModal.component.test.tsx | 2 ++ .../utils/useOverviewImage.test.ts | 3 ++ .../utils/useOverviewImageLinkActions.test.ts | 8 +++++ .../useOverviewImageLinkElements.test.ts | 3 ++ .../utils/useOverviewImageSize.test.tsx | 3 ++ .../utils/useOverviewImageUrl.test.ts | 2 ++ .../UserOverlayForm.component.test.tsx | 5 +++ .../ProjectInfoDrawer.component.test.tsx | 1 + .../MapAdditionalOptions.component.test.tsx | 28 +++++++++++++++- .../MapAdditionalOptions.component.tsx | 14 ++++++-- src/constants/index.ts | 11 ++++--- src/constants/index.utils.test.ts | 33 +++++++++++++++++++ src/constants/index.utils.ts | 19 +++++++++++ src/models/projectSchema.ts | 2 +- src/redux/overlays/overlays.thunks.ts | 3 +- src/redux/project/project.mock.ts | 3 +- src/redux/project/project.reducers.test.ts | 1 + src/redux/project/project.reducers.ts | 8 ++++- src/redux/project/project.selectors.ts | 4 ++- src/redux/project/project.slice.ts | 4 ++- src/redux/project/project.thunks.ts | 11 +++++++ src/redux/project/project.types.ts | 4 +++ src/redux/root/init.thunks.ts | 4 ++- src/redux/root/query.selectors.ts | 4 +++ src/types/query.ts | 3 ++ src/utils/parseQueryToTypes.ts | 1 + .../useReduxBusQueryManager.test.ts | 1 + 33 files changed, 211 insertions(+), 24 deletions(-) create mode 100644 pages/_document.tsx create mode 100644 public/config.js create mode 100644 src/constants/index.utils.test.ts create mode 100644 src/constants/index.utils.ts diff --git a/.env b/.env index b3e48b42..295a27f9 100644 --- a/.env +++ b/.env @@ -1,6 +1 @@ - -NEXT_PUBLIC_BASE_API_URL = 'https://lux1.atcomp.pl/minerva/api' -NEXT_PUBLIC_BASE_NEW_API_URL = 'https://lux1.atcomp.pl/minerva/new_api/' -BASE_MAP_IMAGES_URL = 'https://lux1.atcomp.pl/' -NEXT_PUBLIC_PROJECT_ID = 'pdmap_appu_test' ZOD_SEED = 997 diff --git a/index.d.ts b/index.d.ts index f9baf054..81c13458 100644 --- a/index.d.ts +++ b/index.d.ts @@ -42,6 +42,13 @@ type HashPlugin = { declare global { interface Window { + config: { + BASE_API_URL: string; + BASE_NEW_API_URL: string; + BASE_MAP_IMAGES_URL: string; + DEFAULT_PROJECT_ID: string; + }; + minerva: { configuration?: MinervaConfiguration; plugins: { diff --git a/next.config.js b/next.config.js index eebeaf4d..c451e700 100644 --- a/next.config.js +++ b/next.config.js @@ -1,13 +1,11 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - experimental: { - fontLoaders: [{ loader: '@next/font/google', options: { subsets: ['latin'] } }], + output: 'export', + images: { + unoptimized: true, }, env: { - BASE_API_URL: process.env.NEXT_PUBLIC_BASE_API_URL || '', - BASE_MAP_IMAGES_URL: process.env.BASE_MAP_IMAGES_URL || '', - PROJECT_ID: process.env.NEXT_PUBLIC_PROJECT_ID || '', ZOD_SEED: process.env.ZOD_SEED || 123, }, }; diff --git a/pages/_document.tsx b/pages/_document.tsx new file mode 100644 index 00000000..eaa2d812 --- /dev/null +++ b/pages/_document.tsx @@ -0,0 +1,15 @@ +import { Html, Head, Main, NextScript } from 'next/document'; +import Script from 'next/script'; + +const Document = (): React.ReactNode => ( + <Html> + <Head /> + <body> + <Main /> + <NextScript /> + <Script src="/config.js" strategy="beforeInteractive" /> + </body> + </Html> +); + +export default Document; diff --git a/public/config.js b/public/config.js new file mode 100644 index 00000000..c30b99cc --- /dev/null +++ b/public/config.js @@ -0,0 +1,6 @@ +window.config = { + BASE_API_URL: 'https://lux1.atcomp.pl/minerva/api', + BASE_NEW_API_URL: 'https://lux1.atcomp.pl/minerva/new_api/', + BASE_MAP_IMAGES_URL: 'https://lux1.atcomp.pl/', + DEFAULT_PROJECT_ID: 'pdmap_appu_test', +}; diff --git a/setupTests.ts b/setupTests.ts index 1d944c81..7a4cf03f 100644 --- a/setupTests.ts +++ b/setupTests.ts @@ -36,3 +36,12 @@ const localStorageMock = (() => { Object.defineProperty(global, 'localStorage', { value: localStorageMock, }); + +Object.defineProperty(window, 'config', { + value: { + BASE_API_URL: 'https://lux1.atcomp.pl/minerva/api', + BASE_NEW_API_URL: 'https://lux1.atcomp.pl/minerva/new_api/', + BASE_MAP_IMAGES_URL: 'https://lux1.atcomp.pl/', + DEFAULT_PROJECT_ID: 'pdmap_appu_test', + }, +}); diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx index b8c92be9..5b7ed93e 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx @@ -45,6 +45,7 @@ describe('OverviewImagesModal - component', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -72,6 +73,7 @@ describe('OverviewImagesModal - component', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts index cd7468fd..f5ae9c32 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts @@ -18,6 +18,7 @@ describe('useOverviewImage - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -50,6 +51,7 @@ describe('useOverviewImage - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -89,6 +91,7 @@ describe('useOverviewImage - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts index 609cc0f5..375cd187 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkActions.test.ts @@ -43,6 +43,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -92,6 +93,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -148,6 +150,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -225,6 +228,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -328,6 +332,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -378,6 +383,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, map: { data: { @@ -438,6 +444,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, map: { data: { @@ -500,6 +507,7 @@ describe('useOverviewImageLinkActions - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, map: { data: { diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkElements.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkElements.test.ts index 308e5240..61169d09 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkElements.test.ts +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageLinkElements.test.ts @@ -17,6 +17,7 @@ describe('useOverviewImageLinkConfigs - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -53,6 +54,7 @@ describe('useOverviewImageLinkConfigs - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -89,6 +91,7 @@ describe('useOverviewImageLinkConfigs - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx index b5c8b6b5..f1cfe2e7 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx @@ -18,6 +18,7 @@ describe('useOverviewImageSize - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -49,6 +50,7 @@ describe('useOverviewImageSize - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -77,6 +79,7 @@ describe('useOverviewImageSize - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts index b5e9beb8..b257be4c 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts @@ -17,6 +17,7 @@ describe('useOverviewImageUrl - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, @@ -43,6 +44,7 @@ describe('useOverviewImageUrl - hook', () => { }, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, modal: { ...MODAL_INITIAL_STATE_MOCK, diff --git a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx index b9966147..0d0561aa 100644 --- a/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx +++ b/src/components/Map/Drawer/OverlaysDrawer/UserOverlayForm/UserOverlayForm.component.test.tsx @@ -88,6 +88,7 @@ describe('UserOverlayForm - Component', () => { data: projectFixture, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -111,6 +112,7 @@ describe('UserOverlayForm - Component', () => { data: projectFixture, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -181,6 +183,7 @@ describe('UserOverlayForm - Component', () => { data: projectFixture, loading: 'succeeded', error: { message: '', name: '' }, + projectId: '', }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -225,6 +228,7 @@ describe('UserOverlayForm - Component', () => { data: projectFixture, loading: 'succeeded', error: DEFAULT_ERROR, + projectId: '', }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -283,6 +287,7 @@ describe('UserOverlayForm - Component', () => { data: projectFixture, loading: 'succeeded', error: DEFAULT_ERROR, + projectId: '', }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); diff --git a/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.test.tsx b/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.test.tsx index bfad3705..e7e1a3ef 100644 --- a/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.test.tsx +++ b/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.test.tsx @@ -14,6 +14,7 @@ const MOCKED_STORE: InitialStoreState = { data: { ...projectFixture }, loading: 'idle', error: new Error(), + projectId: '', }, models: { data: [MODEL_WITH_DESCRIPTION], diff --git a/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.test.tsx b/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.test.tsx index 19571c28..ff8459b4 100644 --- a/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.test.tsx +++ b/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.test.tsx @@ -12,6 +12,8 @@ import { } from '@/utils/testing/getReduxWrapperWithStore'; import { render, screen } from '@testing-library/react'; import { MockStoreEnhanced } from 'redux-mock-store'; +import { PROJECT_STATE_INITIAL_MOCK } from '@/redux/project/project.mock'; +import { projectFixture } from '@/models/fixtures/projectFixture'; import { MapAdditionalOptions } from './MapAdditionalOptions.component'; const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { @@ -59,6 +61,10 @@ describe('MapAdditionalOptions - component', () => { it('should open overview image modal on button click', () => { const { store } = renderComponentWithActionListener({ + project: { + ...PROJECT_STATE_INITIAL_MOCK, + data: projectFixture, + }, map: initialMapStateFixture, backgrounds: { ...BACKGROUND_INITIAL_STATE_MOCK, data: BACKGROUNDS_MOCK }, }); @@ -68,8 +74,28 @@ describe('MapAdditionalOptions - component', () => { const actions = store.getActions(); expect(actions[FIRST_ARRAY_ELEMENT]).toStrictEqual({ - payload: 0, + payload: projectFixture.topOverviewImage?.idObject, type: 'modal/openOverviewImagesModalById', }); }); + it('should disable button browse overview images if there are no overview images', () => { + const { store } = renderComponentWithActionListener({ + project: { + ...PROJECT_STATE_INITIAL_MOCK, + data: { + ...projectFixture, + overviewImageViews: [], + }, + }, + map: initialMapStateFixture, + backgrounds: { ...BACKGROUND_INITIAL_STATE_MOCK, data: BACKGROUNDS_MOCK }, + }); + + const overviewImageButton = screen.getByText('Browse overview images'); + expect(overviewImageButton).toBeDisabled(); + overviewImageButton.click(); + + const actions = store.getActions(); + expect(actions).toStrictEqual([]); + }); }); diff --git a/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.tsx b/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.tsx index 84dec36a..a06ecbdb 100644 --- a/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.tsx +++ b/src/components/Map/MapAdditionalOptions/MapAdditionalOptions.component.tsx @@ -1,9 +1,13 @@ import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { openOverviewImagesModalById } from '@/redux/modal/modal.slice'; -import { projectDefaultOverviewImageIdSelector } from '@/redux/project/project.selectors'; +import { + projectDefaultOverviewImageIdSelector, + projectOverviewImagesSelector, +} from '@/redux/project/project.selectors'; import { Button } from '@/shared/Button'; import { useSelector } from 'react-redux'; import { twMerge } from 'tailwind-merge'; +import { ZERO } from '@/constants/common'; import { BackgroundSelector } from './BackgroundsSelector'; // top-[calc(64px+40px+24px)] -> TOP_BAR_HEIGHT+MAP_NAVIGATION_HEIGHT+DISTANCE_FROM_MAP_NAVIGATION @@ -11,6 +15,8 @@ import { BackgroundSelector } from './BackgroundsSelector'; export const MapAdditionalOptions = (): JSX.Element => { const dispatch = useAppDispatch(); const defaultOverviewImageId = useSelector(projectDefaultOverviewImageIdSelector); + const overviewImages = useSelector(projectOverviewImagesSelector); + const overviewImagesEmpty = overviewImages.length === ZERO; const handleBrowseOverviewImagesClick = (): void => { dispatch(openOverviewImagesModalById(defaultOverviewImageId)); @@ -18,7 +24,11 @@ export const MapAdditionalOptions = (): JSX.Element => { return ( <div className={twMerge('absolute right-6 top-[calc(64px+40px+24px)] z-10 flex')}> - <Button className="mr-4" onClick={handleBrowseOverviewImagesClick}> + <Button + className="mr-4" + onClick={handleBrowseOverviewImagesClick} + disabled={overviewImagesEmpty} + > Browse overview images </Button> <BackgroundSelector /> diff --git a/src/constants/index.ts b/src/constants/index.ts index 70fa367a..84426822 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,9 +1,12 @@ /* eslint-disable no-magic-numbers */ -export const BASE_API_URL = process.env.NEXT_PUBLIC_BASE_API_URL || ''; -export const BASE_MAP_IMAGES_URL = process.env.BASE_MAP_IMAGES_URL || ''; -export const BASE_NEW_API_URL = process.env.NEXT_PUBLIC_BASE_NEW_API_URL || ''; -export const PROJECT_ID = process.env.NEXT_PUBLIC_PROJECT_ID || ''; +import { getConfigValue, getProjectIdFromUrl } from './index.utils'; + +export const BASE_API_URL = getConfigValue('BASE_API_URL'); +export const BASE_MAP_IMAGES_URL = getConfigValue('BASE_MAP_IMAGES_URL'); +export const BASE_NEW_API_URL = getConfigValue('BASE_NEW_API_URL'); +export const DEFAULT_PROJECT_ID = getConfigValue('DEFAULT_PROJECT_ID'); +export const PROJECT_ID = getProjectIdFromUrl() || DEFAULT_PROJECT_ID; export const ZOD_SEED = parseInt(process.env.ZOD_SEED || '123', 10); export const BIO_ENTITY = 'bioEntity'; export const DRUGS_CHEMICALS = ['drugs', 'chemicals']; diff --git a/src/constants/index.utils.test.ts b/src/constants/index.utils.test.ts new file mode 100644 index 00000000..2d9ddfd0 --- /dev/null +++ b/src/constants/index.utils.test.ts @@ -0,0 +1,33 @@ +import { getConfigValue, getProjectIdFromUrl } from './index.utils'; + +describe('getConfigValue - util', () => { + it('should return value for existing key', () => { + expect(getConfigValue('BASE_API_URL')).toBe('https://lux1.atcomp.pl/minerva/api'); + }); + + it('should return default value for non-existing key', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect(getConfigValue('nonExistingKey' as any)).toBe(''); + }); +}); + +describe('getProjectIdFromUrl - util', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should return project ID from URL if present', () => { + jest.spyOn(URLSearchParams.prototype, 'get').mockReturnValue('my_project_id'); + expect(getProjectIdFromUrl()).toBe('my_project_id'); + }); + + it('should return default project ID if not present in URL', () => { + jest.spyOn(URLSearchParams.prototype, 'get').mockReturnValue(null); + expect(getProjectIdFromUrl()).toBeNull(); + }); + it('should return undefined if window is undefined', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + jest.spyOn(global as any, 'window', 'get').mockImplementation(() => undefined); + + expect(getProjectIdFromUrl()).toBeUndefined(); + }); +}); diff --git a/src/constants/index.utils.ts b/src/constants/index.utils.ts new file mode 100644 index 00000000..ebd2553b --- /dev/null +++ b/src/constants/index.utils.ts @@ -0,0 +1,19 @@ +type ConfigKeys = keyof typeof window.config; + +export const getConfigValue = (key: ConfigKeys): string => { + const defaultValue = ''; + if (typeof window !== 'undefined' && window.config && window.config[key]) { + return window.config[key]; + } + return defaultValue; +}; + +export const getProjectIdFromUrl = (): string | null | undefined => { + if (typeof window !== 'undefined') { + const params = new URLSearchParams(window.location.search); + + return params.get('id'); + } + + return undefined; +}; diff --git a/src/models/projectSchema.ts b/src/models/projectSchema.ts index 517d7b0c..611b93a7 100644 --- a/src/models/projectSchema.ts +++ b/src/models/projectSchema.ts @@ -23,5 +23,5 @@ export const projectSchema = z.object({ creationDate: z.string(), mapCanvasType: z.string(), overviewImageViews: z.array(overviewImageView), - topOverviewImage: overviewImageView, + topOverviewImage: overviewImageView.nullable(), }); diff --git a/src/redux/overlays/overlays.thunks.ts b/src/redux/overlays/overlays.thunks.ts index 4b1fa460..67fd7b7d 100644 --- a/src/redux/overlays/overlays.thunks.ts +++ b/src/redux/overlays/overlays.thunks.ts @@ -14,6 +14,7 @@ import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; import { showToast } from '@/utils/showToast'; import { getErrorMessage } from '@/utils/getErrorMessage'; import { ThunkConfig } from '@/types/store'; +import { BASE_API_URL } from '@/constants'; import { apiPath } from '../apiPath'; import { CHUNK_SIZE, @@ -124,7 +125,7 @@ const uploadContent = async ({ createdFile, overlayContent }: UploadContentArgs) const chunk = data.slice(uploadedLength, uploadedLength + CHUNK_SIZE); const responeJSON = await fetch( - `${process.env.NEXT_PUBLIC_BASE_API_URL}/${apiPath.uploadOverlayFileContent(createdFile.id)}`, + `${BASE_API_URL}/${apiPath.uploadOverlayFileContent(createdFile.id)}`, { method: 'POST', credentials: 'include', diff --git a/src/redux/project/project.mock.ts b/src/redux/project/project.mock.ts index dada67e4..0b8da5ef 100644 --- a/src/redux/project/project.mock.ts +++ b/src/redux/project/project.mock.ts @@ -6,9 +6,10 @@ export const PROJECT_STATE_INITIAL_MOCK: ProjectState = { data: undefined, loading: 'idle', error: DEFAULT_ERROR, + projectId: '', }; -export const PROJECT_OVERVIEW_IMAGE_MOCK: OverviewImageView = { +export const PROJECT_OVERVIEW_IMAGE_MOCK: NonNullable<OverviewImageView> = { idObject: 440, filename: '9d4911bdeeea752f076e57a91d9b1f45/biolayout_main_root.png', width: 5776, diff --git a/src/redux/project/project.reducers.test.ts b/src/redux/project/project.reducers.test.ts index f3c00776..0521d9c2 100644 --- a/src/redux/project/project.reducers.test.ts +++ b/src/redux/project/project.reducers.test.ts @@ -17,6 +17,7 @@ const INITIAL_STATE: ProjectState = { data: undefined, loading: 'idle', error: { name: '', message: '' }, + projectId: '', }; describe('project reducer', () => { diff --git a/src/redux/project/project.reducers.ts b/src/redux/project/project.reducers.ts index 435d55e8..e022b8f8 100644 --- a/src/redux/project/project.reducers.ts +++ b/src/redux/project/project.reducers.ts @@ -1,4 +1,4 @@ -import { getProjectById } from '@/redux/project/project.thunks'; +import { getProjectById, setProjectId } from '@/redux/project/project.thunks'; import { ProjectState } from '@/redux/project/project.types'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; @@ -15,3 +15,9 @@ export const getProjectByIdReducer = (builder: ActionReducerMapBuilder<ProjectSt // TODO to discuss manage state of failure }); }; + +export const setProjectIdReducer = (builder: ActionReducerMapBuilder<ProjectState>): void => { + builder.addCase(setProjectId.fulfilled, (state, action) => { + state.projectId = action.payload; + }); +}; diff --git a/src/redux/project/project.selectors.ts b/src/redux/project/project.selectors.ts index 6ae2769e..aa0c62ae 100644 --- a/src/redux/project/project.selectors.ts +++ b/src/redux/project/project.selectors.ts @@ -10,7 +10,7 @@ export const projectDataSelector = createSelector(projectSelector, project => pr export const projectDefaultOverviewImageIdSelector = createSelector( projectDataSelector, - projectData => projectData?.topOverviewImage.idObject || OVERVIEW_IMAGE_ID_DEFAULT, + projectData => projectData?.topOverviewImage?.idObject || OVERVIEW_IMAGE_ID_DEFAULT, ); export const currentOverviewImageSelector = createSelector( @@ -63,3 +63,5 @@ export const organismNameSelector = createSelector( ); export const versionSelector = createSelector(projectDataSelector, state => state?.version); + +export const projectMainIdSelector = createSelector(projectSelector, project => project.projectId); diff --git a/src/redux/project/project.slice.ts b/src/redux/project/project.slice.ts index a6e0d9d0..6fb716ec 100644 --- a/src/redux/project/project.slice.ts +++ b/src/redux/project/project.slice.ts @@ -1,11 +1,12 @@ import { ProjectState } from '@/redux/project/project.types'; import { createSlice } from '@reduxjs/toolkit'; -import { getProjectByIdReducer } from './project.reducers'; +import { getProjectByIdReducer, setProjectIdReducer } from './project.reducers'; const initialState: ProjectState = { data: undefined, loading: 'idle', error: { name: '', message: '' }, + projectId: '', }; const projectSlice = createSlice({ @@ -14,6 +15,7 @@ const projectSlice = createSlice({ reducers: {}, extraReducers: builder => { getProjectByIdReducer(builder); + setProjectIdReducer(builder); }, }); diff --git a/src/redux/project/project.thunks.ts b/src/redux/project/project.thunks.ts index 2ef8de82..23a73a09 100644 --- a/src/redux/project/project.thunks.ts +++ b/src/redux/project/project.thunks.ts @@ -5,8 +5,10 @@ import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; import { createAsyncThunk } from '@reduxjs/toolkit'; import { getErrorMessage } from '@/utils/getErrorMessage'; import { ThunkConfig } from '@/types/store'; +import { DEFAULT_PROJECT_ID } from '@/constants'; import { apiPath } from '../apiPath'; import { PROJECT_FETCHING_ERROR_PREFIX } from './project.constants'; +import { SetProjectIdParams } from './project.types'; export const getProjectById = createAsyncThunk<Project | undefined, string, ThunkConfig>( 'project/getProjectById', @@ -23,3 +25,12 @@ export const getProjectById = createAsyncThunk<Project | undefined, string, Thun } }, ); + +export const setProjectId = createAsyncThunk<string, SetProjectIdParams, ThunkConfig>( + 'project/setProjectId', + async ({ queryData }) => { + const projectId = queryData?.id || DEFAULT_PROJECT_ID; + + return projectId; + }, +); diff --git a/src/redux/project/project.types.ts b/src/redux/project/project.types.ts index c92be2c4..df7dad10 100644 --- a/src/redux/project/project.types.ts +++ b/src/redux/project/project.types.ts @@ -1,8 +1,12 @@ import { Loading } from '@/types/loadingState'; import { Project } from '@/types/models'; +import { QueryData } from '@/types/query'; export type ProjectState = { + projectId: string; data: Project | undefined; loading: Loading; error: Error; }; + +export type SetProjectIdParams = { queryData: QueryData }; diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts index fc1c0f25..23aa9368 100644 --- a/src/redux/root/init.thunks.ts +++ b/src/redux/root/init.thunks.ts @@ -20,7 +20,7 @@ import { getAllUserOverlaysByCreator, } from '../overlays/overlays.thunks'; import { getAllPlugins, getInitPlugins } from '../plugins/plugins.thunks'; -import { getProjectById } from '../project/project.thunks'; +import { getProjectById, setProjectId } from '../project/project.thunks'; import { setPerfectMatch } from '../search/search.slice'; import { getSearchData } from '../search/search.thunks'; import { getStatisticsById } from '../statistics/statistics.thunks'; @@ -35,6 +35,8 @@ export const fetchInitialAppData = createAsyncThunk< InitializeAppParams, { dispatch: AppDispatch } >('appInit/fetchInitialAppData', async ({ queryData }, { dispatch }): Promise<void> => { + dispatch(setProjectId({ queryData })); + if (queryData.pluginsId) { await dispatch( getInitPlugins({ diff --git a/src/redux/root/query.selectors.ts b/src/redux/root/query.selectors.ts index b862ed42..8c4f1038 100644 --- a/src/redux/root/query.selectors.ts +++ b/src/redux/root/query.selectors.ts @@ -5,6 +5,7 @@ import { mapDataSelector } from '../map/map.selectors'; import { perfectMatchSelector, searchValueSelector } from '../search/search.selectors'; import { activeOverlaysIdSelector } from '../overlayBioEntity/overlayBioEntity.selector'; import { activePluginsIdSelector } from '../plugins/plugins.selectors'; +import { projectMainIdSelector } from '../project/project.selectors'; export const queryDataParamsSelector = createSelector( searchValueSelector, @@ -12,12 +13,14 @@ export const queryDataParamsSelector = createSelector( mapDataSelector, activeOverlaysIdSelector, activePluginsIdSelector, + projectMainIdSelector, ( searchValue, perfectMatch, { modelId, backgroundId, position }, activeOverlaysId, activePluginsId, + id, ): QueryDataParams => { const joinedSearchValue = searchValue.join(';'); const shouldIncludeSearchValue = searchValue.length > ZERO && joinedSearchValue; @@ -26,6 +29,7 @@ export const queryDataParamsSelector = createSelector( const shouldIncludePluginsId = activePluginsId.length > ZERO; const queryDataParams: QueryDataParams = { + id, perfectMatch, modelId, backgroundId, diff --git a/src/types/query.ts b/src/types/query.ts index be3453f0..e41e2520 100644 --- a/src/types/query.ts +++ b/src/types/query.ts @@ -1,6 +1,7 @@ import { Point } from './map'; export interface QueryData { + id?: string; searchValue?: string[]; perfectMatch: boolean; modelId?: number; @@ -11,6 +12,7 @@ export interface QueryData { } export interface QueryDataParams { + id?: string; searchValue?: string; perfectMatch: boolean; modelId?: number; @@ -23,6 +25,7 @@ export interface QueryDataParams { } export interface QueryDataRouterParams { + id?: string; searchValue?: string; perfectMatch?: string; modelId?: string; diff --git a/src/utils/parseQueryToTypes.ts b/src/utils/parseQueryToTypes.ts index f04abadf..5aebfe4a 100644 --- a/src/utils/parseQueryToTypes.ts +++ b/src/utils/parseQueryToTypes.ts @@ -1,6 +1,7 @@ import { QueryData, QueryDataRouterParams } from '@/types/query'; export const parseQueryToTypes = (query: QueryDataRouterParams): QueryData => ({ + id: query.id, searchValue: query.searchValue?.split(';'), perfectMatch: query?.perfectMatch === 'true' || false, modelId: Number(query.modelId) || undefined, diff --git a/src/utils/query-manager/useReduxBusQueryManager.test.ts b/src/utils/query-manager/useReduxBusQueryManager.test.ts index c77f8f3f..adecf259 100644 --- a/src/utils/query-manager/useReduxBusQueryManager.test.ts +++ b/src/utils/query-manager/useReduxBusQueryManager.test.ts @@ -48,6 +48,7 @@ describe('useReduxBusQueryManager - util', () => { project: { ...loadedDataMock, data: undefined, + projectId: '', }, map: { ...loadedDataMock, -- GitLab