From 0ebba14ef1e1336889cddd00a1489fa24332311e Mon Sep 17 00:00:00 2001
From: Mateusz Bolewski <mateusz.bolewski@allegro.pl>
Date: Fri, 10 Nov 2023 13:10:19 +0100
Subject: [PATCH] Feature/search drugs details

---
 .../DrugsAccordion.component.test.tsx         |  2 +-
 .../AccordionsDetails.component.test.tsx      | 63 +++++++++++++++++++
 .../AccordionsDetails.component.tsx           | 49 +++++++++++++++
 .../AccordionsDetails.utils.tsx               | 47 ++++++++++++++
 .../PinsList/PinsList.component.tsx           | 18 +++++-
 .../MirnaPinsListItem.component.tsx           | 15 +++--
 src/redux/drugs/drugs.selectors.ts            | 16 ++++-
 yarn.lock                                     |  6 +-
 8 files changed, 200 insertions(+), 16 deletions(-)
 create mode 100644 src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx
 create mode 100644 src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx

diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
index ff2cc2db..ddba126b 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/DrugsAccordion/DrugsAccordion.component.test.tsx
@@ -33,7 +33,7 @@ describe('DrugsAccordion - component', () => {
     renderComponent({
       drugs: { data: drugsFixture, loading: 'succeeded', error: { name: '', message: '' } },
     });
-    expect(screen.getByText('Drugs (2)')).toBeInTheDocument();
+    expect(screen.getByText('Drugs (4)')).toBeInTheDocument();
   });
   it('should display loading indicator while waiting for drug search response', () => {
     renderComponent({
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx
new file mode 100644
index 00000000..2f3c00b7
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.test.tsx
@@ -0,0 +1,63 @@
+/* eslint-disable no-magic-numbers */
+import { drugsFixture } from '@/models/fixtures/drugFixtures';
+import { StoreType } from '@/redux/store';
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { AccordionsDetails } from './AccordionsDetails.component';
+
+const PINS_LIST = drugsFixture.map(drug => ({
+  id: drug.id,
+  name: drug.name,
+  data: drug,
+}));
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <AccordionsDetails pinsList={PINS_LIST} />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('AccordionsDetails - component', () => {
+  it('should display name of drug', () => {
+    renderComponent();
+
+    const drugName = drugsFixture[0].name;
+
+    expect(screen.getByText(drugName, { exact: false })).toBeInTheDocument();
+  });
+  it('should display description of drug', () => {
+    renderComponent();
+
+    const drugDescription = drugsFixture[0].description;
+
+    expect(screen.getByText(drugDescription, { exact: false })).toBeInTheDocument();
+  });
+  it('should display synonyms of drug', () => {
+    renderComponent();
+
+    const firstDrugSynonym = drugsFixture[0].synonyms[0];
+    const secondDrugSynonym = drugsFixture[0].synonyms[1];
+
+    expect(screen.getByText(firstDrugSynonym, { exact: false })).toBeInTheDocument();
+    expect(screen.getByText(secondDrugSynonym, { exact: false })).toBeInTheDocument();
+  });
+  it('should display additional info about drug', () => {
+    renderComponent();
+
+    const drugAdditionalInfo = drugsFixture[0].bloodBrainBarrier;
+
+    expect(screen.getByText(drugAdditionalInfo, { exact: false })).toBeInTheDocument();
+  });
+});
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx
new file mode 100644
index 00000000..9b4bad36
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.component.tsx
@@ -0,0 +1,49 @@
+import {
+  Accordion,
+  AccordionItem,
+  AccordionItemButton,
+  AccordionItemHeading,
+  AccordionItemPanel,
+} from '@/shared/Accordion';
+import { PinItem } from '../PinsList/PinsList.types';
+import {
+  getAdditionalInfo,
+  getEntityDescriptions,
+  getEntityNames,
+  getEntitySynonyms,
+} from './AccordionsDetails.utils';
+
+interface AccordionsDetailsProps {
+  pinsList: PinItem[];
+}
+
+export const AccordionsDetails = ({ pinsList }: AccordionsDetailsProps): JSX.Element => {
+  return (
+    <>
+      <Accordion allowZeroExpanded className="px-6">
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Drug</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntityNames(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Description</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntityDescriptions(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+        <AccordionItem>
+          <AccordionItemHeading>
+            <AccordionItemButton>Synonyms</AccordionItemButton>
+          </AccordionItemHeading>
+          <AccordionItemPanel>{getEntitySynonyms(pinsList)}</AccordionItemPanel>
+        </AccordionItem>
+      </Accordion>
+      <div className="flex justify-between px-6 py-4 text-sm font-bold">
+        <div>Blood brain barrier</div>
+        <div>{getAdditionalInfo(pinsList)}</div>
+      </div>
+    </>
+  );
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx
new file mode 100644
index 00000000..c5952708
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/AccordionsDetails/AccordionsDetails.utils.tsx
@@ -0,0 +1,47 @@
+import { PinItem } from '../PinsList/PinsList.types';
+
+export const getEntityNames = (pinsList: PinItem[]): string => {
+  let name = '';
+
+  pinsList.forEach(element => {
+    name += element.data.name;
+  });
+
+  return name;
+};
+
+export const getEntityDescriptions = (pinsList: PinItem[]): string => {
+  let description = '';
+
+  pinsList.forEach(element => {
+    if ('description' in element.data) {
+      description += element.data.description;
+    }
+  });
+
+  return description;
+};
+
+export const getEntitySynonyms = (pinsList: PinItem[]): string => {
+  let synonyms = '';
+
+  pinsList.forEach(element => {
+    if ('synonyms' in element.data) {
+      synonyms += element.data.synonyms.join(', ');
+    }
+  });
+
+  return synonyms;
+};
+
+export const getAdditionalInfo = (pinsList: PinItem[]): string => {
+  let additionalDetails = '';
+
+  pinsList.forEach(element => {
+    if ('bloodBrainBarrier' in element.data) {
+      additionalDetails += element.data.bloodBrainBarrier;
+    }
+  });
+
+  return additionalDetails;
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
index 44bb49c8..6aeb854e 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx
@@ -1,4 +1,5 @@
 import { assertNever } from '@/utils/assertNever';
+import { AccordionsDetails } from '../AccordionsDetails/AccordionsDetails.component';
 import { PinItem, PinType } from './PinsList.types';
 import { MirnaPinsListItem } from './PinsListItem';
 
@@ -9,18 +10,29 @@ interface PinsListProps {
 
 export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => {
   switch (type) {
+    case 'drugs':
+      return (
+        <div className="h-[calc(100vh-198px)] overflow-auto">
+          <AccordionsDetails pinsList={pinsList} />
+          <ul className="px-6 py-2">
+            {pinsList.map(result => {
+              return result.data.targets.map(pin => (
+                <MirnaPinsListItem key={pin.name} name={pin.name} type={type} pin={pin} />
+              ));
+            })}
+          </ul>
+        </div>
+      );
     case 'bioEntity':
       return <div />;
     case 'chemicals':
       return <div />;
-    case 'drugs':
-      return <div />;
     case 'mirna':
       return (
         <ul className="h-[calc(100vh-198px)] overflow-auto px-6 py-2">
           {pinsList.map(result => {
             return result.data.targets.map(pin => (
-              <MirnaPinsListItem key={pin.name} name={pin.name} pin={pin} />
+              <MirnaPinsListItem key={pin.name} name={pin.name} type={type} pin={pin} />
             ));
           })}
         </ul>
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
index 2bb701d9..ebd97b20 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx
@@ -2,19 +2,22 @@ import { twMerge } from 'tailwind-merge';
 import { Icon } from '@/shared/Icon';
 import { MirnaItems } from '@/types/models';
 import { getPinColor } from './PinsListItem.component.utils';
+import { PinType } from '../PinsList.types';
 
 interface MirnaPinsListItemProps {
   name: string;
+  type: PinType;
   pin: MirnaItems;
 }
 
-export const MirnaPinsListItem = ({ name, pin }: MirnaPinsListItemProps): JSX.Element => {
+export const MirnaPinsListItem = ({ name, type, pin }: MirnaPinsListItemProps): JSX.Element => {
   return (
-    <div className="mb-4 flex w-full flex-col gap-2 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
-      <div className="flex w-full flex-row gap-2">
-        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor('mirna'))} />
-        <p className="min-w-fit">Full name: </p>
-        <p className="w-full font-bold">{name}</p>
+    <div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
+      <div className="flex w-full flex-row items-center gap-2">
+        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor(type))} />
+        <p>
+          Full name: <span className="w-full font-bold">{name}</span>
+        </p>
       </div>
       <ul className="leading-6">
         <div className="font-bold">Elements:</div>
diff --git a/src/redux/drugs/drugs.selectors.ts b/src/redux/drugs/drugs.selectors.ts
index 7a1d3eac..af9a8d7f 100644
--- a/src/redux/drugs/drugs.selectors.ts
+++ b/src/redux/drugs/drugs.selectors.ts
@@ -5,6 +5,16 @@ import { createSelector } from '@reduxjs/toolkit';
 export const drugsSelector = createSelector(rootSelector, state => state.drugs);
 
 export const loadingDrugsStatusSelector = createSelector(drugsSelector, state => state.loading);
-export const numberOfDrugsSelector = createSelector(drugsSelector, state =>
-  state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY,
-);
+export const numberOfDrugsSelector = createSelector(drugsSelector, state => {
+  if (!state.data) {
+    return SIZE_OF_EMPTY_ARRAY;
+  }
+
+  let numberOfDrugs = 0;
+
+  state.data.forEach(element => {
+    numberOfDrugs += element.targets.length;
+  });
+
+  return numberOfDrugs;
+});
diff --git a/yarn.lock b/yarn.lock
index 9f446451..de1a94bc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -847,9 +847,9 @@
   "resolved" "https://registry.npmjs.org/@next/font/-/font-13.5.4.tgz"
   "version" "13.5.4"
 
-"@next/swc-darwin-arm64@13.4.19":
-  "integrity" "sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ=="
-  "resolved" "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.19.tgz"
+"@next/swc-darwin-x64@13.4.19":
+  "integrity" "sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw=="
+  "resolved" "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz"
   "version" "13.4.19"
 
 "@nodelib/fs.scandir@2.1.5":
-- 
GitLab