diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx index 685bfdbdd59f2948df45081a45e3eb95d35517a5..a1bec280f9de88ba0b354c552d180ac34f3e16dd 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx @@ -1,12 +1,16 @@ +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { MODELS_MOCK } from '@/models/mocks/modelsMock'; -import { StoreType } from '@/redux/store'; +import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; +import { AppDispatch, RootState, StoreType } from '@/redux/store'; import { Accordion } from '@/shared/Accordion'; +import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; import { InitialStoreState, getReduxWrapperWithStore, } from '@/utils/testing/getReduxWrapperWithStore'; import { render, screen } from '@testing-library/react'; +import { MockStoreEnhanced } from 'redux-mock-store'; import { BioEntitiesAccordion } from './BioEntitiesAccordion.component'; const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { @@ -26,6 +30,25 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St ); }; +const renderComponentWithActionListener = ( + initialStoreState: InitialStoreState = {}, +): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => { + const { Wrapper, store } = getReduxStoreWithActionsListener(initialStoreState); + + return ( + render( + <Wrapper> + <Accordion> + <BioEntitiesAccordion /> + </Accordion> + </Wrapper>, + ), + { + store, + } + ); +}; + describe('BioEntitiesAccordion - component', () => { it('should display loading indicator when bioEntity search is pending', () => { renderComponent({ @@ -77,4 +100,36 @@ describe('BioEntitiesAccordion - component', () => { expect(screen.getByText('Histamine signaling (4)')).toBeInTheDocument(); expect(screen.getByText('PRKN substrates (3)')).toBeInTheDocument(); }); + + it('should fire toggleIsContentTabOpened on accordion item button click', () => { + const { store } = renderComponentWithActionListener({ + ...INITIAL_STORE_STATE_MOCK, + bioEntity: { + data: [ + { + searchQueryElement: '', + loading: 'succeeded', + error: { name: '', message: '' }, + data: bioEntitiesContentFixture, + }, + ], + loading: 'succeeded', + error: { name: '', message: '' }, + isContentTabOpened: false, + }, + models: { + data: MODELS_MOCK, + loading: 'succeeded', + error: { name: '', message: '' }, + }, + }); + + const button = screen.getByTestId('accordion-item-button'); + + button.click(); + expect(store.getActions()[FIRST_ARRAY_ELEMENT]).toStrictEqual({ + payload: true, + type: 'bioEntityContents/toggleIsContentTabOpened', + }); + }); }); diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx index 1024d202c3dc1a87049b026891c3c27d6572d4e6..8754b663a1c714f0f8e3e4740ae012bc23c0ab3c 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx @@ -1,26 +1,35 @@ +import { + bioEntitiesPerModelSelector, + bioEntityIsContentTabOpenedSelector, + loadingBioEntityStatusSelector, + numberOfBioEntitiesSelector, +} from '@/redux/bioEntity/bioEntity.selectors'; +import { toggleIsContentTabOpened } from '@/redux/bioEntity/bioEntity.slice'; +import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { AccordionItem, AccordionItemButton, - AccordionItemPanel, AccordionItemHeading, + AccordionItemPanel, } from '@/shared/Accordion'; -import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { - loadingBioEntityStatusSelector, - bioEntitiesPerModelSelector, - numberOfBioEntitiesSelector, -} from '@/redux/bioEntity/bioEntity.selectors'; import { BioEntitiesSubmapItem } from './BioEntitiesSubmapItem'; export const BioEntitiesAccordion = (): JSX.Element => { + const dispatch = useAppDispatch(); const bioEntitiesNumber = useAppSelector(numberOfBioEntitiesSelector); const bioEntitiesState = useAppSelector(loadingBioEntityStatusSelector); const bioEntitiesPerModel = useAppSelector(bioEntitiesPerModelSelector); + const isContentTabOpened = useAppSelector(bioEntityIsContentTabOpenedSelector); + + const toggleTabOpened = (): void => { + dispatch(toggleIsContentTabOpened(!isContentTabOpened)); + }; return ( - <AccordionItem> + <AccordionItem dangerouslySetExpanded={isContentTabOpened}> <AccordionItemHeading> - <AccordionItemButton> + <AccordionItemButton onClick={toggleTabOpened}> Content {bioEntitiesState === 'pending' && ' (Loading...)'} {bioEntitiesState === 'succeeded' && ` (${bioEntitiesNumber})`} </AccordionItemButton> diff --git a/src/redux/bioEntity/bioEntity.constants.ts b/src/redux/bioEntity/bioEntity.constants.ts index 14f1bdc1ad572a72495c24393fb65f0c2276f94c..b267180f2c4cc9dbc46f9436eda4d6547da8796a 100644 --- a/src/redux/bioEntity/bioEntity.constants.ts +++ b/src/redux/bioEntity/bioEntity.constants.ts @@ -20,4 +20,5 @@ export const BIOENTITY_INITIAL_STATE: BioEntityContentsState = { loading: 'idle', error: { name: '', message: '' }, submapConnections: BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, + isContentTabOpened: false, }; diff --git a/src/redux/bioEntity/bioEntity.reducers.test.ts b/src/redux/bioEntity/bioEntity.reducers.test.ts index 07af4ebe2cc8d18f49b353fe759039125617c1cf..8fa2002f40d92211b93a63ff3f013c91560dc03a 100644 --- a/src/redux/bioEntity/bioEntity.reducers.test.ts +++ b/src/redux/bioEntity/bioEntity.reducers.test.ts @@ -6,8 +6,8 @@ import { createStoreInstanceUsingSliceReducer, } from '@/utils/createStoreInstanceUsingSliceReducer'; import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; -import { HttpStatusCode } from 'axios'; import { unwrapResult } from '@reduxjs/toolkit'; +import { HttpStatusCode } from 'axios'; import bioEntityContentsReducer from './bioEntity.slice'; import { getBioEntity } from './bioEntity.thunks'; import { BioEntityContentsState } from './bioEntity.types'; @@ -20,6 +20,7 @@ jest.mock('../../utils/error-report/errorReporting'); const INITIAL_STATE: BioEntityContentsState = { data: [], loading: 'idle', + isContentTabOpened: false, error: { name: '', message: '' }, submapConnections: { data: [], diff --git a/src/redux/bioEntity/bioEntity.reducers.ts b/src/redux/bioEntity/bioEntity.reducers.ts index fb6f1d36efc67b164f595a37de24a026984ec283..46892945a2d1221206680c947b8fd8398b225fe7 100644 --- a/src/redux/bioEntity/bioEntity.reducers.ts +++ b/src/redux/bioEntity/bioEntity.reducers.ts @@ -1,5 +1,5 @@ import { DEFAULT_ERROR } from '@/constants/errors'; -import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; +import { ActionReducerMapBuilder, PayloadAction } from '@reduxjs/toolkit'; import { BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE } from './bioEntity.constants'; import { getBioEntity, getMultiBioEntity } from './bioEntity.thunks'; import { BioEntityContentsState } from './bioEntity.types'; @@ -86,3 +86,10 @@ export const clearBioEntitiesDataReducer = (state: BioEntityContentsState): void state.submapConnections = BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE; }; + +export const toggleIsContentTabOpenedReducer = ( + state: BioEntityContentsState, + action: PayloadAction<boolean>, +): void => { + state.isContentTabOpened = action.payload; +}; diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts index 778d123b47fbace3b0a6f863bdf791599f26d096..ee3b893c71f2dfa198c35186f7cd541a8bb45332 100644 --- a/src/redux/bioEntity/bioEntity.selectors.ts +++ b/src/redux/bioEntity/bioEntity.selectors.ts @@ -1,15 +1,15 @@ -import { rootSelector } from '@/redux/root/root.selectors'; import { ONE, SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common'; -import { BioEntityWithPinType } from '@/types/bioEntity'; -import { ElementIdTabObj } from '@/types/elements'; -import { MultiSearchData } from '@/types/fetchDataState'; -import { BioEntity, BioEntityContent, Comment, MapModel } from '@/types/models'; -import { createSelector } from '@reduxjs/toolkit'; import { allCommentsSelectorOfCurrentMap, commentElementSelector, } from '@/redux/comment/comment.selectors'; import { currentDrawerReactionSelector } from '@/redux/reactions/reactions.selector'; +import { rootSelector } from '@/redux/root/root.selectors'; +import { BioEntityWithPinType } from '@/types/bioEntity'; +import { ElementIdTabObj } from '@/types/elements'; +import { MultiSearchData } from '@/types/fetchDataState'; +import { BioEntity, BioEntityContent, Comment, MapModel } from '@/types/models'; +import { createSelector } from '@reduxjs/toolkit'; import { allChemicalsBioEntitesOfAllMapsSelector, allChemicalsBioEntitesOfCurrentMapSelector, @@ -35,6 +35,11 @@ export const bioEntitySelector = createSelector(rootSelector, state => state.bio export const bioEntityDataSelector = createSelector(bioEntitySelector, bioEntity => bioEntity.data); +export const bioEntityIsContentTabOpenedSelector = createSelector( + bioEntitySelector, + bioEntity => bioEntity.isContentTabOpened, +); + export const bioEntityLoadingSelector = createSelector( bioEntitySelector, bioEntity => bioEntity.loading, diff --git a/src/redux/bioEntity/bioEntity.slice.ts b/src/redux/bioEntity/bioEntity.slice.ts index 55d1c4ae344fa00d627447482ef60ba0dee58b1a..728467a93a220932df93ba7ed498e42184895c2f 100644 --- a/src/redux/bioEntity/bioEntity.slice.ts +++ b/src/redux/bioEntity/bioEntity.slice.ts @@ -5,6 +5,7 @@ import { getBioEntityContentsReducer, getMultiBioEntityContentsReducer, getSubmapConnectionsBioEntityReducer, + toggleIsContentTabOpenedReducer, } from './bioEntity.reducers'; export const bioEntityContentsSlice = createSlice({ @@ -12,6 +13,7 @@ export const bioEntityContentsSlice = createSlice({ initialState: BIOENTITY_INITIAL_STATE, reducers: { clearBioEntitiesData: clearBioEntitiesDataReducer, + toggleIsContentTabOpened: toggleIsContentTabOpenedReducer, }, extraReducers: builder => { getBioEntityContentsReducer(builder); @@ -20,6 +22,6 @@ export const bioEntityContentsSlice = createSlice({ }, }); -export const { clearBioEntitiesData } = bioEntityContentsSlice.actions; +export const { clearBioEntitiesData, toggleIsContentTabOpened } = bioEntityContentsSlice.actions; export default bioEntityContentsSlice.reducer; diff --git a/src/redux/bioEntity/bioEntity.types.ts b/src/redux/bioEntity/bioEntity.types.ts index 65e8d8aa8997240924ed10d851058d45126b6a98..11c3418fac7c70bd76ce4c2554fad6cfb27722e5 100644 --- a/src/redux/bioEntity/bioEntity.types.ts +++ b/src/redux/bioEntity/bioEntity.types.ts @@ -4,6 +4,7 @@ import { PayloadAction } from '@reduxjs/toolkit'; export type BioEntityContentsState = MultiFetchDataState<BioEntityContent[]> & { submapConnections?: FetchDataState<BioEntityContent[]>; + isContentTabOpened?: boolean; }; export type BioEntityContentSearchQuery = {