From 02c814f1b0d82e695bf166e356ba86418c585890 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <p.gawron@atcomp.pl> Date: Wed, 4 Sep 2024 11:31:22 +0200 Subject: [PATCH] include drug and chemical autocomplete --- .../TopBar/SearchBar/SearchBar.component.tsx | 19 ++++++--- .../TopBar/TopBar.component.test.tsx | 4 ++ src/redux/apiPath.ts | 2 + .../autocomplete/autocomplete.reducers.ts | 38 +++++++++++++++++- .../autocomplete/autocomplete.selectors.ts | 10 +++++ src/redux/autocomplete/autocomplete.slice.ts | 30 +++++++++++++- src/redux/autocomplete/autocomplete.thunks.ts | 40 +++++++++++++++++++ src/redux/root/init.thunks.ts | 8 +++- src/redux/root/root.fixtures.ts | 2 + src/redux/store.ts | 8 +++- 10 files changed, 150 insertions(+), 11 deletions(-) diff --git a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx index b1dda904..fc28ddc3 100644 --- a/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx +++ b/src/components/FunctionalArea/TopBar/SearchBar/SearchBar.component.tsx @@ -1,4 +1,8 @@ -import { autocompleteSearchSelector } from '@/redux/autocomplete/autocomplete.selectors'; +import { + autocompleteChemicalSelector, + autocompleteDrugSelector, + autocompleteSearchSelector, +} from '@/redux/autocomplete/autocomplete.selectors'; import { currentSelectedSearchElement, searchDrawerOpenSelector, @@ -37,6 +41,8 @@ export const SearchBar = (): JSX.Element => { const isPerfectMatch = useSelector(perfectMatchSelector); const searchValueState = useSelector(searchValueSelector); const searchAutocompleteState = useSelector(autocompleteSearchSelector); + const drugAutocompleteState = useSelector(autocompleteDrugSelector); + const chemicalAutocompleteState = useSelector(autocompleteChemicalSelector); const dispatch = useAppDispatch(); const router = useRouter(); const currentTab = useSelector(currentSelectedSearchElement); @@ -87,11 +93,12 @@ export const SearchBar = (): JSX.Element => { openSearchDrawerIfClosed(currentTab); }; - // eslint-disable-next-line no-console - console.log(searchAutocompleteState.searchValues); - const suggestions = searchAutocompleteState.searchValues.map(entry => { - return { name: entry }; - }); + const suggestions = searchAutocompleteState.searchValues + .concat(drugAutocompleteState.searchValues, chemicalAutocompleteState.searchValues) + .map(entry => { + return { name: entry }; + }) + .sort((a: Suggestion, b: Suggestion) => a.name.localeCompare(b.name)); const getSuggestions = (value: string): Suggestion[] => { const inputValue = value.trim().toLowerCase(); diff --git a/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx b/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx index 83958538..0fb61179 100644 --- a/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx +++ b/src/components/FunctionalArea/TopBar/TopBar.component.test.tsx @@ -119,6 +119,8 @@ describe('TopBar - component', () => { map: initialMapStateFixture, search: SEARCH_STATE_INITIAL_MOCK, autocompleteSearch: AUTOCOMPLETE_INITIAL_STATE, + autocompleteDrug: AUTOCOMPLETE_INITIAL_STATE, + autocompleteChemical: AUTOCOMPLETE_INITIAL_STATE, backgrounds: { ...BACKGROUND_INITIAL_STATE_MOCK, data: BACKGROUNDS_MOCK }, }); @@ -136,6 +138,8 @@ describe('TopBar - component', () => { user: USER_INITIAL_STATE_MOCK, search: SEARCH_STATE_INITIAL_MOCK, autocompleteSearch: AUTOCOMPLETE_INITIAL_STATE, + autocompleteDrug: AUTOCOMPLETE_INITIAL_STATE, + autocompleteChemical: AUTOCOMPLETE_INITIAL_STATE, drawer: initialStateFixture, project: { ...PROJECT_STATE_INITIAL_MOCK, diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index b8002874..423aefbf 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -112,4 +112,6 @@ export const apiPath = { getSearchAutocomplete: (): string => `projects/${PROJECT_ID}/models/*/bioEntities/suggestedQueryList`, + getDrugAutocomplete: (): string => `projects/${PROJECT_ID}/drugs/suggestedQueryList`, + getChemicalAutocomplete: (): string => `projects/${PROJECT_ID}/chemicals/suggestedQueryList`, }; diff --git a/src/redux/autocomplete/autocomplete.reducers.ts b/src/redux/autocomplete/autocomplete.reducers.ts index 8fb6ce0e..a36fa9a3 100644 --- a/src/redux/autocomplete/autocomplete.reducers.ts +++ b/src/redux/autocomplete/autocomplete.reducers.ts @@ -1,6 +1,10 @@ import { AutocompleteState } from '@/redux/autocomplete/autocomplete.types'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; -import { getSearchAutocomplete } from '@/redux/autocomplete/autocomplete.thunks'; +import { + getChemicalAutocomplete, + getDrugAutocomplete, + getSearchAutocomplete, +} from '@/redux/autocomplete/autocomplete.thunks'; export const getSearchAutocompleteReducer = ( builder: ActionReducerMapBuilder<AutocompleteState>, @@ -17,3 +21,35 @@ export const getSearchAutocompleteReducer = ( // TODO: error management to be discussed in the team }); }; + +export const getDrugAutocompleteReducer = ( + builder: ActionReducerMapBuilder<AutocompleteState>, +): void => { + builder.addCase(getDrugAutocomplete.pending, state => { + state.loading = 'pending'; + }); + builder.addCase(getDrugAutocomplete.fulfilled, (state, action) => { + state.searchValues = action.payload ? action.payload : []; + state.loading = 'succeeded'; + }); + builder.addCase(getDrugAutocomplete.rejected, state => { + state.loading = 'failed'; + // TODO: error management to be discussed in the team + }); +}; + +export const getChemicalAutocompleteReducer = ( + builder: ActionReducerMapBuilder<AutocompleteState>, +): void => { + builder.addCase(getChemicalAutocomplete.pending, state => { + state.loading = 'pending'; + }); + builder.addCase(getChemicalAutocomplete.fulfilled, (state, action) => { + state.searchValues = action.payload ? action.payload : []; + state.loading = 'succeeded'; + }); + builder.addCase(getChemicalAutocomplete.rejected, state => { + state.loading = 'failed'; + // TODO: error management to be discussed in the team + }); +}; diff --git a/src/redux/autocomplete/autocomplete.selectors.ts b/src/redux/autocomplete/autocomplete.selectors.ts index c6f1f6ae..d1ee002a 100644 --- a/src/redux/autocomplete/autocomplete.selectors.ts +++ b/src/redux/autocomplete/autocomplete.selectors.ts @@ -5,3 +5,13 @@ export const autocompleteSearchSelector = createSelector( rootSelector, state => state.autocompleteSearch, ); + +export const autocompleteDrugSelector = createSelector( + rootSelector, + state => state.autocompleteDrug, +); + +export const autocompleteChemicalSelector = createSelector( + rootSelector, + state => state.autocompleteChemical, +); diff --git a/src/redux/autocomplete/autocomplete.slice.ts b/src/redux/autocomplete/autocomplete.slice.ts index ab28dbc6..6d042065 100644 --- a/src/redux/autocomplete/autocomplete.slice.ts +++ b/src/redux/autocomplete/autocomplete.slice.ts @@ -1,9 +1,13 @@ import { createSlice } from '@reduxjs/toolkit'; import { AUTOCOMPLETE_INITIAL_STATE } from '@/redux/autocomplete/autocomplete.constants'; -import { getSearchAutocompleteReducer } from '@/redux/autocomplete/autocomplete.reducers'; +import { + getChemicalAutocompleteReducer, + getDrugAutocompleteReducer, + getSearchAutocompleteReducer, +} from '@/redux/autocomplete/autocomplete.reducers'; export const autocompleteSearchSlice = createSlice({ - name: 'autocomplete', + name: 'autocompleteSearch', initialState: AUTOCOMPLETE_INITIAL_STATE, reducers: {}, extraReducers(builder) { @@ -12,3 +16,25 @@ export const autocompleteSearchSlice = createSlice({ }); export const autocompleteSearchReducer = autocompleteSearchSlice.reducer; + +export const autocompleteDrugSlice = createSlice({ + name: 'autocompleteDrug', + initialState: AUTOCOMPLETE_INITIAL_STATE, + reducers: {}, + extraReducers(builder) { + getDrugAutocompleteReducer(builder); + }, +}); + +export const autocompleteDrugReducer = autocompleteDrugSlice.reducer; + +export const autocompleteChemicalSlice = createSlice({ + name: 'autocompleteChemical', + initialState: AUTOCOMPLETE_INITIAL_STATE, + reducers: {}, + extraReducers(builder) { + getChemicalAutocompleteReducer(builder); + }, +}); + +export const autocompleteChemicalReducer = autocompleteChemicalSlice.reducer; diff --git a/src/redux/autocomplete/autocomplete.thunks.ts b/src/redux/autocomplete/autocomplete.thunks.ts index 6397ea42..d9204b9e 100644 --- a/src/redux/autocomplete/autocomplete.thunks.ts +++ b/src/redux/autocomplete/autocomplete.thunks.ts @@ -26,3 +26,43 @@ export const getSearchAutocomplete = createAsyncThunk< } }, ); + +export const getDrugAutocomplete = createAsyncThunk< + string[] | undefined, + void, + { state: RootState } & ThunkConfig +>( + 'project/getDrugAutocomplete', + // eslint-disable-next-line consistent-return + async () => { + try { + const response = await axiosInstance.get<string[]>(apiPath.getDrugAutocomplete()); + + const isDataValid = validateDataUsingZodSchema(response.data, autocompleteSchema); + + return isDataValid ? response.data : undefined; + } catch (error) { + return Promise.reject(getError({ error })); + } + }, +); + +export const getChemicalAutocomplete = createAsyncThunk< + string[] | undefined, + void, + { state: RootState } & ThunkConfig +>( + 'project/getChemicalAutocomplete', + // eslint-disable-next-line consistent-return + async () => { + try { + const response = await axiosInstance.get<string[]>(apiPath.getChemicalAutocomplete()); + + const isDataValid = validateDataUsingZodSchema(response.data, autocompleteSchema); + + return isDataValid ? response.data : undefined; + } catch (error) { + return Promise.reject(getError({ error })); + } + }, +); diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts index 476e5b40..9387f79c 100644 --- a/src/redux/root/init.thunks.ts +++ b/src/redux/root/init.thunks.ts @@ -7,7 +7,11 @@ import { PluginsManager } from '@/services/pluginsManager'; import { createAsyncThunk } from '@reduxjs/toolkit'; import { ZERO } from '@/constants/common'; import { getConstant } from '@/redux/constant/constant.thunks'; -import { getSearchAutocomplete } from '@/redux/autocomplete/autocomplete.thunks'; +import { + getChemicalAutocomplete, + getDrugAutocomplete, + getSearchAutocomplete, +} from '@/redux/autocomplete/autocomplete.thunks'; import { getAllBackgroundsByProjectId } from '../backgrounds/backgrounds.thunks'; import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks'; import { @@ -89,6 +93,8 @@ export const fetchInitialAppData = createAsyncThunk< // autocomplete dispatch(getSearchAutocomplete()); + dispatch(getDrugAutocomplete()); + dispatch(getChemicalAutocomplete()); /** Trigger search */ if (queryData.searchValue) { diff --git a/src/redux/root/root.fixtures.ts b/src/redux/root/root.fixtures.ts index 5f116bc5..e260f230 100644 --- a/src/redux/root/root.fixtures.ts +++ b/src/redux/root/root.fixtures.ts @@ -32,6 +32,8 @@ import { USER_INITIAL_STATE_MOCK } from '../user/user.mock'; export const INITIAL_STORE_STATE_MOCK: RootState = { autocompleteSearch: AUTOCOMPLETE_INITIAL_STATE, + autocompleteDrug: AUTOCOMPLETE_INITIAL_STATE, + autocompleteChemical: AUTOCOMPLETE_INITIAL_STATE, search: SEARCH_STATE_INITIAL_MOCK, project: PROJECT_STATE_INITIAL_MOCK, projects: PROJECTS_STATE_INITIAL_MOCK, diff --git a/src/redux/store.ts b/src/redux/store.ts index a5c2daea..f11f6e57 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -18,7 +18,11 @@ import projectsReducer from '@/redux/projects/projects.slice'; import reactionsReducer from '@/redux/reactions/reactions.slice'; import searchReducer from '@/redux/search/search.slice'; import userReducer from '@/redux/user/user.slice'; -import { autocompleteSearchReducer } from '@/redux/autocomplete/autocomplete.slice'; +import { + autocompleteChemicalReducer, + autocompleteDrugReducer, + autocompleteSearchReducer, +} from '@/redux/autocomplete/autocomplete.slice'; import { AnyAction, ListenerEffectAPI, @@ -40,6 +44,8 @@ import statisticsReducer from './statistics/statistics.slice'; export const reducers = { autocompleteSearch: autocompleteSearchReducer, + autocompleteDrug: autocompleteDrugReducer, + autocompleteChemical: autocompleteChemicalReducer, search: searchReducer, project: projectReducer, projects: projectsReducer, -- GitLab