Fix Date2 component

This commit is contained in:
SachaG 2019-02-08 16:57:18 +09:00
parent 868c36cadd
commit ea3b5d7d27
2 changed files with 103 additions and 42 deletions

View file

@ -46,6 +46,9 @@ addStrings('en', {
'forms.delete_confirm': 'Delete document?',
'forms.revert': 'Revert',
'forms.confirm_discard': 'Discard changes?',
'forms.day': 'Day',
'forms.month': 'Month',
'forms.year': 'Year',
'users.profile': 'Profile',
'users.complete_profile': 'Complete your Profile',

View file

@ -1,6 +1,7 @@
import React, { PureComponent } from 'react';
import { Components, registerComponent } from 'meteor/vulcan:core';
import moment from 'moment';
import { FormattedMessage } from 'meteor/vulcan:i18n';
const isEmptyValue = value =>
typeof value === 'undefined' ||
@ -8,89 +9,146 @@ const isEmptyValue = value =>
value === '' ||
(Array.isArray(value) && value.length === 0);
const isValidYear = year => year && year.toString().length === 4;
const isValidDay = day => day && day.toString().length <= 2;
class DateComponent2 extends PureComponent {
state = {
year: null,
month: null,
day: null,
};
/*
Keep initial local state blank so that form state values are used instead
*/
state = {}
/*
Transform the value received from props into
three year/month/day properties, or else default to
empty strings for all three
*/
getDateObject = value => {
const mDate = !isEmptyValue(value) && moment(value);
return mDate ? {
year: mDate.format('YYYY'),
month: mDate.format('MMMM'),
day: mDate.format('D'),
} : {
year: '',
month: '',
day: '',
};
}
updateDate = date => {
const { value, path } = this.props;
const newState = { ...this.state, ...date };
const { year, month, day } = newState;
let newDate;
this.setState(date, () => {
const { year, month, day } = this.state;
if (isEmptyValue(value)) {
if (year && month && day) {
// wait until we have all three values to update the date
newDate = moment()
.year(year)
.month(month)
.date(day);
this.props.updateCurrentValues({ [path]: newDate.toDate() });
}
} else {
// update current date
newDate = moment(this.props.value);
if (year) newDate.year(year);
if (month) newDate.month(month);
if (day) newDate.date(day);
if (isEmptyValue(value)) { // if there is no date value yet
if (isValidYear(year) && month && isValidDay(day)) {
// wait until we have all three valid values to update the date in the form state
newDate = moment()
.year(year)
.month(month)
.date(day);
this.props.updateCurrentValues({ [path]: newDate.toDate() });
// clear our the local component state to avoid storing outdated or conflicting values
this.setState({ year: undefined, month: undefined, day: undefined });
} else {
// otherwise only update local state
this.setState(date);
}
});
} else {
// there is currently a date value in the form state
newDate = moment(this.props.value);
// by default, update all three values in local state
const updateStateObject = { ...date };
// update all three values separately; clear local state when updating a value in form state
if (isValidYear(year)) {
newDate.year(year);
updateStateObject.year = undefined;
}
if (month) {
newDate.month(month);
updateStateObject.month = undefined;
}
if (isValidDay(day)) {
newDate.date(day);
updateStateObject.day = undefined;
}
this.props.updateCurrentValues({ [path]: newDate.toDate() });
this.setState(updateStateObject);
}
};
render() {
const { path, value } = this.props;
const months = moment.months();
const mDate = !isEmptyValue(value) && moment(value);
const { path, value, inputProperties, itemProperties } = this.props;
const s = this.state;
const p = this.getDateObject(value);
/*
For values: if local *state* is defined we use that, else
we use value from form state passed through *props* and
split into month/day/year via getDateObject()
*/
const monthProperties = {
label: 'Month',
name: `${path}.month`,
layout: 'vertical',
options: months.map((m, i) => ({ label: m, value: m })),
value: (mDate && mDate.format('MMMM')) || '',
onChange: (name, value) => {
this.updateDate({ month: value });
options: moment.months().map((m, i) => ({ label: m, value: m })),
value: typeof s.month === 'undefined' ? p.month : s.month,
onChange: e => {
this.updateDate({ month: e.target.value });
},
};
const dayProperties = {
label: 'Day',
name: `${path}.day`,
layout: 'vertical',
maxLength: 2,
value: (mDate && mDate.format('DD')) || '',
onBlur: e => {
value: typeof s.day === 'undefined' ? p.day : s.day,
onChange: e => {
this.updateDate({ day: e.target.value });
},
};
const yearProperties = {
label: 'Year',
name: `${path}.year`,
layout: 'vertical',
maxLength: 4,
value: (mDate && mDate.format('YYYY')) || '',
onBlur: e => {
value: typeof s.year === 'undefined' ? p.year : s.year,
onChange: e => {
this.updateDate({ year: e.target.value });
},
};
// note: get rid of the default onChange inherited from FormComponent
const { onChange, ...newInputProperties } = inputProperties; // eslint-disable-line no-unused-vars
return (
<Components.FormItem {...this.props.inputProperties} {...this.props.itemProperties}>
<div>
<Components.FormItem {...newInputProperties} {...itemProperties}>
<div style={{ display: 'flex' }}>
<div>
<label>
<FormattedMessage id="forms.month" />
</label>
<Components.FormComponentSelect
inputProperties={monthProperties}
datatype={[{ type: String }]}
/>
</div>
<div style={{ marginLeft: 10, width: 60 }}>
<label>
<FormattedMessage id="forms.day" />
</label>
<Components.FormComponentText inputProperties={dayProperties} />
</div>
<div style={{ marginLeft: 10, width: 80 }}>
<label>
<FormattedMessage id="forms.year" />
</label>
<Components.FormComponentText inputProperties={yearProperties} />
</div>
</div>