Skip to content

Commit

Permalink
Add Search bar solid choice control
Browse files Browse the repository at this point in the history
  • Loading branch information
vesnushka committed Dec 2, 2024
1 parent 1507cfb commit d643fcd
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Col } from 'antd';

import { Select } from 'src/components/Select';
import { ValueSetOption } from 'src/services';

Expand All @@ -13,17 +11,15 @@ export function SelectChoiceColumn(props: SearchBarColumnChoiceTypeProps) {
const { onSelect, getOptionLabel, isOptionSelected } = useChoiceColumn(props);

return (
<Col>
<Select<ValueSetOption>
value={columnFilterValue.value}
options={options}
onChange={onSelect}
isOptionSelected={isOptionSelected}
isMulti={repeats}
getOptionLabel={getOptionLabel}
classNamePrefix="react-select"
placeholder={placeholder}
/>
</Col>
<Select<ValueSetOption>
value={columnFilterValue.value}
options={options}
onChange={onSelect}
isOptionSelected={isOptionSelected}
isMulti={repeats}
getOptionLabel={getOptionLabel}
classNamePrefix="react-select"
placeholder={placeholder}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Col } from 'antd';

import { AsyncSelect } from 'src/components/Select';

import { SearchBarColumnChoiceTypeProps } from '../../types';
Expand All @@ -12,17 +10,15 @@ export function ValueSetColumn(props: SearchBarColumnChoiceTypeProps) {
const { onSelect, isOptionSelected, getOptionLabel, debouncedLoadOptions } = useChoiceColumn(props);

return (
<Col>
<AsyncSelect
defaultOptions
loadOptions={debouncedLoadOptions}
value={columnFilterValue.value}
isMulti={repeats}
onChange={onSelect}
isOptionSelected={isOptionSelected}
getOptionLabel={getOptionLabel}
placeholder={placeholder}
/>
</Col>
<AsyncSelect
defaultOptions
loadOptions={debouncedLoadOptions}
value={columnFilterValue.value}
isMulti={repeats}
onChange={onSelect}
isOptionSelected={isOptionSelected}
getOptionLabel={getOptionLabel}
placeholder={placeholder}
/>
);
}
14 changes: 5 additions & 9 deletions src/components/SearchBar/SearchBarColumn/DateColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Col } from 'antd';

import { DatePicker } from 'src/components/DatePicker';

import { useDateColumn } from './hooks';
Expand All @@ -13,12 +11,10 @@ export function DateColumn(props: SearchBarColumnDateTypeProps) {
const { onColumnChange } = useDateColumn(props);

return (
<Col>
<RangePicker
placeholder={columnFilterValue.column.placeholder}
value={columnFilterValue.value}
onChange={onColumnChange}
/>
</Col>
<RangePicker
placeholder={columnFilterValue.column.placeholder}
value={columnFilterValue.value}
onChange={onColumnChange}
/>
);
}
24 changes: 10 additions & 14 deletions src/components/SearchBar/SearchBarColumn/ReferenceColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Col } from 'antd';

import { AsyncSelect } from 'src/components/Select';
import { getAnswerCode, getAnswerDisplay } from 'src/utils/questionnaire';

