From cd14e79ab4024b3b852df8ae8afa5f90ebed4833 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadeusz=20Miesi=C4=85c?= <tadeusz.miesiac@gmail.com>
Date: Mon, 16 Oct 2023 18:07:36 +0800
Subject: [PATCH] feat(chemicals,mirna accordion): added chemicals and mirna
 accordion

---
 .../ChemicalsAccordion.component.test.tsx     | 41 +++++++++++++++++
 .../ChemicalsAccordion.component.tsx          | 23 ++++++++++
 .../ChemicalsAccordion/index.ts               |  1 +
 .../MirnaAccordion.component.test.tsx         | 41 +++++++++++++++++
 .../MirnaAccordion.component.tsx              | 23 ++++++++++
 .../MirnaAccordion/index.ts                   |  1 +
 .../SearchDrawerContent.component.tsx         |  4 ++
 src/redux/chemicals/chemicals.selectors.ts    |  6 +++
 src/redux/mirnas/mirnas.selectors.ts          |  5 ++
 src/redux/store.ts                            |  1 -
 ...erHeadingBackwardButton.component.test.tsx | 11 +++--
 src/utils/getReduxWrapperWithStore.tsx        | 46 -------------------
 .../testing/getReduxWrapperWithStore.tsx      | 23 ++--------
 13 files changed, 157 insertions(+), 69 deletions(-)
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.test.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/index.ts
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.test.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/index.ts
 delete mode 100644 src/utils/getReduxWrapperWithStore.tsx

