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",
"Layout": "Layout",
"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 CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import StudyList from './StudyList.json';
@ -13,6 +14,7 @@ export default {
Buttons,
CineDialog,
Common,
DatePicker,
Header,
MeasurementTable,
StudyList,

View File

@ -1,4 +1,5 @@
{
"Close": "Fechar",
"Image": "Imagem",
"Layout": "Layout",
"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 CineDialog from './CineDialog.json';
import Common from './Common.json';
import DatePicker from './DatePicker.json';
import Header from './Header.json';
import UserPreferencesModal from './UserPreferencesModal.json';
@ -11,6 +12,7 @@ export default {
Buttons,
CineDialog,
Common,
DatePicker,
Header,
UserPreferencesModal,
},

View File

@ -2,22 +2,23 @@
/* Will edit everything selected including everything between a range of dates */
.CalendarDay__selected_span {
background: var(--table-text-secondary-color);
color: #fff;
background: var(--datePicker-picker-background);
color: var(--datePicker-picker-text);
border-color: #e4e7e7;
}
/* Will edit selected date or the endpoints of a range of dates */
.CalendarDay__selected {
background: var(--table-text-secondary-color);
color: #fff;
background: var(--datePicker-picker-background);
color: var(--datePicker-picker-text);
border-color: #e4e7e7;
}
/* Will edit when hovered over. _span style also has this property */
.CalendarDay__selected:hover {
background: var(--table-text-secondary-color);
color: #fff;
.CalendarDay__selected:hover,
.CalendarDay__default:hover {
background: var(--datePicker-picker-background);
color: var(--datePicker-picker-text);
border-color: #e4e7e7;
}
@ -25,8 +26,8 @@
is not yet selected. Edits the dates between your mouse and said date */
.CalendarDay__hovered_span:hover,
.CalendarDay__hovered_span {
background: var(--table-text-secondary-color);
color: #fff;
background: var(--datePicker-picker-background);
color: var(--datePicker-picker-text);
border-color: #e4e7e7;
}
@ -42,15 +43,15 @@ is not yet selected. Edits the dates between your mouse and said date */
/* Container - visual */
.DateRangePickerInput {
width: calc(100% - 10px); /* Just use padding? */
background-color: var(--input-background-color);
border-color: var(--input-background-color);
color: var(--input-placeholder-color);
background-color: var(--datePicker-input-background);
border-color: var(--datePicker-input-background);
color: var(--datePicker-picker-text-input);
height: 40px;
}
.DateRangePickerInput.DateRangePickerInput__withBorder {
border-radius: 4px;
background-color: var(--input-background-color);
background-color: var(--datePicker-input-background);
}
/* Input Container */
@ -58,14 +59,14 @@ is not yet selected. Edits the dates between your mouse and said date */
width: 97px;
height: 38px;
border-radius: 4px;
background-color: var(--input-background-color);
background-color: var(--datePicker-input-background);
}
/* Actual Input Element */
.DateInput > .DateInput_input {
border-color: transparent;
background-color: transparent;
color: var(--input-placeholder-color);
color: var(--datePicker-picker-text-input);
height: 38px;
font-size: 10pt;
padding: 0;
@ -80,4 +81,39 @@ is not yet selected. Edits the dates between your mouse and said date */
.PresetDateRangePicker_button {
margin: 0;
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 PropTypes from 'prop-types';
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 {
static propTypes = {
presets: PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.string,
start: PropTypes.required,
end: PropTypes.required,
})
),
};
function CustomDateRangePicker(props) {
moment.locale(i18n.language); // using i18n in the date picker
constructor(props) {
super(props);
this.state = {
startDate: this.props.startDate,
endDate: this.props.endDate,
};
const { t } = useTranslation('DatePicker');
this.renderDatePresets = this.renderDatePresets.bind(this);
this.onDatesChange = this.onDatesChange.bind(this);
}
const {
onDatesChange,
startDate,
endDate,
presets,
...dateRangePickerProps
} = props;
onDatesChange({ startDate, endDate, preset }) {
this.setState({ startDate, endDate });
if (this.props.onDatesChange) {
this.props.onDatesChange({ startDate, endDate, preset });
}
}
renderDatePresets() {
const { presets } = this.props;
const { startDate, endDate } = this.state;
const renderDatePresets = () => {
const { presets } = props;
return (
<div className="PresetDateRangePicker_panel">
@ -54,7 +40,7 @@ export default class CustomDateRangePicker extends React.Component {
isSelected ? 'PresetDateRangePicker_button__selected' : ''
}`}
onClick={() =>
this.onDatesChange({
onDatesChange({
startDate: start,
endDate: end,
preset: true,
@ -67,30 +53,89 @@ export default class CustomDateRangePicker extends React.Component {
})}
</div>
);
}
};
const renderMonthElement = ({ month, onMonthSelect, onYearSelect }) => {
const containerStyle = {
margin: '0 5px',
};
render() {
let {
autoFocus,
autoFocusEndDate,
initialStartDate,
initialEndDate,
stateDateWrapper,
onDatesChange,
startDate,
endDate,
presets,
...dateRangePickerProps
} = this.props;
const renderYearsOptions = () => {
const yearsRange = 20;
const options = [];
for (let i = 0; i < yearsRange; i++) {
const year = moment().year() - i;
options.push(<option value={year}>{year}</option>);
}
return options;
};
renderMonthElement.propTypes = {
onMonthSelect: PropTypes.func,
onYearSelect: PropTypes.func,
};
return (
<DateRangePicker
{...dateRangePickerProps}
startDate={this.state.startDate}
endDate={this.state.endDate}
renderCalendarInfo={this.renderDatePresets}
onDatesChange={this.onDatesChange}
/>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div style={containerStyle}>
<select
className="DateRangePicker_select"
value={month.month()}
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,
onSelectItem: handleSelectItem,
t,
//
studyListDateFilterNumDays,
} = props;
@ -208,7 +207,6 @@ StudyList.propTypes = {
allFields: PropTypes.string.isRequired,
}).isRequired,
onFilterChange: PropTypes.func.isRequired,
//
studyListDateFilterNumDays: PropTypes.number,
};

View File

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

View File

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

View File

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

View File

@ -31,4 +31,12 @@
/** z-Index **/
--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;
}