Skip to content
Snippets Groups Projects
Commit efc617d0 authored by Tadeusz Miesiąc's avatar Tadeusz Miesiąc
Browse files

feat(results list): connected drugs drawer to results list

parent 3a6501ff
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...,!38feat(results list): connected drugs drawer to results list
Pipeline #79990 passed
import * as toolkitRaw from '@reduxjs/toolkit';
import { AnyAction } from '@reduxjs/toolkit';
import type { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import { drugFixture } from '@/models/fixtures/drugFixtures';
import drawerReducer, {
clearSearchDrawerState,
closeDrawer,
displayDrugsList,
displayEntityDetails,
displayGroupedSearchResults,
openDrawer,
setSearchDrawerState,
openSearchDrawer,
} from './drawer.slice';
import type { DrawerState } from './drawer.types';
......@@ -14,13 +17,17 @@ const INITIAL_STATE: DrawerState = {
drawerName: 'none',
searchDrawerState: {
currentStep: 0,
selectedValue: {
name: '',
valueType: 'none',
},
stepType: 'none',
selectedValue: undefined,
},
};
const STEP = {
FIRST: 1,
SECOND: 2,
THIRD: 3,
};
type SliceReducerType = ToolkitStore<
{
drawer: DrawerState;
......@@ -48,7 +55,7 @@ describe('drawer reducer', () => {
expect(drawerReducer(undefined, action)).toEqual(INITIAL_STATE);
});
it('should update the store when you click a project info button on the nav bar', async () => {
it('should update the store after openDrawer action', async () => {
const { type } = await store.dispatch(openDrawer('project-info'));
const { isOpen, drawerName } = store.getState().drawer;
......@@ -57,60 +64,68 @@ describe('drawer reducer', () => {
expect(drawerName).toEqual('project-info');
});
it('should update the store when you click the close button on the drawer', async () => {
it('should update the store after openSearchDrawer action', async () => {
const { type } = await store.dispatch(openSearchDrawer());
const {
isOpen,
drawerName,
searchDrawerState: { currentStep },
} = store.getState().drawer;
expect(type).toBe('drawer/openSearchDrawer');
expect(isOpen).toBe(true);
expect(drawerName).toEqual('search');
expect(currentStep).toEqual(STEP.FIRST);
});
it('should update the store after closeDrawerReducer action', async () => {
const { type } = await store.dispatch(closeDrawer());
const { isOpen, drawerName } = store.getState().drawer;
const {
isOpen,
drawerName,
searchDrawerState: { currentStep, selectedValue, stepType },
} = store.getState().drawer;
expect(type).toBe('drawer/closeDrawer');
expect(isOpen).toBe(false);
expect(drawerName).toEqual('none');
expect(drawerName).toBe('none');
expect(currentStep).toBe(STEP.FIRST);
expect(selectedValue).toEqual(undefined);
expect(stepType).toEqual('none');
expect(type).toBe('drawer/closeDrawer');
});
it('should update the store when you choose from the drawer chemical`s first step', async () => {
const searchDrawerData: DrawerState['searchDrawerState'] = {
currentStep: 1,
selectedValue: {
name: 'chemicals frist step',
valueType: 'chemicals',
},
};
const { type } = await store.dispatch(setSearchDrawerState(searchDrawerData));
const { searchDrawerState } = store.getState().drawer;
const { currentStep, selectedValue } = searchDrawerState;
const currentStepToBE = 1;
expect(type).toBe('drawer/setSearchDrawerState');
expect(currentStep).toBe(currentStepToBE);
expect(selectedValue).toEqual({
name: 'chemicals frist step',
valueType: 'chemicals',
});
it('should update the store after displayDrugsList action', async () => {
const { type } = await store.dispatch(displayDrugsList());
const {
drawerName,
searchDrawerState: { currentStep, stepType },
} = store.getState().drawer;
expect(type).toBe('drawer/displayDrugsList');
expect(drawerName).toBe('search');
expect(currentStep).toBe(STEP.SECOND);
expect(stepType).toEqual('drugs');
});
it('should update the store when you clear the search drawer state', async () => {
const searchDrawerData: DrawerState['searchDrawerState'] = {
currentStep: 1,
selectedValue: {
name: 'chemicals frist step',
valueType: 'chemicals',
},
};
await store.dispatch(setSearchDrawerState(searchDrawerData));
const { type } = await store.dispatch(clearSearchDrawerState());
const { searchDrawerState } = store.getState().drawer;
const { currentStep, selectedValue } = searchDrawerState;
const currentStepToBE = 0;
expect(type).toBe('drawer/clearSearchDrawerState');
expect(currentStep).toBe(currentStepToBE);
expect(selectedValue).toEqual({
name: '',
valueType: 'none',
});
it('should update the store after displayGroupedSearchResults action', async () => {
const { type } = await store.dispatch(displayGroupedSearchResults());
const {
searchDrawerState: { currentStep, stepType },
} = store.getState().drawer;
expect(type).toBe('drawer/displayGroupedSearchResults');
expect(currentStep).toBe(STEP.FIRST);
expect(stepType).toEqual('none');
});
it('should update the store after displayEntityDetails action', async () => {
const { type } = await store.dispatch(displayEntityDetails(drugFixture));
const {
searchDrawerState: { currentStep, selectedValue },
} = store.getState().drawer;
expect(type).toBe('drawer/displayEntityDetails');
expect(currentStep).toBe(STEP.THIRD);
expect(selectedValue).toEqual(drugFixture);
});
});
import { STEP } from '@/constants/searchDrawer';
import type { DrawerState } from '@/redux/drawer/drawer.types';
import type { DrawerName } from '@/types/drawerName';
import type { PayloadAction } from '@reduxjs/toolkit';
......@@ -7,24 +8,35 @@ export const openDrawerReducer = (state: DrawerState, action: PayloadAction<Draw
state.drawerName = action.payload;
};
export const openSearchDrawerReducer = (state: DrawerState): void => {
state.isOpen = true;
state.drawerName = 'search';
state.searchDrawerState.currentStep = STEP.FIRST;
};
export const closeDrawerReducer = (state: DrawerState): void => {
state.isOpen = false;
state.drawerName = 'none';
state.searchDrawerState.currentStep = STEP.FIRST;
state.searchDrawerState.selectedValue = undefined;
state.searchDrawerState.stepType = 'none';
};
export const setSearchDrawerStateReducer = (
state: DrawerState,
action: PayloadAction<DrawerState['searchDrawerState']>,
): void => {
const { currentStep, selectedValue } = action.payload;
export const displayDrugsListReducer = (state: DrawerState): void => {
state.drawerName = 'search';
state.searchDrawerState.currentStep = STEP.SECOND;
state.searchDrawerState.stepType = 'drugs';
};
state.searchDrawerState.currentStep = currentStep;
state.searchDrawerState.selectedValue = selectedValue;
export const displayGroupedSearchResultsReducer = (state: DrawerState): void => {
state.searchDrawerState.currentStep = STEP.FIRST;
state.searchDrawerState.stepType = 'none';
};
export const clearSearchDrawerStateReducer = (state: DrawerState): void => {
state.searchDrawerState.currentStep = 0;
state.searchDrawerState.selectedValue = {
name: '',
valueType: 'none',
};
export const displayEntityDetailsReducer = (
state: DrawerState,
action: PayloadAction<DrawerState['searchDrawerState']['selectedValue']>,
): void => {
state.searchDrawerState.currentStep = STEP.THIRD;
state.searchDrawerState.selectedValue = action.payload;
};
import { rootSelector } from '@/redux/root/root.selectors';
import { assertNever } from '@/utils/assertNever';
import { createSelector } from '@reduxjs/toolkit';
export const drawerSelector = createSelector(rootSelector, state => state.drawer);
......@@ -20,7 +21,34 @@ export const selectedValueDrawerSelector = createSelector(
state => state.selectedValue,
);
export const valueTypeDrawerSelector = createSelector(
selectedValueDrawerSelector,
state => state.valueType,
export const stepTypeDrawerSelector = createSelector(
searchDrawerStateSelector,
state => state.stepType,
);
export const resultListSelector = createSelector(rootSelector, state => {
const selectedType = state.drawer.searchDrawerState.stepType;
switch (selectedType) {
case 'drugs':
return state.drugs.data!.map(drug => ({
id: drug.id,
name: drug.name,
data: drug,
}));
case 'chemicals':
return state.chemicals.data!.map(chemical => ({
id: chemical.id.id,
name: chemical.name,
data: chemical,
}));
case 'bioEntity':
return undefined;
case 'mirna':
return state.mirnas.data!.map(mirna => ({ id: mirna.id, name: mirna.name, data: mirna }));
case 'none':
return undefined;
default:
return assertNever(selectedType);
}
});
import { DrawerState } from '@/redux/drawer/drawer.types';
import { createSlice } from '@reduxjs/toolkit';
import {
clearSearchDrawerStateReducer,
closeDrawerReducer,
displayDrugsListReducer,
displayEntityDetailsReducer,
displayGroupedSearchResultsReducer,
openDrawerReducer,
setSearchDrawerStateReducer,
openSearchDrawerReducer,
} from './drawer.reducers';
const initialState: DrawerState = {
......@@ -12,10 +14,8 @@ const initialState: DrawerState = {
drawerName: 'none',
searchDrawerState: {
currentStep: 0,
selectedValue: {
name: '',
valueType: 'none',
},
stepType: 'none',
selectedValue: undefined,
},
};
......@@ -24,13 +24,21 @@ const drawerSlice = createSlice({
initialState,
reducers: {
openDrawer: openDrawerReducer,
openSearchDrawer: openSearchDrawerReducer,
closeDrawer: closeDrawerReducer,
setSearchDrawerState: setSearchDrawerStateReducer,
clearSearchDrawerState: clearSearchDrawerStateReducer,
displayDrugsList: displayDrugsListReducer,
displayGroupedSearchResults: displayGroupedSearchResultsReducer,
displayEntityDetails: displayEntityDetailsReducer,
},
});
export const { openDrawer, closeDrawer, setSearchDrawerState, clearSearchDrawerState } =
drawerSlice.actions;
export const {
openDrawer,
openSearchDrawer,
closeDrawer,
displayDrugsList,
displayGroupedSearchResults,
displayEntityDetails,
} = drawerSlice.actions;
export default drawerSlice.reducer;
import type { DrawerName } from '@/types/drawerName';
type DrugValue = {
name: string;
valueType: 'drugs';
};
type ChemicalsValue = {
name: string;
valueType: 'chemicals';
};
type MirnaValue = {
name: string;
valueType: 'mirna';
};
type BioEntityValue = {
model: { name: string; id: string };
name: string;
valueType: 'bioEntity';
};
type NoneValue = {
name: string;
valueType: 'none';
};
export type SelectedValue = DrugValue | ChemicalsValue | MirnaValue | BioEntityValue | NoneValue;
import { BioEntityContent, Chemical, Drug, Mirna } from '@/types/models';
export type SearchDrawerState = {
currentStep: number;
selectedValue: SelectedValue;
stepType: 'bioEntity' | 'drugs' | 'mirna' | 'chemicals' | 'none';
selectedValue: BioEntityContent | Drug | Mirna | Chemical | undefined;
};
export type DrawerState = {
......
import { DrawerState } from './drawer.types';
export const initialStateFixture: DrawerState = {
isOpen: false,
drawerName: 'none',
searchDrawerState: {
currentStep: 0,
stepType: 'none',
selectedValue: undefined,
},
};
export const drawerSearchStepOneFixture: DrawerState = {
isOpen: true,
drawerName: 'search',
searchDrawerState: {
currentStep: 1,
stepType: 'none',
selectedValue: undefined,
},
};
export const drawerSearchDrugsStepTwoFixture: DrawerState = {
isOpen: true,
drawerName: 'search',
searchDrawerState: {
currentStep: 2,
stepType: 'drugs',
selectedValue: undefined,
},
};
......@@ -3,21 +3,32 @@ import './AccordionItemButton.style.css';
import { Variant } from './AccordionItemButton.types';
import { getIcon } from './AccordionItemButton.utils';
interface AccordionItemButtonProps {
type AccordionItemButtonProps = {
children: React.ReactNode;
variant?: Variant;
}
onClick?: () => void;
disabled?: boolean;
};
export const AccordionItemButton = ({
children,
variant = 'expandable',
onClick,
disabled,
}: AccordionItemButtonProps): JSX.Element => {
const ButtonIcon = getIcon(variant);
return (
<AIB className="accordion-button flex flex-row flex-nowrap justify-between">
{children}
{ButtonIcon}
<button
onClick={onClick}
disabled={disabled}
className="flex w-full flex-row flex-nowrap justify-between text-sm"
type="button"
>
{children}
{ButtonIcon}
</button>
</AIB>
);
};
.accordion-button[aria-expanded='true'] > .arrow-button {
.accordion-button[aria-expanded='true'] .arrow-button {
@apply rotate-180;
}
......@@ -4,6 +4,7 @@ import {
getReduxWrapperWithStore,
} from '@/utils/testing/getReduxWrapperWithStore';
import { render, screen } from '@testing-library/react';
import { drawerSearchStepOneFixture } from '@/redux/drawer/drawerFixture';
import { DrawerHeadingBackwardButton } from './DrawerHeadingBackwardButton.component';
const backwardFunction = jest.fn();
......@@ -57,9 +58,7 @@ describe('DrawerHeadingBackwardButton - component', () => {
it('should call class drawer on close button click', () => {
const { store } = renderComponent('Title', 'value', {
drawer: {
isOpen: true,
drawerName: 'search',
searchDrawerState: { currentStep: 0, selectedValue: { name: '', valueType: 'none' } },
...drawerSearchStepOneFixture,
},
});
expect(store.getState().drawer.isOpen).toBe(true);
......
......@@ -11,10 +11,7 @@ export const Pin = ({ className }: PinOrangeProps): JSX.Element => (
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
d="M9 0C4.575 0 0 3.375 0 9C0 14.325 8.1 22.65 8.475 23.025C8.625 23.175 8.775 23.25 9 23.25C9.225 23.25 9.375 23.175 9.525 23.025C9.9 22.65 18 14.4 18 9C18 3.375 13.425 0 9 0ZM9 12C7.35 12 6 10.65 6 9C6 7.35 7.35 6 9 6C10.65 6 12 7.35 12 9C12 10.65 10.65 12 9 12Z"
fill="currentColor"
/>
<circle cx="9.0002" cy="8.99922" r="4.8" fill="currentColor" />
<path d="M9 0C4.575 0 0 3.375 0 9C0 14.325 8.1 22.65 8.475 23.025C8.625 23.175 8.775 23.25 9 23.25C9.225 23.25 9.375 23.175 9.525 23.025C9.9 22.65 18 14.4 18 9C18 3.375 13.425 0 9 0ZM9 12C7.35 12 6 10.65 6 9C6 7.35 7.35 6 9 6C10.65 6 12 7.35 12 9C12 10.65 10.65 12 9 12Z" />
<circle cx="9.0002" cy="8.99922" r="4.8" />
</svg>
);
export const assertNever = (value: never): never => {
throw new Error(`Unexpected value ${value}`);
};
......@@ -25,6 +25,8 @@ const config: Config = {
cultured: '#f7f7f8',
'white-pearl': '#ffffff',
divide: '#e1e0e6',
orange: '#f48c40',
purple: '#6400e3',
},
height: {
'calc-drawer': 'calc(100% - 104px)',
......
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