fix: minor date picker UX improvements

* improvement: Date Picker

* remove unused values

* fix: search results w/ valid date returning empty

* translations from locize

* styling select

* revert studyListDateFilterNumDays
This commit is contained in:
Rodrigo Antinarelli 2019-11-18 18:30:47 -03:00 committed by Danny Brown
parent 6085b5f733
commit 813ee5ed4d
13 changed files with 188 additions and 83 deletions

View File

@ -1,4 +1,5 @@
{ {
"Close": "Close",
"Image": "Image", "Image": "Image",
"Layout": "Layout", "Layout": "Layout",
"Measurements": "Measurements", "Measurements": "Measurements",

View File

@ -0,0 +1,5 @@
{
"Clear dates": "Clear dates",
"End Date": "End Date",
"Start Date": "Start Date"
}

View File

@ -2,6 +2,7 @@ import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json'; import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json'; import CineDialog from './CineDialog.json';
import Common from './Common.json'; import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json'; import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json'; import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json'; import StudyList from './StudyList.json';
@ -13,6 +14,7 @@ export default {
Buttons, Buttons,
CineDialog, CineDialog,
Common, Common,
DatePicker,
Header, Header,
MeasurementTable, MeasurementTable,
StudyList, StudyList,

View File

@ -1,4 +1,5 @@
{ {
"Close": "Fechar",
"Image": "Imagem", "Image": "Imagem",
"Layout": "Layout", "Layout": "Layout",
"More": "Mais", "More": "Mais",

View File

@ -0,0 +1,5 @@
{
"Clear dates": "Limpar datas",
"End Date": "Data Final",
"Start Date": "Data Inicial"
}

View File

@ -2,6 +2,7 @@ import AboutModal from './AboutModal.json';
import Buttons from './Buttons.json'; import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json'; import CineDialog from './CineDialog.json';
import Common from './Common.json'; import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json'; import Header from './Header.json';
import UserPreferencesModal from './UserPreferencesModal.json'; import UserPreferencesModal from './UserPreferencesModal.json';
@ -11,6 +12,7 @@ export default {
Buttons, Buttons,
CineDialog, CineDialog,
Common, Common,
DatePicker,
Header, Header,
UserPreferencesModal, UserPreferencesModal,
}, },

View File

@ -2,22 +2,23 @@
/* Will edit everything selected including everything between a range of dates */ /* Will edit everything selected including everything between a range of dates */
.CalendarDay__selected_span { .CalendarDay__selected_span {
background: var(--table-text-secondary-color); background: var(--datePicker-picker-background);
color: #fff; color: var(--datePicker-picker-text);
border-color: #e4e7e7; border-color: #e4e7e7;
} }
/* Will edit selected date or the endpoints of a range of dates */ /* Will edit selected date or the endpoints of a range of dates */
.CalendarDay__selected { .CalendarDay__selected {
background: var(--table-text-secondary-color); background: var(--datePicker-picker-background);
color: #fff; color: var(--datePicker-picker-text);
border-color: #e4e7e7; border-color: #e4e7e7;
} }
/* Will edit when hovered over. _span style also has this property */ /* Will edit when hovered over. _span style also has this property */
.CalendarDay__selected:hover { .CalendarDay__selected:hover,
background: var(--table-text-secondary-color); .CalendarDay__default:hover {
color: #fff; background: var(--datePicker-picker-background);
color: var(--datePicker-picker-text);
border-color: #e4e7e7; border-color: #e4e7e7;
} }
@ -25,8 +26,8 @@
is not yet selected. Edits the dates between your mouse and said date */ is not yet selected. Edits the dates between your mouse and said date */
.CalendarDay__hovered_span:hover, .CalendarDay__hovered_span:hover,
.CalendarDay__hovered_span { .CalendarDay__hovered_span {
background: var(--table-text-secondary-color); background: var(--datePicker-picker-background);
color: #fff; color: var(--datePicker-picker-text);
border-color: #e4e7e7; border-color: #e4e7e7;
} }
@ -42,15 +43,15 @@ is not yet selected. Edits the dates between your mouse and said date */
/* Container - visual */ /* Container - visual */
.DateRangePickerInput { .DateRangePickerInput {
width: calc(100% - 10px); /* Just use padding? */ width: calc(100% - 10px); /* Just use padding? */
background-color: var(--input-background-color); background-color: var(--datePicker-input-background);
border-color: var(--input-background-color); border-color: var(--datePicker-input-background);
color: var(--input-placeholder-color); color: var(--datePicker-picker-text-input);
height: 40px; height: 40px;
} }
.DateRangePickerInput.DateRangePickerInput__withBorder { .DateRangePickerInput.DateRangePickerInput__withBorder {
border-radius: 4px; border-radius: 4px;
background-color: var(--input-background-color); background-color: var(--datePicker-input-background);
} }
/* Input Container */ /* Input Container */
@ -58,14 +59,14 @@ is not yet selected. Edits the dates between your mouse and said date */
width: 97px; width: 97px;
height: 38px; height: 38px;
border-radius: 4px; border-radius: 4px;
background-color: var(--input-background-color); background-color: var(--datePicker-input-background);
} }
/* Actual Input Element */ /* Actual Input Element */
.DateInput > .DateInput_input { .DateInput > .DateInput_input {
border-color: transparent; border-color: transparent;
background-color: transparent; background-color: transparent;
color: var(--input-placeholder-color); color: var(--datePicker-picker-text-input);
height: 38px; height: 38px;
font-size: 10pt; font-size: 10pt;
padding: 0; padding: 0;
@ -80,4 +81,39 @@ is not yet selected. Edits the dates between your mouse and said date */
.PresetDateRangePicker_button { .PresetDateRangePicker_button {
margin: 0; margin: 0;
padding: 4px 8px; padding: 4px 8px;
color: #00a699;
background: var(--datePicker-picker-text-input);
}
.PresetDateRangePicker_button:hover {
background: #00a699;
color: var(--datePicker-picker-text-input);
}
.CalendarDay__blocked_out_of_range:hover {
background: #fff;
cursor: not-allowed;
color: var(--datePicker-picker-text-disabled);
}
.DateRangePicker_select {
background-color: white;
color: var(--datePicker-picker-text);
border: 1px solid #e4e7e7;
border-radius: 4px;
display: inline-block;
padding: 3px 20px 3px 10px;
font-size: 14px;
cursor: pointer;
appearance: none;
background-image: linear-gradient(45deg, transparent 50%, gray 50%),
linear-gradient(135deg, gray 50%, transparent 50%);
background-position: calc(100% - 11px) 11px, calc(100% - 6px) calc(11px);
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
}
.DateRangePicker_select:hover {
border-color: #c4c4c4;
} }

View File

@ -7,39 +7,25 @@ import './CustomDateRangePicker.css';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DateRangePicker } from 'react-dates'; import { DateRangePicker } from 'react-dates';
import moment from 'moment';
import i18n from '@ohif/i18n';
import { useTranslation } from 'react-i18next';
export default class CustomDateRangePicker extends React.Component { function CustomDateRangePicker(props) {
static propTypes = { moment.locale(i18n.language); // using i18n in the date picker
presets: PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.string,
start: PropTypes.required,
end: PropTypes.required,
})
),
};
constructor(props) { const { t } = useTranslation('DatePicker');
super(props);
this.state = {
startDate: this.props.startDate,
endDate: this.props.endDate,
};
this.renderDatePresets = this.renderDatePresets.bind(this); const {
this.onDatesChange = this.onDatesChange.bind(this); onDatesChange,
} startDate,
endDate,
presets,
...dateRangePickerProps
} = props;
onDatesChange({ startDate, endDate, preset }) { const renderDatePresets = () => {
this.setState({ startDate, endDate }); const { presets } = props;
if (this.props.onDatesChange) {
this.props.onDatesChange({ startDate, endDate, preset });
}
}
renderDatePresets() {
const { presets } = this.props;
const { startDate, endDate } = this.state;
return ( return (
<div className="PresetDateRangePicker_panel"> <div className="PresetDateRangePicker_panel">
@ -54,7 +40,7 @@ export default class CustomDateRangePicker extends React.Component {
isSelected ? 'PresetDateRangePicker_button__selected' : '' isSelected ? 'PresetDateRangePicker_button__selected' : ''
}`} }`}
onClick={() => onClick={() =>
this.onDatesChange({ onDatesChange({
startDate: start, startDate: start,
endDate: end, endDate: end,
preset: true, preset: true,
@ -67,30 +53,89 @@ export default class CustomDateRangePicker extends React.Component {
})} })}
</div> </div>
); );
} };
const renderMonthElement = ({ month, onMonthSelect, onYearSelect }) => {
const containerStyle = {
margin: '0 5px',
};
render() { const renderYearsOptions = () => {
let { const yearsRange = 20;
autoFocus, const options = [];
autoFocusEndDate,
initialStartDate, for (let i = 0; i < yearsRange; i++) {
initialEndDate, const year = moment().year() - i;
stateDateWrapper, options.push(<option value={year}>{year}</option>);
onDatesChange, }
startDate,
endDate, return options;
presets, };
...dateRangePickerProps
} = this.props; renderMonthElement.propTypes = {
onMonthSelect: PropTypes.func,
onYearSelect: PropTypes.func,
};
return ( return (
<DateRangePicker <div style={{ display: 'flex', justifyContent: 'center' }}>
{...dateRangePickerProps} <div style={containerStyle}>
startDate={this.state.startDate} <select
endDate={this.state.endDate} className="DateRangePicker_select"
renderCalendarInfo={this.renderDatePresets} value={month.month()}
onDatesChange={this.onDatesChange} onChange={e => onMonthSelect(month, e.target.value)}
/> >
{moment.months().map((label, value) => (
<option key={value} value={value}>
{label}
</option>
))}
</select>
</div>
<div style={containerStyle}>
{}
<select
className="DateRangePicker_select"
value={month.year()}
onChange={e => onYearSelect(month, e.target.value)}
>
{renderYearsOptions()}
</select>
</div>
</div>
); );
} };
return (
<DateRangePicker
{...dateRangePickerProps}
startDate={startDate}
endDate={endDate}
renderCalendarInfo={renderDatePresets}
onDatesChange={onDatesChange}
renderMonthElement={renderMonthElement}
startDatePlaceholderText={t('Start Date')}
endDatePlaceholderText={t('End Date')}
phrases={{
closeDatePicker: t('Common:Close'),
clearDates: t('Clear dates'),
}}
/>
);
} }
CustomDateRangePicker.propTypes = {
presets: PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.string,
start: PropTypes.required,
end: PropTypes.required,
})
),
autoFocus: PropTypes.bool.isRequired,
onDatesChange: PropTypes.func.isRequired,
startDate: PropTypes.instanceOf(Date),
endDate: PropTypes.instanceOf(Date),
month: PropTypes.instanceOf(Date),
};
export default CustomDateRangePicker;