diff --git a/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.test.tsx
new file mode 100644
index 00000000..c8a4826a
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.test.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from '@testing-library/react';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture';
+import { Accordion } from '@/shared/Accordion';
+import { ChemicalsAccordion } from './ChemicalsAccordion.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Accordion>
+          <ChemicalsAccordion />
+        </Accordion>
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('DrugsAccordion - component', () => {
+  it('should display drugs number after succesfull chemicals search', () => {
+    renderComponent({
+      chemicals: { data: chemicalsFixture, loading: 'succeeded', error: { name: '', message: '' } },
+    });
+    expect(screen.getByText('Chemicals (2)')).toBeInTheDocument();
+  });
+  it('should display loading indicator while waiting for chemicals search response', () => {
+    renderComponent({
+      chemicals: { data: [], loading: 'pending', error: { name: '', message: '' } },
+    });
+    expect(screen.getByText('Chemicals (Loading...)')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.tsx b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.tsx
new file mode 100644
index 00000000..46ee6f78
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/ChemicalsAccordion.component.tsx
@@ -0,0 +1,23 @@
+import {
+  numberOfChemicalsSelector,
+  loadingChemicalsStatusSelector,
+} from '@/redux/chemicals/chemicals.selectors';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { AccordionItem, AccordionItemHeading, AccordionItemButton } from '@/shared/Accordion';
+
+export const ChemicalsAccordion = (): JSX.Element => {
+  const chemicalsNumber = useAppSelector(numberOfChemicalsSelector);
+  const drugsState = useAppSelector(loadingChemicalsStatusSelector);
+
+  return (
+    <AccordionItem>
+      <AccordionItemHeading>
+        <AccordionItemButton variant="non-expandable">
+          Chemicals
+          {drugsState === 'pending' && ' (Loading...)'}
+          {drugsState === 'succeeded' && ` (${chemicalsNumber})`}
+        </AccordionItemButton>
+      </AccordionItemHeading>
+    </AccordionItem>
+  );
+};
diff --git a/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/index.ts b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/index.ts
new file mode 100644
index 00000000..9fc44924
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion/index.ts
@@ -0,0 +1 @@
+export { ChemicalsAccordion } from './ChemicalsAccordion.component';
diff --git a/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.test.tsx
new file mode 100644
index 00000000..b3b10bf6
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.test.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from '@testing-library/react';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { mirnasFixture } from '@/models/fixtures/mirnasFixture';
+import { Accordion } from '@/shared/Accordion';
+import { MirnaAccordion } from './MirnaAccordion.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <Accordion>
+          <MirnaAccordion />
+        </Accordion>
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('DrugsAccordion - component', () => {
+  it('should display drugs number after succesfull chemicals search', () => {
+    renderComponent({
+      mirnas: { data: mirnasFixture, loading: 'succeeded', error: { name: '', message: '' } },
+    });
+    expect(screen.getByText('MiRNA (2)')).toBeInTheDocument();
+  });
+  it('should display loading indicator while waiting for chemicals search response', () => {
+    renderComponent({
+      mirnas: { data: [], loading: 'pending', error: { name: '', message: '' } },
+    });
+    expect(screen.getByText('MiRNA (Loading...)')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.tsx b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.tsx
new file mode 100644
index 00000000..e23bf056
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/MirnaAccordion.component.tsx
@@ -0,0 +1,23 @@
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  numberOfMirnasSelector,
+  loadingMirnasStatusSelector,
+} from '@/redux/mirnas/mirnas.selectors';
+import { AccordionItem, AccordionItemHeading, AccordionItemButton } from '@/shared/Accordion';
+
+export const MirnaAccordion = (): JSX.Element => {
+  const mirnaNumber = useAppSelector(numberOfMirnasSelector);
+  const mirnaState = useAppSelector(loadingMirnasStatusSelector);
+
+  return (
+    <AccordionItem>
+      <AccordionItemHeading>
+        <AccordionItemButton variant="non-expandable">
+          MiRNA
+          {mirnaState === 'pending' && ' (Loading...)'}
+          {mirnaState === 'succeeded' && ` (${mirnaNumber})`}
+        </AccordionItemButton>
+      </AccordionItemHeading>
+    </AccordionItem>
+  );
+};
diff --git a/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/index.ts b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/index.ts
new file mode 100644
index 00000000..69f2736c
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerContent/MirnaAccordion/index.ts
@@ -0,0 +1 @@
+export { MirnaAccordion } from './MirnaAccordion.component';
diff --git a/src/components/Map/Drawer/SearchDrawerContent/SearchDrawerContent.component.tsx b/src/components/Map/Drawer/SearchDrawerContent/SearchDrawerContent.component.tsx
index ea53111c..7f0cc18b 100644
--- a/src/components/Map/Drawer/SearchDrawerContent/SearchDrawerContent.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerContent/SearchDrawerContent.component.tsx
@@ -1,5 +1,7 @@
 import { BioEntitiesAccordion } from '@/components/Map/Drawer/SearchDrawerContent/BioEntitiesAccordion';
 import { DrugsAccordion } from '@/components/Map/Drawer/SearchDrawerContent/DrugsAccordion';
+import { ChemicalsAccordion } from '@/components/Map/Drawer/SearchDrawerContent/ChemicalsAccordion';
+import { MirnaAccordion } from '@/components/Map/Drawer/SearchDrawerContent/MirnaAccordion';
 import { closeDrawer } from '@/redux/drawer/drawer.slice';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { IconButton } from '@/shared/IconButton';
@@ -33,6 +35,8 @@ export const SearchDrawerContent = (): JSX.Element => {
         <Accordion allowZeroExpanded>
           <BioEntitiesAccordion />
           <DrugsAccordion />
+          <ChemicalsAccordion />
+          <MirnaAccordion />
         </Accordion>
       </div>
     </div>
diff --git a/src/redux/chemicals/chemicals.selectors.ts b/src/redux/chemicals/chemicals.selectors.ts
index b6c7cb1c..d0cdd9b7 100644
--- a/src/redux/chemicals/chemicals.selectors.ts
+++ b/src/redux/chemicals/chemicals.selectors.ts
@@ -1,9 +1,15 @@
 import { rootSelector } from '@/redux/root/root.selectors';
 import { createSelector } from '@reduxjs/toolkit';
 
+const SIZE_OF_EMPTY_ARRAY = 0;
+
 export const chemicalsSelector = createSelector(rootSelector, state => state.chemicals);
 
 export const loadingChemicalsStatusSelector = createSelector(
   chemicalsSelector,
   state => state.loading,
 );
+
+export const numberOfChemicalsSelector = createSelector(chemicalsSelector, state =>
+  state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY,
+);
diff --git a/src/redux/mirnas/mirnas.selectors.ts b/src/redux/mirnas/mirnas.selectors.ts
index 5344f037..59af89ec 100644
--- a/src/redux/mirnas/mirnas.selectors.ts
+++ b/src/redux/mirnas/mirnas.selectors.ts
@@ -1,6 +1,11 @@
 import { rootSelector } from '@/redux/root/root.selectors';
 import { createSelector } from '@reduxjs/toolkit';
 
+const SIZE_OF_EMPTY_ARRAY = 0;
+
 export const mirnasSelector = createSelector(rootSelector, state => state.mirnas);
 
 export const loadingMirnasStatusSelector = createSelector(mirnasSelector, state => state.loading);
+export const numberOfMirnasSelector = createSelector(mirnasSelector, state =>
+  state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY,
+);
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 194e3db0..841a79b8 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -27,4 +27,3 @@ export type StoreType = typeof store;
 export type RootState = ReturnType<typeof store.getState>;
 // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
 export type AppDispatch = typeof store.dispatch;
-export type StoreType = typeof store;
diff --git a/src/shared/DrawerHeadingBackwardButton/DrawerHeadingBackwardButton.component.test.tsx b/src/shared/DrawerHeadingBackwardButton/DrawerHeadingBackwardButton.component.test.tsx
index c6ef266e..23e0ad5d 100644
--- a/src/shared/DrawerHeadingBackwardButton/DrawerHeadingBackwardButton.component.test.tsx
+++ b/src/shared/DrawerHeadingBackwardButton/DrawerHeadingBackwardButton.component.test.tsx
@@ -1,5 +1,8 @@
 import { StoreType } from '@/redux/store';
-import { InitialStoreState, getReduxWrapperWithStore } from '@/utils/getReduxWrapperWithStore';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
 import { render, screen } from '@testing-library/react';
 import { DrawerHeadingBackwardButton } from './DrawerHeadingBackwardButton.component';
 
@@ -53,13 +56,13 @@ describe('DrawerHeadingBackwardButton - component', () => {
 
   it('should call class drawer on close button click', () => {
     const { store } = renderComponent('Title', 'value', {
-      drawer: { open: true, drawerName: 'search' },
+      drawer: { isOpen: true, drawerName: 'search' },
     });
-    expect(store.getState().drawer.open).toBe(true);
+    expect(store.getState().drawer.isOpen).toBe(true);
 
     const closeButton = screen.getByRole('close-drawer-button');
     closeButton.click();
 
-    expect(store.getState().drawer.open).toBe(false);
+    expect(store.getState().drawer.isOpen).toBe(false);
   });
 });
diff --git a/src/utils/getReduxWrapperWithStore.tsx b/src/utils/getReduxWrapperWithStore.tsx
deleted file mode 100644
index cf6097bd..00000000
--- a/src/utils/getReduxWrapperWithStore.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { RootState, StoreType } from '@/redux/store';
-import { configureStore } from '@reduxjs/toolkit';
-import { Provider } from 'react-redux';
-import bioEntityContentsReducer from '@/redux/bioEntityContents/bioEntityContents.slice';
-import chemicalsReducer from '@/redux/chemicals/chemicals.slice';
-import drawerReducer from '@/redux/drawer/drawer.slice';
-import drugsReducer from '@/redux/drugs/drugs.slice';
-import mirnasReducer from '@/redux/mirnas/mirnas.slice';
-import projectReducer from '@/redux/project/project.slice';
-import searchReducer from '@/redux/search/search.slice';
-import modelsReducer from '@/redux/models/models.slice';
-
-interface WrapperProps {
-  children: React.ReactNode;
-}
-
-export type InitialStoreState = Partial<RootState>;
-
-type GetReduxWrapperUsingSliceReducer = (initialState?: InitialStoreState) => {
-  Wrapper: ({ children }: WrapperProps) => JSX.Element;
-  store: StoreType;
-};
-
-export const getReduxWrapperWithStore: GetReduxWrapperUsingSliceReducer = (
-  preloadedState: InitialStoreState = {},
-) => {
-  const testStore = configureStore({
-    reducer: {
-      search: searchReducer,
-      project: projectReducer,
-      drugs: drugsReducer,
-      mirnas: mirnasReducer,
-      chemicals: chemicalsReducer,
-      bioEntityContents: bioEntityContentsReducer,
-      drawer: drawerReducer,
-      models: modelsReducer,
-    },
-    preloadedState,
-  });
-
-  const Wrapper = ({ children }: WrapperProps): JSX.Element => (
-    <Provider store={testStore}>{children}</Provider>
-  );
-
-  return { Wrapper, store: testStore };
-};
diff --git a/src/utils/testing/getReduxWrapperWithStore.tsx b/src/utils/testing/getReduxWrapperWithStore.tsx
index 37e3cd5a..cf6097bd 100644
--- a/src/utils/testing/getReduxWrapperWithStore.tsx
+++ b/src/utils/testing/getReduxWrapperWithStore.tsx
@@ -1,4 +1,4 @@
-import { store } from '@/redux/store';
+import { RootState, StoreType } from '@/redux/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import bioEntityContentsReducer from '@/redux/bioEntityContents/bioEntityContents.slice';
@@ -8,31 +8,17 @@ import drugsReducer from '@/redux/drugs/drugs.slice';
 import mirnasReducer from '@/redux/mirnas/mirnas.slice';
 import projectReducer from '@/redux/project/project.slice';
 import searchReducer from '@/redux/search/search.slice';
-import { SearchState } from '@/redux/search/search.types';
-import { ProjectState } from '@/redux/project/project.types';
-import { DrugsState } from '@/redux/drugs/drugs.types';
-import { MirnasState } from '@/redux/mirnas/mirnas.types';
-import { ChemicalsState } from '@/redux/chemicals/chemicals.types';
-import { BioEntityContentsState } from '@/redux/bioEntityContents/bioEntityContents.types';
-import { DrawerState } from '@/redux/drawer/drawer.types';
+import modelsReducer from '@/redux/models/models.slice';
 
 interface WrapperProps {
   children: React.ReactNode;
 }
 
-export type InitialStoreState = {
-  search?: SearchState;
-  project?: ProjectState;
-  drugs?: DrugsState;
-  mirnas?: MirnasState;
-  chemicals?: ChemicalsState;
-  bioEntityContents?: BioEntityContentsState;
-  drawer?: DrawerState;
-};
+export type InitialStoreState = Partial<RootState>;
 
 type GetReduxWrapperUsingSliceReducer = (initialState?: InitialStoreState) => {
   Wrapper: ({ children }: WrapperProps) => JSX.Element;
-  store: typeof store;
+  store: StoreType;
 };
 
 export const getReduxWrapperWithStore: GetReduxWrapperUsingSliceReducer = (
@@ -47,6 +33,7 @@ export const getReduxWrapperWithStore: GetReduxWrapperUsingSliceReducer = (
       chemicals: chemicalsReducer,
       bioEntityContents: bioEntityContentsReducer,
       drawer: drawerReducer,
+      models: modelsReducer,
     },
     preloadedState,
   });
-- 
GitLab