From 7c753c8f900fabf7e2ec0eed6ac711d861374708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com> Date: Mon, 27 Nov 2023 02:12:29 +0100 Subject: [PATCH] feat: add display pins of categories + global search input --- .../TopBar/SearchBar/SearchBar.component.tsx | 19 +++++++-------- .../config/pinsLayer/useOlMapPinsLayer.ts | 12 ++++++++-- .../mapSingleClick/handleDataReset.test.ts | 12 +++++++--- .../mapSingleClick/handleDataReset.ts | 6 +++++ src/models/targetSchema.ts | 4 ++-- .../chemicals/chemicals.reducers.test.ts | 6 ++--- src/redux/chemicals/chemicals.reducers.ts | 7 +++++- src/redux/chemicals/chemicals.selectors.ts | 23 +++++++++++++++++-- src/redux/chemicals/chemicals.slice.ts | 12 ++++++++-- src/redux/chemicals/chemicals.thunks.test.ts | 4 ++-- src/redux/chemicals/chemicals.thunks.ts | 4 ++-- src/redux/drugs/drugs.reducers.test.ts | 12 +++++----- src/redux/drugs/drugs.reducers.ts | 7 +++++- src/redux/drugs/drugs.selectors.ts | 23 +++++++++++++++++-- src/redux/drugs/drugs.slice.ts | 10 +++++--- src/redux/drugs/drugs.thunks.test.ts | 10 ++++---- src/redux/drugs/drugs.thunks.ts | 14 ++++++----- src/redux/search/search.constants.ts | 8 +++++++ src/redux/search/search.mock.ts | 1 + src/redux/search/search.reducers.test.ts | 1 + src/redux/search/search.reducers.ts | 17 +++++++++++++- src/redux/search/search.selectors.ts | 2 ++ src/redux/search/search.slice.ts | 21 +++++++++-------- src/redux/search/search.types.ts | 4 ++++ 24 files changed, 175 insertions(+), 64 deletions(-) create mode 100644 src/redux/search/search.constants.ts diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx index 05231d6f..294f6fb6 100644 --- a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx @@ -5,12 +5,14 @@ import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { isPendingSearchStatusSelector, perfectMatchSelector, + searchInputSelector, } from '@/redux/search/search.selectors'; +import { setSearchInput } from '@/redux/search/search.slice'; import { getSearchData } from '@/redux/search/search.thunks'; import Image from 'next/image'; -import { ChangeEvent, KeyboardEvent, useEffect, useState } from 'react'; -import { useSelector } from 'react-redux'; import { useRouter } from 'next/router'; +import { ChangeEvent, KeyboardEvent } from 'react'; +import { useSelector } from 'react-redux'; import { getDefaultSearchTab, getSearchValuesArrayAndTrimToSeven } from './SearchBar.utils'; const ENTER_KEY_CODE = 'Enter'; @@ -19,24 +21,19 @@ export const SearchBar = (): JSX.Element => { const isPendingSearchStatus = useSelector(isPendingSearchStatusSelector); const isDrawerOpen = useSelector(isDrawerOpenSelector); const isPerfectMatch = useSelector(perfectMatchSelector); - const [searchValue, setSearchValue] = useState<string>(''); + const searchValue = useSelector(searchInputSelector); const dispatch = useAppDispatch(); const { query } = useRouter(); - useEffect(() => { - if (!searchValue && query.searchValue) { - setSearchValue(String(query.searchValue)); - } - }, [searchValue, query]); - const openSearchDrawerIfClosed = (defaultSearchTab: string): void => { if (!isDrawerOpen) { dispatch(openSearchDrawerWithSelectedTab(defaultSearchTab)); } }; - const onSearchChange = (event: ChangeEvent<HTMLInputElement>): void => - setSearchValue(event.target.value); + const onSearchChange = (event: ChangeEvent<HTMLInputElement>): void => { + dispatch(setSearchInput(event.target.value)); + }; const onSearchClick = (): void => { const searchValues = getSearchValuesArrayAndTrimToSeven(searchValue); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts index 6580ded5..0c2079d0 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts @@ -1,5 +1,7 @@ /* eslint-disable no-magic-numbers */ import { searchedBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors'; +import { searchedChemicalsBioEntitesOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors'; +import { searchedDrugsBioEntitesOfCurrentMapSelector } from '@/redux/drugs/drugs.selectors'; import { usePointToProjection } from '@/utils/map/usePointToProjection'; import BaseLayer from 'ol/layer/Base'; import VectorLayer from 'ol/layer/Vector'; @@ -11,11 +13,17 @@ import { getBioEntitiesFeatures } from './getBioEntitiesFeatures'; export const useOlMapPinsLayer = (): BaseLayer => { const pointToProjection = usePointToProjection(); const contentBioEntites = useSelector(searchedBioEntitesSelectorOfCurrentMap); + const chemicalsBioEntities = useSelector(searchedChemicalsBioEntitesOfCurrentMapSelector); + const drugsBioEntities = useSelector(searchedDrugsBioEntitesOfCurrentMapSelector); const bioEntityFeatures = useMemo( () => - [getBioEntitiesFeatures(contentBioEntites, { pointToProjection, type: 'bioEntity' })].flat(), - [contentBioEntites, pointToProjection], + [ + getBioEntitiesFeatures(contentBioEntites, { pointToProjection, type: 'bioEntity' }), + getBioEntitiesFeatures(chemicalsBioEntities, { pointToProjection, type: 'chemicals' }), + getBioEntitiesFeatures(drugsBioEntities, { pointToProjection, type: 'drugs' }), + ].flat(), + [contentBioEntites, drugsBioEntities, chemicalsBioEntities, pointToProjection], ); const vectorSource = useMemo(() => { diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts index f188b5fc..2cb880c6 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.test.ts @@ -1,4 +1,3 @@ -import { FIRST } from '@/constants/common'; import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; import { handleDataReset } from './handleDataReset'; @@ -6,10 +5,17 @@ describe('handleDataReset', () => { const { store } = getReduxStoreWithActionsListener(); const { dispatch } = store; - it('should dispatch resetReactionsData action', () => { + it('should dispatch reset actions', () => { dispatch(handleDataReset); const actions = store.getActions(); - expect(actions[FIRST].type).toBe('reactions/resetReactionsData'); + const actionsTypes = [ + 'reactions/resetReactionsData', + 'search/clearSearchData', + 'drugs/clearDrugsData', + 'chemicals/clearChemicalsData', + ]; + + expect(actions.map(a => a.type)).toStrictEqual(actionsTypes); }); }); diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts index 4d3e1d6d..1bc13bd1 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset.ts @@ -1,6 +1,12 @@ +import { clearChemicalsData } from '@/redux/chemicals/chemicals.slice'; +import { clearDrugsData } from '@/redux/drugs/drugs.slice'; import { resetReactionsData } from '@/redux/reactions/reactions.slice'; +import { clearSearchData } from '@/redux/search/search.slice'; import { AppDispatch } from '@/redux/store'; export const handleDataReset = (dispatch: AppDispatch): void => { dispatch(resetReactionsData()); + dispatch(clearSearchData()); + dispatch(clearDrugsData()); + dispatch(clearChemicalsData()); }; diff --git a/src/models/targetSchema.ts b/src/models/targetSchema.ts index bda0bfca..015626e1 100644 --- a/src/models/targetSchema.ts +++ b/src/models/targetSchema.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; +import { bioEntitySchema } from './bioEntitySchema'; import { referenceSchema } from './referenceSchema'; -import { targetElementSchema } from './targetElementSchema'; import { targetParticipantSchema } from './targetParticipantSchema'; export const targetSchema = z.object({ @@ -9,7 +9,7 @@ export const targetSchema = z.object({ /** list of target references */ references: z.array(referenceSchema), /** list of elements on the map associated with this target */ - targetElements: z.array(targetElementSchema), + targetElements: z.array(bioEntitySchema), /** list of identifiers associated with this target */ targetParticipants: z.array(targetParticipantSchema), }); diff --git a/src/redux/chemicals/chemicals.reducers.test.ts b/src/redux/chemicals/chemicals.reducers.test.ts index 0a990dc5..59a87b20 100644 --- a/src/redux/chemicals/chemicals.reducers.test.ts +++ b/src/redux/chemicals/chemicals.reducers.test.ts @@ -1,17 +1,17 @@ +import { DEFAULT_ERROR } from '@/constants/errors'; import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture'; import { apiPath } from '@/redux/apiPath'; -import { DEFAULT_ERROR } from '@/constants/errors'; import { ToolkitStoreWithSingleSlice, createStoreInstanceUsingSliceReducer, } from '@/utils/createStoreInstanceUsingSliceReducer'; -import { mockNetworkResponse } from '@/utils/mockNetworkResponse'; +import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; import { HttpStatusCode } from 'axios'; import chemicalsReducer from './chemicals.slice'; import { getChemicals } from './chemicals.thunks'; import { ChemicalsState } from './chemicals.types'; -const mockedAxiosClient = mockNetworkResponse(); +const mockedAxiosClient = mockNetworkNewAPIResponse(); const SEARCH_QUERY = 'Corticosterone'; const INITIAL_STATE: ChemicalsState = { diff --git a/src/redux/chemicals/chemicals.reducers.ts b/src/redux/chemicals/chemicals.reducers.ts index 5f7603f6..1034ead8 100644 --- a/src/redux/chemicals/chemicals.reducers.ts +++ b/src/redux/chemicals/chemicals.reducers.ts @@ -1,5 +1,5 @@ -import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; import { DEFAULT_ERROR } from '@/constants/errors'; +import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; import { getChemicals, getMultiChemicals } from './chemicals.thunks'; import { ChemicalsState } from './chemicals.types'; @@ -43,3 +43,8 @@ export const getMultiChemicalsReducer = ( // TODO: error management to be discussed in the team }); }; + +export const clearChemicalsDataReducer = (state: ChemicalsState): void => { + state.data = []; + state.loading = 'idle'; +}; diff --git a/src/redux/chemicals/chemicals.selectors.ts b/src/redux/chemicals/chemicals.selectors.ts index 09f59c72..f2d10808 100644 --- a/src/redux/chemicals/chemicals.selectors.ts +++ b/src/redux/chemicals/chemicals.selectors.ts @@ -1,9 +1,10 @@ import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; -import { Chemical } from '@/types/models'; -import { createSelector } from '@reduxjs/toolkit'; import { MultiSearchData } from '@/types/fetchDataState'; +import { BioEntity, Chemical } from '@/types/models'; +import { createSelector } from '@reduxjs/toolkit'; import { currentSelectedSearchElement } from '../drawer/drawer.selectors'; +import { currentModelIdSelector } from '../models/models.selectors'; export const chemicalsSelector = createSelector(rootSelector, state => state.chemicals); @@ -16,6 +17,24 @@ export const chemicalsForSelectedSearchElementSelector = createSelector( ), ); +export const searchedChemicalsBioEntitesOfCurrentMapSelector = createSelector( + chemicalsSelector, + currentSelectedSearchElement, + currentModelIdSelector, + (chemicalsState, currentSearchElement, currentModelId): BioEntity[] => { + return (chemicalsState?.data || []) + .filter(({ searchQueryElement }) => + currentSearchElement ? searchQueryElement === currentSearchElement : true, + ) + .map(({ data }) => data || []) + .flat() + .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) + .flat() + .flat() + .filter(bioEntity => bioEntity.model === currentModelId); + }, +); + export const loadingChemicalsStatusSelector = createSelector( chemicalsForSelectedSearchElementSelector, state => state?.loading, diff --git a/src/redux/chemicals/chemicals.slice.ts b/src/redux/chemicals/chemicals.slice.ts index 2528d4f2..6de994ae 100644 --- a/src/redux/chemicals/chemicals.slice.ts +++ b/src/redux/chemicals/chemicals.slice.ts @@ -1,6 +1,10 @@ import { ChemicalsState } from '@/redux/chemicals/chemicals.types'; import { createSlice } from '@reduxjs/toolkit'; -import { getChemicalsReducer, getMultiChemicalsReducer } from './chemicals.reducers'; +import { + clearChemicalsDataReducer, + getChemicalsReducer, + getMultiChemicalsReducer, +} from './chemicals.reducers'; const initialState: ChemicalsState = { data: [], @@ -11,11 +15,15 @@ const initialState: ChemicalsState = { export const chemicalsSlice = createSlice({ name: 'chemicals', initialState, - reducers: {}, + reducers: { + clearChemicalsData: clearChemicalsDataReducer, + }, extraReducers: builder => { getChemicalsReducer(builder); getMultiChemicalsReducer(builder); }, }); +export const { clearChemicalsData } = chemicalsSlice.actions; + export default chemicalsSlice.reducer; diff --git a/src/redux/chemicals/chemicals.thunks.test.ts b/src/redux/chemicals/chemicals.thunks.test.ts index 93945477..88926792 100644 --- a/src/redux/chemicals/chemicals.thunks.test.ts +++ b/src/redux/chemicals/chemicals.thunks.test.ts @@ -4,13 +4,13 @@ import { ToolkitStoreWithSingleSlice, createStoreInstanceUsingSliceReducer, } from '@/utils/createStoreInstanceUsingSliceReducer'; -import { mockNetworkResponse } from '@/utils/mockNetworkResponse'; +import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; import { HttpStatusCode } from 'axios'; import chemicalsReducer from './chemicals.slice'; import { getChemicals } from './chemicals.thunks'; import { ChemicalsState } from './chemicals.types'; -const mockedAxiosClient = mockNetworkResponse(); +const mockedAxiosClient = mockNetworkNewAPIResponse(); const SEARCH_QUERY = 'Corticosterone'; describe('chemicals thunks', () => { diff --git a/src/redux/chemicals/chemicals.thunks.ts b/src/redux/chemicals/chemicals.thunks.ts index 848ee24d..0afc94db 100644 --- a/src/redux/chemicals/chemicals.thunks.ts +++ b/src/redux/chemicals/chemicals.thunks.ts @@ -1,6 +1,6 @@ import { chemicalSchema } from '@/models/chemicalSchema'; import { apiPath } from '@/redux/apiPath'; -import { axiosInstance } from '@/services/api/utils/axiosInstance'; +import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; import { Chemical } from '@/types/models'; import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; import { createAsyncThunk } from '@reduxjs/toolkit'; @@ -9,7 +9,7 @@ import { z } from 'zod'; export const getChemicals = createAsyncThunk( 'project/getChemicals', async (searchQuery: string): Promise<Chemical[] | undefined> => { - const response = await axiosInstance.get<Chemical[]>( + const response = await axiosInstanceNewAPI.get<Chemical[]>( apiPath.getChemicalsStringWithQuery(searchQuery), ); diff --git a/src/redux/drugs/drugs.reducers.test.ts b/src/redux/drugs/drugs.reducers.test.ts index b0db33c1..3ad034db 100644 --- a/src/redux/drugs/drugs.reducers.test.ts +++ b/src/redux/drugs/drugs.reducers.test.ts @@ -1,17 +1,17 @@ -import { HttpStatusCode } from 'axios'; +import { DEFAULT_ERROR } from '@/constants/errors'; import { drugsFixture } from '@/models/fixtures/drugFixtures'; -import { mockNetworkResponse } from '@/utils/mockNetworkResponse'; +import { apiPath } from '@/redux/apiPath'; import { ToolkitStoreWithSingleSlice, createStoreInstanceUsingSliceReducer, } from '@/utils/createStoreInstanceUsingSliceReducer'; -import { DEFAULT_ERROR } from '@/constants/errors'; -import { apiPath } from '@/redux/apiPath'; -import { getDrugs } from './drugs.thunks'; +import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; +import { HttpStatusCode } from 'axios'; import drugsReducer from './drugs.slice'; +import { getDrugs } from './drugs.thunks'; import { DrugsState } from './drugs.types'; -const mockedAxiosClient = mockNetworkResponse(); +const mockedAxiosClient = mockNetworkNewAPIResponse(); const SEARCH_QUERY = 'aspirin'; const INITIAL_STATE: DrugsState = { diff --git a/src/redux/drugs/drugs.reducers.ts b/src/redux/drugs/drugs.reducers.ts index 4dcd353f..a3f83464 100644 --- a/src/redux/drugs/drugs.reducers.ts +++ b/src/redux/drugs/drugs.reducers.ts @@ -1,7 +1,7 @@ import { DEFAULT_ERROR } from '@/constants/errors'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; -import { DrugsState } from './drugs.types'; import { getDrugs, getMultiDrugs } from './drugs.thunks'; +import { DrugsState } from './drugs.types'; export const getDrugsReducer = (builder: ActionReducerMapBuilder<DrugsState>): void => { builder.addCase(getDrugs.pending, (state, action) => { @@ -41,3 +41,8 @@ export const getMultiDrugsReducer = (builder: ActionReducerMapBuilder<DrugsState // TODO: error management to be discussed in the team }); }; + +export const clearDrugsDataReducer = (state: DrugsState): void => { + state.data = []; + state.loading = 'idle'; +}; diff --git a/src/redux/drugs/drugs.selectors.ts b/src/redux/drugs/drugs.selectors.ts index 91cd3688..6790c081 100644 --- a/src/redux/drugs/drugs.selectors.ts +++ b/src/redux/drugs/drugs.selectors.ts @@ -1,9 +1,10 @@ import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; -import { createSelector } from '@reduxjs/toolkit'; import { MultiSearchData } from '@/types/fetchDataState'; -import { Drug } from '@/types/models'; +import { BioEntity, Drug } from '@/types/models'; +import { createSelector } from '@reduxjs/toolkit'; import { currentSelectedSearchElement } from '../drawer/drawer.selectors'; +import { currentModelIdSelector } from '../models/models.selectors'; export const drugsSelector = createSelector(rootSelector, state => state.drugs); @@ -29,3 +30,21 @@ export const numberOfDrugsSelector = createSelector( return state.data.length && state?.data.map(e => e.targets.length)?.reduce((a, b) => a + b); }, ); + +export const searchedDrugsBioEntitesOfCurrentMapSelector = createSelector( + drugsSelector, + currentSelectedSearchElement, + currentModelIdSelector, + (drugsState, currentSearchElement, currentModelId): BioEntity[] => { + return (drugsState?.data || []) + .filter(({ searchQueryElement }) => + currentSearchElement ? searchQueryElement === currentSearchElement : true, + ) + .map(({ data }) => data || []) + .flat() + .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) + .flat() + .flat() + .filter(bioEntity => bioEntity.model === currentModelId); + }, +); diff --git a/src/redux/drugs/drugs.slice.ts b/src/redux/drugs/drugs.slice.ts index 5d1a16e7..d7e8660d 100644 --- a/src/redux/drugs/drugs.slice.ts +++ b/src/redux/drugs/drugs.slice.ts @@ -1,6 +1,6 @@ -import { createSlice } from '@reduxjs/toolkit'; import { DrugsState } from '@/redux/drugs/drugs.types'; -import { getDrugsReducer, getMultiDrugsReducer } from './drugs.reducers'; +import { createSlice } from '@reduxjs/toolkit'; +import { clearDrugsDataReducer, getDrugsReducer, getMultiDrugsReducer } from './drugs.reducers'; const initialState: DrugsState = { data: [], @@ -11,11 +11,15 @@ const initialState: DrugsState = { export const drugsSlice = createSlice({ name: 'drugs', initialState, - reducers: {}, + reducers: { + clearDrugsData: clearDrugsDataReducer, + }, extraReducers: builder => { getDrugsReducer(builder); getMultiDrugsReducer(builder); }, }); +export const { clearDrugsData } = drugsSlice.actions; + export default drugsSlice.reducer; diff --git a/src/redux/drugs/drugs.thunks.test.ts b/src/redux/drugs/drugs.thunks.test.ts index 514ffccf..bb18ddf1 100644 --- a/src/redux/drugs/drugs.thunks.test.ts +++ b/src/redux/drugs/drugs.thunks.test.ts @@ -1,16 +1,16 @@ -import { HttpStatusCode } from 'axios'; import { drugsFixture } from '@/models/fixtures/drugFixtures'; -import { mockNetworkResponse } from '@/utils/mockNetworkResponse'; +import { apiPath } from '@/redux/apiPath'; import { ToolkitStoreWithSingleSlice, createStoreInstanceUsingSliceReducer, } from '@/utils/createStoreInstanceUsingSliceReducer'; -import { apiPath } from '@/redux/apiPath'; -import { getDrugs } from './drugs.thunks'; +import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; +import { HttpStatusCode } from 'axios'; import drugsReducer from './drugs.slice'; +import { getDrugs } from './drugs.thunks'; import { DrugsState } from './drugs.types'; -const mockedAxiosClient = mockNetworkResponse(); +const mockedAxiosClient = mockNetworkNewAPIResponse(); const SEARCH_QUERY = 'aspirin'; describe('drugs thunks', () => { diff --git a/src/redux/drugs/drugs.thunks.ts b/src/redux/drugs/drugs.thunks.ts index 1f3258be..30074e33 100644 --- a/src/redux/drugs/drugs.thunks.ts +++ b/src/redux/drugs/drugs.thunks.ts @@ -1,15 +1,17 @@ -import { z } from 'zod'; -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { axiosInstance } from '@/services/api/utils/axiosInstance'; -import { Drug } from '@/types/models'; import { drugSchema } from '@/models/drugSchema'; -import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; import { apiPath } from '@/redux/apiPath'; +import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; +import { Drug } from '@/types/models'; +import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { z } from 'zod'; export const getDrugs = createAsyncThunk( 'project/getDrugs', async (searchQuery: string): Promise<Drug[] | undefined> => { - const response = await axiosInstance.get<Drug[]>(apiPath.getDrugsStringWithQuery(searchQuery)); + const response = await axiosInstanceNewAPI.get<Drug[]>( + apiPath.getDrugsStringWithQuery(searchQuery), + ); const isDataValid = validateDataUsingZodSchema(response.data, z.array(drugSchema)); diff --git a/src/redux/search/search.constants.ts b/src/redux/search/search.constants.ts new file mode 100644 index 00000000..9a7afe4d --- /dev/null +++ b/src/redux/search/search.constants.ts @@ -0,0 +1,8 @@ +import { SearchState } from './search.types'; + +export const SEARCH_INITIAL_STATE: SearchState = { + searchInput: '', + searchValue: [''], + perfectMatch: false, + loading: 'idle', +}; diff --git a/src/redux/search/search.mock.ts b/src/redux/search/search.mock.ts index 16f5498f..d5e7cc4a 100644 --- a/src/redux/search/search.mock.ts +++ b/src/redux/search/search.mock.ts @@ -1,6 +1,7 @@ import { SearchState } from './search.types'; export const SEARCH_STATE_INITIAL_MOCK: SearchState = { + searchInput: '', searchValue: [''], perfectMatch: false, loading: 'idle', diff --git a/src/redux/search/search.reducers.test.ts b/src/redux/search/search.reducers.test.ts index 51bab3d5..76a76b3c 100644 --- a/src/redux/search/search.reducers.test.ts +++ b/src/redux/search/search.reducers.test.ts @@ -9,6 +9,7 @@ import searchReducer, { setPerfectMatch } from './search.slice'; const SEARCH_QUERY = ['Corticosterone']; const INITIAL_STATE: SearchState = { + searchInput: '', searchValue: [''], perfectMatch: false, loading: 'idle', diff --git a/src/redux/search/search.reducers.ts b/src/redux/search/search.reducers.ts index d4e555cd..48353721 100644 --- a/src/redux/search/search.reducers.ts +++ b/src/redux/search/search.reducers.ts @@ -1,10 +1,16 @@ // updating state import { getSearchData } from '@/redux/search/search.thunks'; -import { SearchState, SetPerfectMatchAction } from '@/redux/search/search.types'; +import { + SearchState, + SetPerfectMatchAction, + SetSearchInputAction, +} from '@/redux/search/search.types'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; +import { SEARCH_INITIAL_STATE } from './search.constants'; export const getSearchDataReducer = (builder: ActionReducerMapBuilder<SearchState>): void => { builder.addCase(getSearchData.pending, (state, action) => { + state.searchInput = action.meta.arg.searchQueries.join(';'); state.searchValue = action.meta.arg.searchQueries; state.perfectMatch = action.meta.arg.isPerfectMatch; state.loading = 'pending'; @@ -21,3 +27,12 @@ export const getSearchDataReducer = (builder: ActionReducerMapBuilder<SearchStat export const setPerfectMatchReducer = (state: SearchState, action: SetPerfectMatchAction): void => { state.perfectMatch = action.payload; }; + +export const setSearchInputReducer = (state: SearchState, action: SetSearchInputAction): void => { + state.searchInput = action.payload; +}; + +export const clearSearchDataReducer = (state: SearchState): void => { + state.searchValue = SEARCH_INITIAL_STATE.searchValue; + state.loading = SEARCH_INITIAL_STATE.loading; +}; diff --git a/src/redux/search/search.selectors.ts b/src/redux/search/search.selectors.ts index f2c3b256..0add08e0 100644 --- a/src/redux/search/search.selectors.ts +++ b/src/redux/search/search.selectors.ts @@ -15,3 +15,5 @@ export const isPendingSearchStatusSelector = createSelector( ); export const perfectMatchSelector = createSelector(searchSelector, state => state.perfectMatch); + +export const searchInputSelector = createSelector(searchSelector, state => state.searchInput); diff --git a/src/redux/search/search.slice.ts b/src/redux/search/search.slice.ts index 08223dc6..f746f06e 100644 --- a/src/redux/search/search.slice.ts +++ b/src/redux/search/search.slice.ts @@ -1,24 +1,25 @@ -import { getSearchDataReducer, setPerfectMatchReducer } from '@/redux/search/search.reducers'; -import { SearchState } from '@/redux/search/search.types'; +import { + clearSearchDataReducer, + getSearchDataReducer, + setPerfectMatchReducer, + setSearchInputReducer, +} from '@/redux/search/search.reducers'; import { createSlice } from '@reduxjs/toolkit'; - -const initialState: SearchState = { - searchValue: [''], - perfectMatch: false, - loading: 'idle', -}; +import { SEARCH_INITIAL_STATE } from './search.constants'; export const searchSlice = createSlice({ name: 'search', - initialState, + initialState: SEARCH_INITIAL_STATE, reducers: { setPerfectMatch: setPerfectMatchReducer, + setSearchInput: setSearchInputReducer, + clearSearchData: clearSearchDataReducer, }, extraReducers(builder) { getSearchDataReducer(builder); }, }); -export const { setPerfectMatch } = searchSlice.actions; +export const { setPerfectMatch, setSearchInput, clearSearchData } = searchSlice.actions; export default searchSlice.reducer; diff --git a/src/redux/search/search.types.ts b/src/redux/search/search.types.ts index 9525aa08..dfb86854 100644 --- a/src/redux/search/search.types.ts +++ b/src/redux/search/search.types.ts @@ -2,6 +2,7 @@ import { Loading } from '@/types/loadingState'; import { PayloadAction } from '@reduxjs/toolkit'; export interface SearchState { + searchInput: string; searchValue: string[]; perfectMatch: boolean; loading: Loading; @@ -9,3 +10,6 @@ export interface SearchState { export type SetPerfectMatchPayload = boolean; export type SetPerfectMatchAction = PayloadAction<SetPerfectMatchPayload>; + +export type SetSearchInputPayload = string; +export type SetSearchInputAction = PayloadAction<SetSearchInputPayload>; -- GitLab