Expand All @@ -12,17 +10,15 @@ export function ReferenceColumn(props: SearchBarColumnReferenceTypeProps) {
const { debouncedLoadOptions, onOptionChange } = useReferenceColumn(props);

return (
<Col>
<AsyncSelect
onChange={onOptionChange}
value={columnFilterValue.value}
loadOptions={debouncedLoadOptions}
defaultOptions
getOptionLabel={(option) => getAnswerDisplay(option.value)}
getOptionValue={(option) => getAnswerCode(option.value)}
isMulti={false}
placeholder={columnFilterValue.column.placeholder}
/>
</Col>
<AsyncSelect
onChange={onOptionChange}
value={columnFilterValue.value}
loadOptions={debouncedLoadOptions}
defaultOptions
getOptionLabel={(option) => getAnswerDisplay(option.value)}
getOptionValue={(option) => getAnswerCode(option.value)}
isMulti={false}
placeholder={columnFilterValue.column.placeholder}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import _ from 'lodash';
import { useCallback } from 'react';

import { ValueSetOption } from 'src/services';

import { ChoiceColumnOption } from './types';
import { SearchBarColumnSolidChoiceTypeProps } from '../types';

export function useSolidChoiceColumn(props: SearchBarColumnSolidChoiceTypeProps) {
const { columnFilterValue, onChange } = props;
const { id, options } = columnFilterValue.column;

const onSelect = useCallback(
(code: string) => {
if (!code) {
return onChange(null, id);
}

const option = options.find((o) => o.code === code);

if (!option) {
return onChange(null, id);
}

onChange([option], id);
},
[id, options, onChange],
);

const isOptionSelected = (option: ChoiceColumnOption) => {
return !!columnFilterValue.value && columnFilterValue.value?.findIndex((v) => _.isEqual(v, option)) !== -1;
};

const getOptionLabel = (option: ValueSetOption) => {
return option?.value?.Coding?.display || '';
};

return {
onSelect,
isOptionSelected,
getOptionLabel,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Radio } from 'antd';

import { useSolidChoiceColumn } from './hooks';
import { SearchBarColumnSolidChoiceTypeProps } from '../types';

export function SolidChoiceColumn(props: SearchBarColumnSolidChoiceTypeProps) {
const { columnFilterValue } = props;
const { options, defaultValue } = columnFilterValue.column;

const { onSelect } = useSolidChoiceColumn(props);

return (
<Radio.Group defaultValue={defaultValue?.code} optionType="button" onChange={(e) => onSelect(e.target.value)}>
{options.map((c) => (
<Radio.Button key={c.code} value={c.code}>
{c.display}
</Radio.Button>
))}
</Radio.Group>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { PropsValue } from 'react-select';

import { ValueSetOption } from 'src/services';

import { SolidChoiceTypeColumnFilterValue } from '../../types';

export type ChoiceColumnOption = PropsValue<ValueSetOption | SolidChoiceTypeColumnFilterValue['value']>;
14 changes: 6 additions & 8 deletions src/components/SearchBar/SearchBarColumn/StringColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Col, Input } from 'antd';
import { Input } from 'antd';

import { useStringColumn } from './hooks';
import { SearchBarColumnStringTypeProps } from '../types';
Expand All @@ -9,12 +9,10 @@ export function StringColumn(props: SearchBarColumnStringTypeProps) {
const { onColumnChange } = useStringColumn(props);

return (
<Col>
<Input.Search
placeholder={columnFilterValue.column.placeholder}
value={columnFilterValue.value}
onChange={onColumnChange}
/>
</Col>
<Input.Search
placeholder={columnFilterValue.column.placeholder}
value={columnFilterValue.value}
onChange={onColumnChange}
/>
);
}
11 changes: 11 additions & 0 deletions src/components/SearchBar/SearchBarColumn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { ChoiceColumn } from './ChoiceColumn';
import { DateColumn } from './DateColumn';
import { ReferenceColumn } from './ReferenceColumn';
import { SolidChoiceColumn } from './SolidChoiceColumn';
import { StringColumn } from './StringColumn';
import { SearchBarColumnProps } from './types';
import {
isStringColumnFilterValue,
isDateColumnFilterValue,
isReferenceColumnFilterValue,
isChoiceColumnFilterValue,
isSolidChoiceColumnFilterValue,
} from '../types';

export function SearchBarColumn(props: SearchBarColumnProps) {
Expand Down Expand Up @@ -45,5 +47,14 @@ export function SearchBarColumn(props: SearchBarColumnProps) {
return <ChoiceColumn {...choiceProps} />;
}

if (isSolidChoiceColumnFilterValue(columnFilterValue)) {
const choiceProps = {
...props,
columnFilterValue,
};

return <SolidChoiceColumn {...choiceProps} />;
}

return null;
}
6 changes: 6 additions & 0 deletions src/components/SearchBar/SearchBarColumn/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ChoiceTypeColumnFilterValue,
SolidChoiceTypeColumnFilterValue,
ColumnFilterValue,
DateTypeColumnFilterValue,
ReferenceTypeColumnFilterValue,
Expand Down Expand Up @@ -30,3 +31,8 @@ export interface SearchBarColumnChoiceTypeProps {
columnFilterValue: ChoiceTypeColumnFilterValue;
onChange: (value: ChoiceTypeColumnFilterValue['value'], key: string) => void;
}

export interface SearchBarColumnSolidChoiceTypeProps {
columnFilterValue: SolidChoiceTypeColumnFilterValue;
onChange: (value: SolidChoiceTypeColumnFilterValue['value'], key: string) => void;
}
15 changes: 14 additions & 1 deletion src/components/SearchBar/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import _ from 'lodash';
import { useCallback, useMemo, useState } from 'react';

import {
Expand All @@ -13,12 +12,15 @@ import {
SearchBarProps,
isChoiceColumn,
isChoiceColumnFilterValue,
isSolidChoiceColumn,
isSolidChoiceColumnFilterValue,
} from './types';
import {
validateStringColumnFilterValue,
validateDateColumnFilterValue,
validateReferenceColumnFilterValue,
validateChoiceColumnFilterValue,
validateSolidChoiceColumnFilterValue,
} from './validate';

export function useSearchBar(props: SearchBarProps): SearchBarData {
Expand All @@ -42,6 +44,10 @@ export function useSearchBar(props: SearchBarProps): SearchBarData {
return { column, value: null };
}

if (isSolidChoiceColumn(column)) {
return { column, value: null };
}

throw new Error('Unsupported column type');
});
}, [columns]);
Expand Down Expand Up @@ -86,6 +92,13 @@ export function useSearchBar(props: SearchBarProps): SearchBarData {
}
}

if (isSolidChoiceColumnFilterValue(newFilterValue)) {
if (validateSolidChoiceColumnFilterValue(value)) {
newFilterValue.value = value;
return newFilterValue;
}
}

throw new Error('Unsupported column type');
});
});
Expand Down
32 changes: 30 additions & 2 deletions src/components/SearchBar/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Coding } from 'fhir/r4b';

