From 056f56f5b448cdae92d82f64546a4b2344fbe72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Andr=C3=A9=20Lelis?= Date: Thu, 2 Apr 2020 16:32:27 -0300 Subject: [PATCH] refactor: StudyListFilter refactor (#1580) * Creating InputGroup * Updating Views with new InputGroup * Creating Docz for InputGroup * Fixing eslint issues * Renaming inputGroup props naming to be more generic. --- platform/ui/index.js | 19 +- .../ui/src/components/DateRange/DateRange.jsx | 103 ++++++----- .../src/components/InputGroup/InputGroup.jsx | 162 ++++++++++++++++++ .../src/components/InputGroup/InputGroup.mdx | 90 ++++++++++ .../ui/src/components/InputGroup/index.js | 2 + .../InputLabelWrapper/InputLabelWrapper.jsx | 2 + .../InputMultiSelect/InputMultiSelect.jsx | 2 +- platform/ui/src/components/index.js | 6 + .../ui/src/contextProviders/ModalProvider.js | 22 +-- .../components/Sidebar/index.js | 3 + platform/ui/src/utils/index.js | 4 + platform/ui/src/views/StudyList/StudyList.js | 17 +- .../StudyList/components/StudyListFilter.js | 83 ++++++--- 13 files changed, 418 insertions(+), 97 deletions(-) create mode 100644 platform/ui/src/components/InputGroup/InputGroup.jsx create mode 100644 platform/ui/src/components/InputGroup/InputGroup.mdx create mode 100644 platform/ui/src/components/InputGroup/index.js diff --git a/platform/ui/index.js b/platform/ui/index.js index 164ee9850..ac7f13282 100644 --- a/platform/ui/index.js +++ b/platform/ui/index.js @@ -1,5 +1,5 @@ /** UTILS */ -import * as utils from './src/utils/'; +import utils from './src/utils'; export { utils }; /** CONTEXT/HOOKS */ @@ -15,22 +15,25 @@ export { Button, ButtonGroup, DateRange, - InputDateRange, - InputMultiSelect, - InputText, - InputLabelWrapper, EmptyStudies, Icon, IconButton, + Input, + InputDateRange, + InputGroup, + InputLabelWrapper, + InputMultiSelect, + InputText, + Label, + NavBar, Select, Svg, - Input, - ThemeWrapper, Table, TableBody, + TableCell, TableHead, TableRow, - TableCell, + ThemeWrapper, Typography, } from './src/components'; diff --git a/platform/ui/src/components/DateRange/DateRange.jsx b/platform/ui/src/components/DateRange/DateRange.jsx index 6cc20d2c3..86814b121 100644 --- a/platform/ui/src/components/DateRange/DateRange.jsx +++ b/platform/ui/src/components/DateRange/DateRange.jsx @@ -4,36 +4,52 @@ import 'react-dates/lib/css/_datepicker.css'; import { DateRangePicker, isInclusivelyBeforeDay } from 'react-dates'; import './DateRange.css'; -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; -const DateRange = (props) => { +const today = moment(); +const lastWeek = moment().subtract(7, 'day'); +const lastMonth = moment().subtract(1, 'month'); +const studyDatePresets = [ + { + text: 'Today', + start: today, + end: today, + }, + { + text: 'Last 7 days', + start: lastWeek, + end: today, + }, + { + text: 'Last 30 days', + start: lastMonth, + end: today, + }, +]; + +const renderYearsOptions = () => { + const currentYear = moment().year(); + const options = []; + + for (let i = 0; i < 20; i++) { + const year = currentYear - i; + options.push( + + ); + } + + return options; +}; + +const DateRange = props => { const { onChange, startDate, endDate } = props; const [focusedInput, setFocusedInput] = useState(null); - - const today = moment(); - const lastWeek = moment().subtract(7, 'day'); - const lastMonth = moment().subtract(1, 'month'); - - const studyDatePresets = [ - { - text: 'Today', - start: today, - end: today, - }, - { - text: 'Last 7 days', - start: lastWeek, - end: today, - }, - { - text: 'Last 30 days', - start: lastMonth, - end: today, - }, - ]; + const renderYearsOptionsCallback = useCallback(renderYearsOptions, []); const renderDatePresets = () => { return ( @@ -60,35 +76,30 @@ const DateRange = (props) => { ); }; const renderMonthElement = ({ month, onMonthSelect, onYearSelect }) => { - const renderYearsOptions = () => { - const yearsRange = 20; - const options = []; - - for (let i = 0; i < yearsRange; i++) { - const year = moment().year() - i; - options.push( - - ); - } - - return options; - }; - renderMonthElement.propTypes = { month: PropTypes.object, onMonthSelect: PropTypes.func, onYearSelect: PropTypes.func, }; + const handleMonthChange = event => { + onMonthSelect(month, event.target.value); + }; + + const handleYearChange = event => { + onYearSelect(month, event.target.value); + }; + + const handleOnBlur = () => {}; + return (
- {}
@@ -120,7 +131,7 @@ const DateRange = (props) => { endDateId={'endDateId'} onDatesChange={onChange} focusedInput={focusedInput} - onFocusChange={(updatedVal) => setFocusedInput(updatedVal)} + onFocusChange={updatedVal => setFocusedInput(updatedVal)} /** OPTIONAL */ renderCalendarInfo={renderDatePresets} renderMonthElement={renderMonthElement} @@ -130,7 +141,7 @@ const DateRange = (props) => { closeDatePicker: 'Close', clearDates: 'Clear dates', }} - isOutsideRange={(day) => !isInclusivelyBeforeDay(day, moment())} + isOutsideRange={day => !isInclusivelyBeforeDay(day, moment())} hideKeyboardShortcutsPanel={true} numberOfMonths={1} showClearDates={false} diff --git a/platform/ui/src/components/InputGroup/InputGroup.jsx b/platform/ui/src/components/InputGroup/InputGroup.jsx new file mode 100644 index 000000000..8dba0ed98 --- /dev/null +++ b/platform/ui/src/components/InputGroup/InputGroup.jsx @@ -0,0 +1,162 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; + +import { + InputText, + InputDateRange, + InputMultiSelect, + InputLabelWrapper, +} from '@ohif/ui'; + +const InputGroup = ({ + inputMeta, + values, + onValuesChange, + sorting, + onSortingChange, + isSortingEnable, +}) => { + const { sortBy, sortDirection } = sorting; + + const handleFilterLabelClick = name => { + if (isSortingEnable) { + let _sortDirection = 'ascending'; + if (sortBy === name) { + if (sortDirection === 'ascending') { + _sortDirection = 'descending'; + } else if (sortDirection === 'descending') { + _sortDirection = 'none'; + } + } + + onSortingChange({ + sortBy: _sortDirection !== 'none' ? name : '', + sortDirection: _sortDirection, + }); + } + }; + + const renderFieldInputComponent = ({ + name, + displayName, + inputProps, + isSortable, + inputType, + }) => { + const _isSortable = isSortable && isSortingEnable; + const _sortDirection = sortBy !== name ? 'none' : sortDirection; + + const onLabelClick = () => { + handleFilterLabelClick(name); + }; + + const handleFieldChange = newValue => { + onValuesChange({ + ...values, + [name]: newValue, + }); + }; + + switch (inputType) { + case 'Text': + return ( + + ); + case 'MultiSelect': + return ( + + ); + case 'DateRange': + return ( + + ); + case 'None': + return ( + + ); + default: + break; + } + }; + return ( +
+
+ {inputMeta.map(inputMeta => { + return ( +
+ {renderFieldInputComponent(inputMeta)} +
+ ); + })} +
+
+ ); +}; + +InputGroup.propTypes = { + inputMeta: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + displayName: PropTypes.string.isRequired, + inputType: PropTypes.oneOf(['Text', 'MultiSelect', 'DateRange', 'None']) + .isRequired, + isSortable: PropTypes.bool.isRequired, + gridCol: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) + .isRequired, + option: PropTypes.arrayOf( + PropTypes.shape({ + value: PropTypes.string, + label: PropTypes.string, + }) + ), + }) + ).isRequired, + values: PropTypes.object.isRequired, + onValuesChange: PropTypes.func.isRequired, + sorting: PropTypes.shape({ + sortBy: PropTypes.string, + sortDirection: PropTypes.oneOf(['ascending', 'descending', 'none']), + }).isRequired, + onSortingChange: PropTypes.func.isRequired, + isSortingEnable: PropTypes.bool.isRequired, +}; + +export default InputGroup; diff --git a/platform/ui/src/components/InputGroup/InputGroup.mdx b/platform/ui/src/components/InputGroup/InputGroup.mdx new file mode 100644 index 000000000..076b75a34 --- /dev/null +++ b/platform/ui/src/components/InputGroup/InputGroup.mdx @@ -0,0 +1,90 @@ +--- +name: InputGroup +menu: Components +route: components/InputGroup +--- + +import { useState } from 'react'; +import { Playground, Props } from 'docz'; +import { InputGroup } from '@ohif/ui'; + +# Input Group + +## Import + +```javascript +import { InputGroup } from '@ohif/ui'; +``` + +## Basic usage + + + {() => { + const [filterValues, setFilterValues] = useState({ + patient: '', + studyDate: { + startDate: null, + endDate: null, + }, + modality: [], + }); + const [filterSorting, setFilterSorting] = useState({ + sortBy: '', + sortDirection: 'none', + }); + const filtersMeta = [ + { + name: 'patient', + displayName: 'Patient Name', + inputType: 'Text', + isSortable: true, + gridCol: 6, + }, + { + name: 'studyDate', + displayName: 'Study date', + inputType: 'DateRange', + isSortable: true, + gridCol: 6, + }, + { + name: 'modality', + displayName: 'Modality', + inputType: 'MultiSelect', + inputProps: { + options: [ + { value: 'SEG', label: 'SEG' }, + { value: 'CT', label: 'CT' }, + { value: 'MR', label: 'MR' }, + { value: 'SR', label: 'SR' }, + ], + }, + isSortable: true, + gridCol: 6, + }, + { + name: 'numberOfInstance', + displayName: 'Number of Instances', + inputType: 'None', + isSortable: true, + gridCol: 6, + }, + ]; + return ( +
+ +
+ ); + }} +
+ +## Properties + + diff --git a/platform/ui/src/components/InputGroup/index.js b/platform/ui/src/components/InputGroup/index.js new file mode 100644 index 000000000..2c20c333d --- /dev/null +++ b/platform/ui/src/components/InputGroup/index.js @@ -0,0 +1,2 @@ +import InputGroup from './InputGroup'; +export default InputGroup; diff --git a/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx b/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx index 3ed1868ad..f80dfccdb 100644 --- a/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx +++ b/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx @@ -24,9 +24,11 @@ const InputLabelWrapper = ({ return (