View File

@ -25,7 +25,6 @@ function StudyList(props) {
onFilterChange: handleFilterChange, onFilterChange: handleFilterChange,
onSelectItem: handleSelectItem, onSelectItem: handleSelectItem,
t, t,
//
studyListDateFilterNumDays, studyListDateFilterNumDays,
} = props; } = props;
@ -208,7 +207,6 @@ StudyList.propTypes = {
allFields: PropTypes.string.isRequired, allFields: PropTypes.string.isRequired,
}).isRequired, }).isRequired,
onFilterChange: PropTypes.func.isRequired, onFilterChange: PropTypes.func.isRequired,
//
studyListDateFilterNumDays: PropTypes.number, studyListDateFilterNumDays: PropTypes.number,
}; };

View File

@ -176,7 +176,7 @@ table.table
margin: 0 auto; margin: 0 auto;
color: var(--table-text-primary-color); color: var(--table-text-primary-color);
font-weight: 400; font-weight: 400;
padding: 20px; padding: 20px 8px;
user-select: none; user-select: none;
font-size: 15px; font-size: 15px;

View File

@ -6,8 +6,6 @@ import CustomDateRangePicker from './CustomDateRangePicker.js';
import { Icon } from './../../elements/Icon'; import { Icon } from './../../elements/Icon';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
function TableSearchFilter(props) { function TableSearchFilter(props) {
const { const {
meta, meta,
@ -17,7 +15,7 @@ function TableSearchFilter(props) {
sortFieldName, sortFieldName,
sortDirection, sortDirection,
// TODO: Rename // TODO: Rename
studyListDateFilterNumDays studyListDateFilterNumDays,
} = props; } = props;
const [focusedInput, setFocusedInput] = useState(null); const [focusedInput, setFocusedInput] = useState(null);
const [t] = useTranslation(); // 'Common'? const [t] = useTranslation(); // 'Common'?
@ -25,11 +23,13 @@ function TableSearchFilter(props) {
const sortIcons = ['sort', 'sort-up', 'sort-down']; const sortIcons = ['sort', 'sort-up', 'sort-down'];
const sortIconForSortField = const sortIconForSortField =
sortDirection === 'asc' ? sortIcons[1] : sortIcons[2]; sortDirection === 'asc' ? sortIcons[1] : sortIcons[2];
//
const today = moment(); const today = moment();
const lastWeek = moment().subtract(7, 'day'); const lastWeek = moment().subtract(7, 'day');
const lastMonth = moment().subtract(1, 'month'); const lastMonth = moment().subtract(1, 'month');
const defaultStartDate = moment().subtract(studyListDateFilterNumDays, 'days'); const defaultStartDate = moment().subtract(
studyListDateFilterNumDays,
'days'
);
const defaultEndDate = today; const defaultEndDate = today;
const studyDatePresets = [ const studyDatePresets = [
{ {
@ -82,8 +82,8 @@ function TableSearchFilter(props) {
endDateId="end-date" endDateId="end-date"
// TODO: We need a dynamic way to determine which fields values to update // TODO: We need a dynamic way to determine which fields values to update
onDatesChange={({ startDate, endDate, preset = false }) => { onDatesChange={({ startDate, endDate, preset = false }) => {
onValueChange('studyDateTo', startDate); onValueChange('studyDateFrom', startDate);
onValueChange('studyDateFrom', endDate); onValueChange('studyDateTo', endDate);
}} }}
focusedInput={focusedInput} focusedInput={focusedInput}
onFocusChange={updatedVal => setFocusedInput(updatedVal)} onFocusChange={updatedVal => setFocusedInput(updatedVal)}

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect, useContext } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Dropzone from 'react-dropzone';
import OHIF from '@ohif/core'; import OHIF from '@ohif/core';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -113,7 +112,8 @@ function StudyListRoute(props) {
pageNumber, pageNumber,
displaySize, displaySize,
server, server,
]); ]
);
// TODO: Update Server // TODO: Update Server
// if (this.props.server !== prevProps.server) { // if (this.props.server !== prevProps.server) {
@ -188,10 +188,12 @@ function StudyListRoute(props) {
} }
function handleFilterChange(fieldName, value) { function handleFilterChange(fieldName, value) {
const updatedFilterValues = Object.assign({}, filterValues); setFilterValues(state => {
return {
updatedFilterValues[fieldName] = value; ...state,
setFilterValues(updatedFilterValues); [fieldName]: value,
};
});
} }
return ( return (

View File

@ -31,4 +31,12 @@
/** z-Index **/ /** z-Index **/
--snackbar-zIndex: 10; --snackbar-zIndex: 10;
/** DatePicker Colors **/
--datePicker-input-background: #2c363f;
--datePicker-picker-background: #9ccef9;
--datePicker-picker-disabled: #d3d3d3;
--datePicker-picker-text: #484848;
--datePicker-picker-text-disabled: #aaa;
--datePicker-picker-text-input: #fff;
} }