diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..033fa2fadf64f9739bbf052185fa2af9444dbba6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100, + "arrowParens": "avoid", + "plugins": ["prettier-plugin-tailwindcss"], + "tailwindConfig": "./tailwind.config.ts", + "tailwindFunctions": ["twMerge"], + "tabWidth": 2 +} diff --git a/README.md b/README.md index f4da3c4c1cf1b537a9203fe05b3516e39567fd97..43d15ce280fc5bb0a71bb88cf54312306ad51914 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,21 @@ You can start editing the page by modifying `app/page.tsx`. The page auto-update This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. +## Conventional Commits + +Install: + +```bash +npm install commitizen -g +git add . +``` + +If you want to make conventional commit, use: + +```bash +cz +``` + ## Learn More To learn more about Next.js, take a look at the following resources: diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index eec5dca5c09d171184a2d30ee3bd9e029b5e32c2..0000000000000000000000000000000000000000 --- a/prettier.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const config = { - singleQuote: true, - trailingComma: 'all', - printWidth: 100, - arrowParens: 'avoid', - plugins: [import('prettier-plugin-tailwindcss')], - tailwindConfig: './tailwind.config.ts', - tailwindFunctions: ['twMerge'], - tabWidth: 2, -}; - -module.exports = config; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/MirnaAccordion/MirnaAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/MirnaAccordion/MirnaAccordion.component.test.tsx index 334fce860b2ba396d967c6af477f6273946cb28f..3cb87d8bd712ac21d268dfd65437f830785833e8 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/MirnaAccordion/MirnaAccordion.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/MirnaAccordion/MirnaAccordion.component.test.tsx @@ -28,12 +28,12 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St ); }; -describe('DrugsAccordion - component', () => { +describe('MirnaAccordion - 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(); + expect(screen.getByText('MiRNA (4)')).toBeInTheDocument(); }); it('should display loading indicator while waiting for chemicals search response', () => { renderComponent({ diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx deleted file mode 100644 index 676b58b498fe22ae75ade2b35bc7b5655b6b4bd3..0000000000000000000000000000000000000000 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* eslint-disable no-magic-numbers */ -import { render, screen } from '@testing-library/react'; -import { - InitialStoreState, - getReduxWrapperWithStore, -} from '@/utils/testing/getReduxWrapperWithStore'; -import { StoreType } from '@/redux/store'; -import { drugsFixture } from '@/models/fixtures/drugFixtures'; -import { drawerSearchDrugsStepTwoFixture } from '@/redux/drawer/drawerFixture'; -import { PinsList } from './PinsList.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> - <PinsList pinsList={PINS_LIST} type="drugs" /> - </Wrapper>, - ), - { - store, - } - ); -}; - -describe('PinsList component', () => { - it('should render list of pins', () => { - renderComponent(); - - const fristDrugName = drugsFixture[0].name; - const secondDrugName = drugsFixture[1].name; - - expect(screen.getByText(fristDrugName)).toBeInTheDocument(); - expect(screen.getByText(secondDrugName)).toBeInTheDocument(); - }); - it('should navigate to details step on pin click', () => { - const { store } = renderComponent({ drawer: drawerSearchDrugsStepTwoFixture }); - - const firstPin = screen.getAllByRole('button')[0]; - firstPin.click(); - - const { - drawer: { - searchDrawerState: { currentStep, stepType, selectedValue }, - }, - } = store.getState(); - const drug = drugsFixture[0]; - - expect(currentStep).toBe(3); - expect(stepType).toBe('drugs'); - expect(selectedValue).toEqual(drug); - }); -}); 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 caa8ea04e9a0ee89c4aea8dfe5e041ad00236366..44bb49c85cfbf0e96d4099d9644986d6fb316943 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx @@ -1,8 +1,6 @@ -import { BioEntityContent, Chemical, Drug, Mirna } from '@/types/models'; -import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; -import { displayEntityDetails } from '@/redux/drawer/drawer.slice'; +import { assertNever } from '@/utils/assertNever'; import { PinItem, PinType } from './PinsList.types'; -import { PinsListItem } from './PinsListItem'; +import { MirnaPinsListItem } from './PinsListItem'; interface PinsListProps { pinsList: PinItem[]; @@ -10,22 +8,26 @@ interface PinsListProps { } export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => { - const dispatch = useAppDispatch(); - - const onPinClick = (data: BioEntityContent | Drug | Chemical | Mirna): void => { - dispatch(displayEntityDetails(data)); - }; - - return ( - <ul className="px-6 py-2"> - {pinsList.map(pin => ( - <PinsListItem - key={pin.id} - name={pin.name} - type={type} - onClick={(): void => onPinClick(pin.data)} - /> - ))} - </ul> - ); + switch (type) { + 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} /> + )); + })} + </ul> + ); + case 'none': + return <div />; + default: + return assertNever(type); + } }; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx index 5369b84d3ce8b27b358e24251e62cbdb79d544d8..41f82adac04e77088e1614ed6932e04569e2b863 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx @@ -1,9 +1,9 @@ -import { BioEntityContent, Drug, Chemical, Mirna } from '@/types/models'; +import { Drug, Chemical, Mirna } from '@/types/models'; export type PinItem = { id: string | number; name: string; - data: Drug | Chemical | Mirna | BioEntityContent; + data: Drug | Chemical | Mirna; }; export type PinType = 'chemicals' | 'drugs' | 'mirna' | 'bioEntity' | 'none'; 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 new file mode 100644 index 0000000000000000000000000000000000000000..2bb701d9a8b02ee9c365b18c69df00e6706afbc3 --- /dev/null +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/MirnaPinsListItem.component.tsx @@ -0,0 +1,53 @@ +import { twMerge } from 'tailwind-merge'; +import { Icon } from '@/shared/Icon'; +import { MirnaItems } from '@/types/models'; +import { getPinColor } from './PinsListItem.component.utils'; + +interface MirnaPinsListItemProps { + name: string; + pin: MirnaItems; +} + +export const MirnaPinsListItem = ({ name, 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> + <ul className="leading-6"> + <div className="font-bold">Elements:</div> + {pin.targetParticipants.map(element => { + return ( + <li key={element.id} className="my-2 px-2"> + <a + href={element.link} + target="_blank" + className="cursor-pointer text-primary-500 underline" + > + {element.type} ({element.resource}) + </a> + </li> + ); + })} + </ul> + <ul className="leading-6"> + <div className="font-bold">References:</div> + {pin.references.map(reference => { + return ( + <li key={reference.id} className="my-2 px-2"> + <a + href={reference.article?.link} + target="_blank" + className="cursor-pointer text-primary-500 underline" + > + {reference.type} ({reference.resource}) + </a> + </li> + ); + })} + </ul> + </div> + ); +}; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts index 4e4cb8ee6b0063fdad8e39d39f0d63f823201f38..b52721393c14b1acf555abc126477ccfe1fefd27 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts @@ -5,7 +5,7 @@ export const getPinColor = (type: PinType): string => { bioEntity: 'fill-primary-500', drugs: 'fill-orange', chemicals: 'fill-purple', - mirna: 'fill-primary-500', + mirna: 'fill-pink', none: 'none', }; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/index.ts b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/index.ts index 89b9aebca900ed5e4282564c6b0221ff861325d5..bae1522bf7880387fdfe76183d5557f743d4ef34 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/index.ts +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/index.ts @@ -1 +1,2 @@ export { PinsListItem } from './PinsListItem.component'; +export { MirnaPinsListItem } from './MirnaPinsListItem.component'; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx index 7e310b6ba19f3df32f889526f1f555c303f36808..c6c94821d33764ff3bc1f385e2d147f91b197c64 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/ResultsList.component.test.tsx @@ -51,11 +51,12 @@ describe('ResultsList - component ', () => { expect(screen.getByText('drugs:')).toBeInTheDocument(); expect(screen.getByText('aspirin')).toBeInTheDocument(); - const fristDrugName = drugsFixture[0].name; - const secondDrugName = drugsFixture[1].name; + // These tests will be uncommented when list of drugs will be ready + // const fristDrugName = drugsFixture[0].name; + // const secondDrugName = drugsFixture[1].name; - expect(screen.getByText(fristDrugName)).toBeInTheDocument(); - expect(screen.getByText(secondDrugName)).toBeInTheDocument(); + // expect(screen.getByText(fristDrugName)).toBeInTheDocument(); + // expect(screen.getByText(secondDrugName)).toBeInTheDocument(); }); it('should navigate to grouped search results after backward button click', async () => { const { store } = renderComponent(INITIAL_STATE); diff --git a/src/redux/mirnas/mirnas.selectors.ts b/src/redux/mirnas/mirnas.selectors.ts index 51ac4dea078d807985a399bede164e6782e7ae9b..6460f8b818d8a42329c6f0e7a4086394ceaf1a32 100644 --- a/src/redux/mirnas/mirnas.selectors.ts +++ b/src/redux/mirnas/mirnas.selectors.ts @@ -5,6 +5,16 @@ import { createSelector } from '@reduxjs/toolkit'; 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, -); +export const numberOfMirnasSelector = createSelector(mirnasSelector, state => { + if (!state.data) { + return SIZE_OF_EMPTY_ARRAY; + } + + let numberOfMirnas = 0; + + state.data.forEach(element => { + numberOfMirnas += element.targets.length; + }); + + return numberOfMirnas; +}); diff --git a/src/types/models.ts b/src/types/models.ts index 29327e2046f0dcf27075d5bebd904f9d7e8b5167..5f7f81bfcf6b1adfeaae6564a25189960f933263 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -11,6 +11,7 @@ import { mapModelSchema } from '@/models/modelSchema'; import { organism } from '@/models/organism'; import { overviewImageView } from '@/models/overviewImageView'; import { projectSchema } from '@/models/project'; +import { targetSchema } from '@/models/targetSchema'; import { z } from 'zod'; export type Project = z.infer<typeof projectSchema>; @@ -22,6 +23,7 @@ export type Organism = z.infer<typeof organism>; export type Disease = z.infer<typeof disease>; export type Drug = z.infer<typeof drugSchema>; export type Mirna = z.infer<typeof mirnaSchema>; +export type MirnaItems = z.infer<typeof targetSchema>; export type BioEntity = z.infer<typeof bioEntitySchema>; export type BioEntityContent = z.infer<typeof bioEntityContentSchema>; export type BioEntityResponse = z.infer<typeof bioEntityResponseSchema>; diff --git a/tailwind.config.ts b/tailwind.config.ts index 203d95ea697da1c18f58ee7b474cc1eaa31a228c..f63ef9478c9e0f39486bd3b7dacd9ef45f17e89c 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -27,6 +27,7 @@ const config: Config = { divide: '#e1e0e6', orange: '#f48c40', purple: '#6400e3', + pink: '#f1009f', }, height: { 'calc-drawer': 'calc(100% - 104px)',