import { Expression, Resource, QuestionnaireItemChoiceColumn, ValueSet } from '@beda.software/aidbox-types';

import { ValueSetOption } from 'src/services';
Expand All @@ -8,6 +10,7 @@ export enum SearchBarColumnType {
DATE = 'date',
REFERENCE = 'reference',
CHOICE = 'choice',
SOLIDCHOICE = 'solidChoice',
}

export interface SearchBarProps {
Expand Down Expand Up @@ -46,11 +49,22 @@ export type SearchBarChoiceColumn = {
}
);

export type SearchBarSolidChoiceColumn = {
id: string;
type: SearchBarColumnType.SOLIDCHOICE;
repeats?: boolean;
placeholder: string;
options: Coding[];
valueSet?: never;
defaultValue?: Coding;
};

export type SearchBarColumn =
| SearchBarStringColumn
| SearchBarDateColumn
| SearchBarReferenceColumn
| SearchBarChoiceColumn;
| SearchBarChoiceColumn
| SearchBarSolidChoiceColumn;
export function isStringColumn(column: SearchBarColumn): column is SearchBarStringColumn {
return column.type === SearchBarColumnType.STRING;
}
Expand All @@ -63,6 +77,9 @@ export function isReferenceColumn(column: SearchBarColumn): column is SearchBarR
export function isChoiceColumn(column: SearchBarColumn): column is SearchBarChoiceColumn {
return column.type === SearchBarColumnType.CHOICE;
}
export function isSolidChoiceColumn(column: SearchBarColumn): column is SearchBarSolidChoiceColumn {
return column.type === SearchBarColumnType.SOLIDCHOICE;
}

export type DateColumnFilterValue = [moment.Moment, moment.Moment];

Expand All @@ -83,11 +100,17 @@ export interface ChoiceTypeColumnFilterValue {
value?: ValueSetOption[] | null;
}

export interface SolidChoiceTypeColumnFilterValue {
column: SearchBarSolidChoiceColumn;
value?: Coding[] | null;
}

export type ColumnFilterValue =
| StringTypeColumnFilterValue
| DateTypeColumnFilterValue
| ReferenceTypeColumnFilterValue
| ChoiceTypeColumnFilterValue;
| ChoiceTypeColumnFilterValue
| SolidChoiceTypeColumnFilterValue;
export function isStringColumnFilterValue(filterValue: ColumnFilterValue): filterValue is StringTypeColumnFilterValue {
return isStringColumn(filterValue.column);
}
Expand All @@ -102,6 +125,11 @@ export function isReferenceColumnFilterValue(
export function isChoiceColumnFilterValue(filterValue: ColumnFilterValue): filterValue is ChoiceTypeColumnFilterValue {
return isChoiceColumn(filterValue.column);
}
export function isSolidChoiceColumnFilterValue(
filterValue: ColumnFilterValue,
): filterValue is SolidChoiceTypeColumnFilterValue {
return isSolidChoiceColumn(filterValue.column);
}

export interface SearchBarData {
columnsFilterValues: ColumnFilterValue[];
Expand Down
Loading

0 comments on commit d643fcd

Please sign in to comment.