Skip to content
Snippets Groups Projects
Commit 2b664a24 authored by Mateusz Bolewski's avatar Mateusz Bolewski
Browse files

Feature/search chemicals details

parent d9900888
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!55Feature/search chemicals details
...@@ -33,7 +33,7 @@ describe('DrugsAccordion - component', () => { ...@@ -33,7 +33,7 @@ describe('DrugsAccordion - component', () => {
renderComponent({ renderComponent({
chemicals: { data: chemicalsFixture, loading: 'succeeded', error: { name: '', message: '' } }, chemicals: { data: chemicalsFixture, loading: 'succeeded', error: { name: '', message: '' } },
}); });
expect(screen.getByText('Chemicals (2)')).toBeInTheDocument(); expect(screen.getByText('Chemicals (4)')).toBeInTheDocument();
}); });
it('should display loading indicator while waiting for chemicals search response', () => { it('should display loading indicator while waiting for chemicals search response', () => {
renderComponent({ renderComponent({
......
/* eslint-disable no-magic-numbers */ /* eslint-disable no-magic-numbers */
import { drugsFixture } from '@/models/fixtures/drugFixtures'; import { drugsFixture } from '@/models/fixtures/drugFixtures';
import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture';
import { StoreType } from '@/redux/store'; import { StoreType } from '@/redux/store';
import { import {
InitialStoreState, InitialStoreState,
getReduxWrapperWithStore, getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore'; } from '@/utils/testing/getReduxWrapperWithStore';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { PinItem, PinType } from '../PinsList/PinsList.types';
import { AccordionsDetails } from './AccordionsDetails.component'; import { AccordionsDetails } from './AccordionsDetails.component';
const PINS_LIST = drugsFixture.map(drug => ({ const DRUGS_PINS_LIST = drugsFixture.map(drug => ({
id: drug.id, id: drug.id,
name: drug.name, name: drug.name,
data: drug, data: drug,
})); }));
const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { const CHEMICALS_PINS_LIST = chemicalsFixture.map(chemical => ({
id: chemical.id.id,
name: chemical.name,
data: chemical,
}));
const renderComponent = (
pinsList: PinItem[],
type: PinType,
initialStoreState: InitialStoreState = {},
): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
return ( return (
render( render(
<Wrapper> <Wrapper>
<AccordionsDetails pinsList={PINS_LIST} /> <AccordionsDetails pinsList={pinsList} type={type} />
</Wrapper>, </Wrapper>,
), ),
{ {
...@@ -31,21 +43,21 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St ...@@ -31,21 +43,21 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
describe('AccordionsDetails - component', () => { describe('AccordionsDetails - component', () => {
it('should display name of drug', () => { it('should display name of drug', () => {
renderComponent(); renderComponent(DRUGS_PINS_LIST, 'drugs');
const drugName = drugsFixture[0].name; const drugName = drugsFixture[0].name;
expect(screen.getByText(drugName, { exact: false })).toBeInTheDocument(); expect(screen.getByText(drugName, { exact: false })).toBeInTheDocument();
}); });
it('should display description of drug', () => { it('should display description of drug', () => {
renderComponent(); renderComponent(DRUGS_PINS_LIST, 'drugs');
const drugDescription = drugsFixture[0].description; const drugDescription = drugsFixture[0].description;
expect(screen.getByText(drugDescription, { exact: false })).toBeInTheDocument(); expect(screen.getByText(drugDescription, { exact: false })).toBeInTheDocument();
}); });
it('should display synonyms of drug', () => { it('should display synonyms of drug', () => {
renderComponent(); renderComponent(DRUGS_PINS_LIST, 'drugs');
const firstDrugSynonym = drugsFixture[0].synonyms[0]; const firstDrugSynonym = drugsFixture[0].synonyms[0];
const secondDrugSynonym = drugsFixture[0].synonyms[1]; const secondDrugSynonym = drugsFixture[0].synonyms[1];
...@@ -53,11 +65,20 @@ describe('AccordionsDetails - component', () => { ...@@ -53,11 +65,20 @@ describe('AccordionsDetails - component', () => {
expect(screen.getByText(firstDrugSynonym, { exact: false })).toBeInTheDocument(); expect(screen.getByText(firstDrugSynonym, { exact: false })).toBeInTheDocument();
expect(screen.getByText(secondDrugSynonym, { exact: false })).toBeInTheDocument(); expect(screen.getByText(secondDrugSynonym, { exact: false })).toBeInTheDocument();
}); });
it('should display additional info about drug', () => { it('should display blood brain barrier for drug', () => {
renderComponent(); renderComponent(DRUGS_PINS_LIST, 'drugs');
const drugAdditionalInfo = drugsFixture[0].bloodBrainBarrier; const drugAdditionalInfo = drugsFixture[0].bloodBrainBarrier;
expect(screen.getByText(drugAdditionalInfo, { exact: false })).toBeInTheDocument(); expect(screen.getByText(drugAdditionalInfo, { exact: false })).toBeInTheDocument();
}); });
it('should display direct evidence publications for chemicals', () => {
renderComponent(CHEMICALS_PINS_LIST, 'chemicals');
const chemicalsAdditionalInfo = chemicalsFixture[0].directEvidence
? chemicalsFixture[0].directEvidence
: '';
expect(screen.getAllByText(chemicalsAdditionalInfo, { exact: false })[0]).toBeInTheDocument();
});
}); });
...@@ -5,7 +5,7 @@ import { ...@@ -5,7 +5,7 @@ import {
AccordionItemHeading, AccordionItemHeading,
AccordionItemPanel, AccordionItemPanel,
} from '@/shared/Accordion'; } from '@/shared/Accordion';
import { PinItem } from '../PinsList/PinsList.types'; import { PinItem, PinType } from '../PinsList/PinsList.types';
import { import {
getAdditionalInfo, getAdditionalInfo,
getEntityDescriptions, getEntityDescriptions,
...@@ -15,15 +15,16 @@ import { ...@@ -15,15 +15,16 @@ import {
interface AccordionsDetailsProps { interface AccordionsDetailsProps {
pinsList: PinItem[]; pinsList: PinItem[];
type: PinType;
} }
export const AccordionsDetails = ({ pinsList }: AccordionsDetailsProps): JSX.Element => { export const AccordionsDetails = ({ pinsList, type }: AccordionsDetailsProps): JSX.Element => {
return ( return (
<> <>
<Accordion allowZeroExpanded className="px-6"> <Accordion allowZeroExpanded className="px-6">
<AccordionItem> <AccordionItem>
<AccordionItemHeading> <AccordionItemHeading>
<AccordionItemButton>Drug</AccordionItemButton> <AccordionItemButton className="capitalize">{type}</AccordionItemButton>
</AccordionItemHeading> </AccordionItemHeading>
<AccordionItemPanel>{getEntityNames(pinsList)}</AccordionItemPanel> <AccordionItemPanel>{getEntityNames(pinsList)}</AccordionItemPanel>
</AccordionItem> </AccordionItem>
...@@ -40,10 +41,18 @@ export const AccordionsDetails = ({ pinsList }: AccordionsDetailsProps): JSX.Ele ...@@ -40,10 +41,18 @@ export const AccordionsDetails = ({ pinsList }: AccordionsDetailsProps): JSX.Ele
<AccordionItemPanel>{getEntitySynonyms(pinsList)}</AccordionItemPanel> <AccordionItemPanel>{getEntitySynonyms(pinsList)}</AccordionItemPanel>
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>
<div className="flex justify-between px-6 py-4 text-sm font-bold"> {type === 'drugs' && (
<div>Blood brain barrier</div> <div className="flex justify-between px-6 py-4 text-sm font-bold">
<div>{getAdditionalInfo(pinsList)}</div> <div>Blood brain barrier</div>
</div> <div>{getAdditionalInfo(pinsList, type)}</div>
</div>
)}
{type === 'chemicals' && (
<div className="flex justify-between px-6 py-4 text-sm">
<div className="font-bold">Direct Evidence Publications</div>
<div>{getAdditionalInfo(pinsList, type)}</div>
</div>
)}
</> </>
); );
}; };
import { PinItem } from '../PinsList/PinsList.types'; import { PinItem, PinType } from '../PinsList/PinsList.types';
export const getEntityNames = (pinsList: PinItem[]): string => { export const getEntityNames = (pinsList: PinItem[]): string => {
let name = ''; let name = '';
...@@ -34,14 +34,22 @@ export const getEntitySynonyms = (pinsList: PinItem[]): string => { ...@@ -34,14 +34,22 @@ export const getEntitySynonyms = (pinsList: PinItem[]): string => {
return synonyms; return synonyms;
}; };
export const getAdditionalInfo = (pinsList: PinItem[]): string => { export const getAdditionalInfo = (pinsList: PinItem[], type: PinType): string => {
let additionalDetails = ''; if (type === 'drugs') {
return pinsList
pinsList.forEach(element => { .map(element => ('bloodBrainBarrier' in element.data ? element.data.bloodBrainBarrier : ''))
if ('bloodBrainBarrier' in element.data) { .join(', ');
additionalDetails += element.data.bloodBrainBarrier; }
}
}); if (type === 'chemicals') {
return pinsList
return additionalDetails; .map(element =>
'directEvidence' in element.data && element.data.directEvidence
? element.data.directEvidence
: 'No annotations',
)
.join(', ');
}
return '';
}; };
...@@ -13,7 +13,7 @@ export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => { ...@@ -13,7 +13,7 @@ export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => {
case 'drugs': case 'drugs':
return ( return (
<div className="h-[calc(100vh-198px)] overflow-auto"> <div className="h-[calc(100vh-198px)] overflow-auto">
<AccordionsDetails pinsList={pinsList} /> <AccordionsDetails pinsList={pinsList} type={type} />
<ul className="px-6 py-2"> <ul className="px-6 py-2">
{pinsList.map(result => { {pinsList.map(result => {
return result.data.targets.map(pin => ( return result.data.targets.map(pin => (
...@@ -26,7 +26,18 @@ export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => { ...@@ -26,7 +26,18 @@ export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => {
case 'bioEntity': case 'bioEntity':
return <div />; return <div />;
case 'chemicals': case 'chemicals':
return <div />; return (
<div className="h-[calc(100vh-198px)] overflow-auto">
<AccordionsDetails pinsList={pinsList} type={type} />
<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 'mirna': case 'mirna':
return ( return (
<ul className="h-[calc(100vh-198px)] overflow-auto px-6 py-2"> <ul className="h-[calc(100vh-198px)] overflow-auto px-6 py-2">
......
...@@ -9,6 +9,10 @@ export const loadingChemicalsStatusSelector = createSelector( ...@@ -9,6 +9,10 @@ export const loadingChemicalsStatusSelector = createSelector(
state => state.loading, state => state.loading,
); );
export const numberOfChemicalsSelector = createSelector(chemicalsSelector, state => export const numberOfChemicalsSelector = createSelector(chemicalsSelector, state => {
state.data ? state.data.length : SIZE_OF_EMPTY_ARRAY, if (!state.data) {
); return SIZE_OF_EMPTY_ARRAY;
}
return state.data.length && state.data.map(e => e.targets.length)?.reduce((a, b) => a + b);
});
import { twMerge } from 'tailwind-merge';
import { AccordionItemButton as AIB } from 'react-accessible-accordion'; import { AccordionItemButton as AIB } from 'react-accessible-accordion';
import './AccordionItemButton.style.css'; import './AccordionItemButton.style.css';
import { Variant } from './AccordionItemButton.types'; import { Variant } from './AccordionItemButton.types';
...@@ -8,6 +9,7 @@ type AccordionItemButtonProps = { ...@@ -8,6 +9,7 @@ type AccordionItemButtonProps = {
variant?: Variant; variant?: Variant;
onClick?: () => void; onClick?: () => void;
disabled?: boolean; disabled?: boolean;
className?: string;
}; };
export const AccordionItemButton = ({ export const AccordionItemButton = ({
...@@ -15,6 +17,7 @@ export const AccordionItemButton = ({ ...@@ -15,6 +17,7 @@ export const AccordionItemButton = ({
variant = 'expandable', variant = 'expandable',
onClick, onClick,
disabled, disabled,
className,
}: AccordionItemButtonProps): JSX.Element => { }: AccordionItemButtonProps): JSX.Element => {
const ButtonIcon = getIcon(variant); const ButtonIcon = getIcon(variant);
...@@ -23,7 +26,7 @@ export const AccordionItemButton = ({ ...@@ -23,7 +26,7 @@ export const AccordionItemButton = ({
<button <button
onClick={onClick} onClick={onClick}
disabled={disabled} disabled={disabled}
className="flex w-full flex-row flex-nowrap justify-between text-sm" className={twMerge('flex w-full flex-row flex-nowrap justify-between text-sm', className)}
type="button" type="button"
data-testid="accordion-item-button" data-testid="accordion-item-button"
> >
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment