From 5a242e940af2efaa9482b1c9b8e09fa6982a2aee Mon Sep 17 00:00:00 2001 From: Prachi Date: Fri, 21 Sep 2018 17:30:50 +0530 Subject: [PATCH 1/5] feat(DatePickerInput): Multiple date picker and block size of date picker input Select multiple dates using date picker input. Block size option for input of date picker. #114 --- src/DatePickerInput/makeStories.js | 13 ++++ src/DatePickerInput/web/DatePickerInput.js | 70 ++++++++++++++++------ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/DatePickerInput/makeStories.js b/src/DatePickerInput/makeStories.js index 845ce83..849851c 100644 --- a/src/DatePickerInput/makeStories.js +++ b/src/DatePickerInput/makeStories.js @@ -9,6 +9,19 @@ export default(storiesOf, { name="dob" /> )) + .add('block', () => ( + + )) + .add('multiple', () => ( + + )) .add('before today', () => ( { @@ -26,21 +35,34 @@ class DatePickerInput extends React.Component { } onDayClick = (day, modifiers) => { - const { name, onDateChange } = this.props; + const { name, onDateChange, multiple } = this.props; const { formik } = this.context; + let selectedDays = this.state.selectedDays ? [...this.state.selectedDays] : null; if (modifiers.disabled) { return; } + if (multiple && selectedDays) { + const dayIndex = selectedDays && selectedDays.findIndex((d) => DateUtils.isSameDay(d, day)); + if (dayIndex !== -1) { + selectedDays.splice(dayIndex, 1); + } else { + selectedDays = [...selectedDays, day]; + } + } else { + selectedDays = [day]; + } this.setState({ - isOpen: false, - selectedDay: day, + isOpen: !!multiple, + selectedDays, }, () => { if (formik && name) { formik.setFieldValue(name, this.formatDayForInput(day)); } - this.inputRef.blur(); + if (!multiple) { + this.inputRef.blur(); + } onDateChange(day, modifiers); }); } @@ -69,10 +91,14 @@ class DatePickerInput extends React.Component { }, 1); } - formatDayForInput = (day) => { + formatDayForInput = (days) => { const { format } = this.props; - if (day) { - return dateFnsFormat(day, format); + if (days && days.length) { + let dayInput = null; + days.forEach((day, index) => { + dayInput = `${dayInput || ''}${dateFnsFormat(day, format)}${days.length - 1 > index ? ', ' : ''}`; + }); + return dayInput; } return ''; } @@ -88,7 +114,7 @@ class DatePickerInput extends React.Component { render() { const { isOpen, - selectedDay, + selectedDays, } = this.state; const { @@ -102,6 +128,7 @@ class DatePickerInput extends React.Component { toMonth, renderDay, disabledDays, + block, } = this.props; return ( @@ -111,11 +138,12 @@ class DatePickerInput extends React.Component { name={name} label={label} defaultValue={this.formatDayForInput(defaultValue)} - value={this.formatDayForInput(selectedDay)} + value={this.formatDayForInput(selectedDays)} placeholder={placeholder} disabled={disabled} onFocus={this.onInputFocus} onBlur={this.onInputBlur} + block={block} autoComplete="off" /> { @@ -136,11 +164,14 @@ class DatePickerInput extends React.Component { numberOfMonths={1} fromMonth={fromMonth} toMonth={toMonth} - month={selectedDay} - selectedDays={[selectedDay]} + month={selectedDays ? + selectedDays[selectedDays.length - 1] + : selectedDays + } + selectedDays={selectedDays} disabledDays={disabledDays} modifiers={{ - start: [selectedDay], + start: selectedDays, }} navbarElement={} captionElement={() => null} @@ -163,7 +194,10 @@ DatePickerInput.propTypes = { name: PropTypes.string, label: PropTypes.string, placeholder: PropTypes.string, - defaultValue: PropTypes.instanceOf(Date), + defaultValue: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.instanceOf(Date)), + PropTypes.instanceOf(Date), + ]), disabled: PropTypes.bool, format: PropTypes.string, fromMonth: PropTypes.instanceOf(Date), @@ -171,6 +205,8 @@ DatePickerInput.propTypes = { renderDay: PropTypes.func, onDateChange: PropTypes.func, theme: PropTypes.object, + multiple: PropTypes.bool, + block: PropTypes.bool, disabledDays: PropTypes.oneOfType([ PropTypes.array, PropTypes.object, From 419eec9dd3054f7de3694229abc233ec1b698f25 Mon Sep 17 00:00:00 2001 From: Prachi Date: Thu, 27 Sep 2018 00:18:49 +0530 Subject: [PATCH 2/5] fix(DatePickerInput): changing input text for multiple date-picker #115 --- src/DatePickerInput/web/DatePickerInput.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/DatePickerInput/web/DatePickerInput.js b/src/DatePickerInput/web/DatePickerInput.js index b9a47c7..8c33dcb 100644 --- a/src/DatePickerInput/web/DatePickerInput.js +++ b/src/DatePickerInput/web/DatePickerInput.js @@ -92,13 +92,11 @@ class DatePickerInput extends React.Component { } formatDayForInput = (days) => { - const { format } = this.props; + const { format, multiple } = this.props; if (days && days.length) { - let dayInput = null; - days.forEach((day, index) => { - dayInput = `${dayInput || ''}${dateFnsFormat(day, format)}${days.length - 1 > index ? ', ' : ''}`; - }); - return dayInput; + return multiple + ? `${days.length} Date${days.length > 1 ? 's' : ''} selected` + : dateFnsFormat(days[0], format); } return ''; } From cf198bdb05b8a394cc3b0a5d22ff2fa472a06d6a Mon Sep 17 00:00:00 2001 From: Prachi Date: Wed, 16 Jan 2019 19:43:08 +0530 Subject: [PATCH 3/5] fix(datePickerInput): Fixing datePickerInput reset state issues 115 --- src/DatePickerInput/makeStories.js | 1 + src/DatePickerInput/web/DatePickerInput.js | 52 ++++++++++++------- .../web/DateRangePickerInput.js | 4 -- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/DatePickerInput/makeStories.js b/src/DatePickerInput/makeStories.js index 974554d..72a674d 100644 --- a/src/DatePickerInput/makeStories.js +++ b/src/DatePickerInput/makeStories.js @@ -15,6 +15,7 @@ export default(storiesOf, { )) .add('before today', () => ( diff --git a/src/DatePickerInput/web/DatePickerInput.js b/src/DatePickerInput/web/DatePickerInput.js index fa8fe5e..c084d65 100644 --- a/src/DatePickerInput/web/DatePickerInput.js +++ b/src/DatePickerInput/web/DatePickerInput.js @@ -14,10 +14,6 @@ import DatePickerNavbar from './DatePickerNavbar'; import injectDatePickerStyles from './injectDatePickerStyles'; class DatePickerInput extends React.Component { - datePickerHasFocus = false; - - timeout = {}; - constructor(props) { super(props); let selectedDays = null; @@ -41,10 +37,11 @@ class DatePickerInput extends React.Component { componentDidMount() { const { selectedDays } = this.state; - const { name, multiple, defaultValue } = this.props; + const { name } = this.props; const { formik } = this.context; + if (formik && name) { - formik.setFieldValue(name, multiple ? selectedDays || '' : defaultValue); + formik.setFieldValue(name, selectedDays || ''); } } @@ -53,13 +50,19 @@ class DatePickerInput extends React.Component { clearTimeout(this.timeout.datePickerBlur); } - makeDate = (date) => { - if (date && dateFnsIsValid(new Date(date))) { - const clonedDate = new Date(date); - clonedDate.setHours(12, 0, 0, 0); - return clonedDate; + makeDate = (dates) => { + const areDatesValid = dates && !dates.find( + (date) => !dateFnsIsValid(new Date(date)), + ); + + if (areDatesValid) { + return dates.map((date) => { + const clonedDate = new Date(date); + clonedDate.setHours(12, 0, 0, 0); + return clonedDate; + }); } - return undefined; + return []; } onDayClick = (day, modifiers) => { @@ -70,12 +73,14 @@ class DatePickerInput extends React.Component { return; } this.setState(({ selectedDays }) => { - let currSelectedDays; + let currSelectedDays = null; + + if (multiple && getIn(selectedDays, 'length')) { + currSelectedDays = [...selectedDays]; + const dayIndex = currSelectedDays.findIndex((d) => DateUtils.isSameDay(d, day)); - if (multiple && selectedDays) { - const dayIndex = selectedDays && selectedDays.findIndex((d) => DateUtils.isSameDay(d, day)); if (dayIndex !== -1) { - selectedDays.splice(dayIndex, 1); + currSelectedDays.splice(dayIndex, 1); } else { currSelectedDays = [...selectedDays, day]; } @@ -138,6 +143,13 @@ class DatePickerInput extends React.Component { this.inputRef = ref; } + updateSelectedDays = () => { + const { formik } = this.context; + const { name } = this.props; + + this.setState({ selectedDays: getIn(formik, `values[${name}]`) }); + } + render() { const { isOpen, @@ -169,6 +181,10 @@ class DatePickerInput extends React.Component { if (formik && name) { errorMessage = error || (getIn(formik.touched, name) && getIn(formik.errors, name)); errorMessage = errorMessage && errorMessage.replace(name, label || name); + + if (getIn(formik, `values[${name}]`) !== selectedDays) { + this.updateSelectedDays(); + } } return ( @@ -214,9 +230,9 @@ class DatePickerInput extends React.Component { fromMonth={fromMonth} toMonth={toMonth} month={ - selectedDays + getIn(selectedDays, 'length') ? selectedDays[selectedDays.length - 1] - : selectedDays + : null } selectedDays={selectedDays} disabledDays={disabledDays} diff --git a/src/DateRangePickerInput/web/DateRangePickerInput.js b/src/DateRangePickerInput/web/DateRangePickerInput.js index 6761b7d..b811c32 100644 --- a/src/DateRangePickerInput/web/DateRangePickerInput.js +++ b/src/DateRangePickerInput/web/DateRangePickerInput.js @@ -18,10 +18,6 @@ import injectDatePickerStyles from '../../DatePickerInput/web/injectDatePickerSt import DateRangePickerNavbar from './DateRangePickerNavbar'; class DateRangePickerInput extends React.Component { - datePickerHasFocus = false; - - timeout = {}; - constructor(props) { super(props); From f0f49c23788d8456d0a559334e5c2ee70e8dcdb4 Mon Sep 17 00:00:00 2001 From: Prachi Date: Thu, 17 Jan 2019 11:03:03 +0530 Subject: [PATCH 4/5] fix(datePickerInput/multiple-date-picker): fixing on-date-change for multiple date picker --- src/DatePickerInput/web/DatePickerInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatePickerInput/web/DatePickerInput.js b/src/DatePickerInput/web/DatePickerInput.js index c084d65..d1b9f77 100644 --- a/src/DatePickerInput/web/DatePickerInput.js +++ b/src/DatePickerInput/web/DatePickerInput.js @@ -101,7 +101,7 @@ class DatePickerInput extends React.Component { if (!multiple) { this.inputRef.blur(); } - onDateChange(day, modifiers); + onDateChange(multiple ? selectedDays : day, modifiers); }); } From b0a621874d6ffaa0bd79d18d9a9c39b18024012d Mon Sep 17 00:00:00 2001 From: Prachi Date: Tue, 22 Jan 2019 17:02:27 +0530 Subject: [PATCH 5/5] fix(datePickerInput/multiple-date-picker): addressing review comments --- src/DatePickerInput/web/DatePickerInput.js | 72 ++++++++++------------ 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/DatePickerInput/web/DatePickerInput.js b/src/DatePickerInput/web/DatePickerInput.js index d1b9f77..8a44694 100644 --- a/src/DatePickerInput/web/DatePickerInput.js +++ b/src/DatePickerInput/web/DatePickerInput.js @@ -12,19 +12,16 @@ import View from '../../View/web'; import TextInput from '../../TextInput/web'; import DatePickerNavbar from './DatePickerNavbar'; import injectDatePickerStyles from './injectDatePickerStyles'; +import pluralize from '../../utils/pluralize'; +import isEqual from '../../utils/isEqual'; class DatePickerInput extends React.Component { constructor(props) { super(props); - let selectedDays = null; - if (props.multiple && props.defaultValue) { - selectedDays = props.defaultValue; - } else if (props.defaultValue) { - selectedDays = [props.defaultValue]; - } + this.state = { isOpen: false, - selectedDays: this.makeDate(selectedDays), + selectedDays: this.makeDate([].concat(props.defaultValue)), }; this.datePickerHasFocus = false; this.timeout = {}; @@ -32,6 +29,7 @@ class DatePickerInput extends React.Component { componentWillMount = () => { const { theme } = this.props; + injectDatePickerStyles(theme); } @@ -45,17 +43,29 @@ class DatePickerInput extends React.Component { } } + componentWillReceiveProps(nextProps) { + const { formik } = this.context; + + if (formik && nextProps.name) { + const formikValues = getIn(formik.values, nextProps.name); + + this.setState((prevState) => { + if (!isEqual(formikValues, prevState.selectedDays)) { + return { selectedDays: this.makeDate([].concat(formikValues)) }; + } + + return null; + }); + } + } + componentWillUnmount = () => { clearTimeout(this.timeout.inputBlur); clearTimeout(this.timeout.datePickerBlur); } makeDate = (dates) => { - const areDatesValid = dates && !dates.find( - (date) => !dateFnsIsValid(new Date(date)), - ); - - if (areDatesValid) { + if (!dates.some((date) => !dateFnsIsValid(new Date(date || '')))) { return dates.map((date) => { const clonedDate = new Date(date); clonedDate.setHours(12, 0, 0, 0); @@ -72,25 +82,24 @@ class DatePickerInput extends React.Component { if (modifiers.disabled) { return; } - this.setState(({ selectedDays }) => { - let currSelectedDays = null; - if (multiple && getIn(selectedDays, 'length')) { - currSelectedDays = [...selectedDays]; - const dayIndex = currSelectedDays.findIndex((d) => DateUtils.isSameDay(d, day)); + this.setState((prevState) => { + let selectedDays = null; - if (dayIndex !== -1) { - currSelectedDays.splice(dayIndex, 1); + if (multiple && getIn(prevState.selectedDays, 'length')) { + if (prevState.selectedDays.some((selectedDay) => DateUtils.isSameDay(selectedDay, day))) { + selectedDays = prevState.selectedDays + .filter((selectedDay) => !DateUtils.isSameDay(day, selectedDay)); } else { - currSelectedDays = [...selectedDays, day]; + selectedDays = [...prevState.selectedDays, day]; } } else { - currSelectedDays = [day]; + selectedDays = [day]; } return { isOpen: !!multiple, - selectedDays: currSelectedDays, + selectedDays, }; }, () => { const { selectedDays } = this.state; @@ -133,7 +142,7 @@ class DatePickerInput extends React.Component { const { format, multiple } = this.props; if (days && days.length) { return multiple - ? `${days.length} Date${days.length > 1 ? 's' : ''} selected` + ? `${days.length} ${pluralize(days.length, 'Date', 'Dates')} selected` : dateFnsFormat(days[0], format); } return ''; @@ -143,13 +152,6 @@ class DatePickerInput extends React.Component { this.inputRef = ref; } - updateSelectedDays = () => { - const { formik } = this.context; - const { name } = this.props; - - this.setState({ selectedDays: getIn(formik, `values[${name}]`) }); - } - render() { const { isOpen, @@ -181,10 +183,6 @@ class DatePickerInput extends React.Component { if (formik && name) { errorMessage = error || (getIn(formik.touched, name) && getIn(formik.errors, name)); errorMessage = errorMessage && errorMessage.replace(name, label || name); - - if (getIn(formik, `values[${name}]`) !== selectedDays) { - this.updateSelectedDays(); - } } return ( @@ -229,11 +227,7 @@ class DatePickerInput extends React.Component { numberOfMonths={1} fromMonth={fromMonth} toMonth={toMonth} - month={ - getIn(selectedDays, 'length') - ? selectedDays[selectedDays.length - 1] - : null - } + month={selectedDays.slice(-1)[0]} selectedDays={selectedDays} disabledDays={disabledDays} modifiers={{