Skip to content

Commit

Permalink
Merge pull request #144 from onefinestay/allow-external-setting-of-dates
Browse files Browse the repository at this point in the history
Allow externally setting dates
  • Loading branch information
AlanFoster authored Oct 19, 2016
2 parents 7785f0a + d75e8c2 commit b2fa6ac
Show file tree
Hide file tree
Showing 14 changed files with 611 additions and 52 deletions.
44 changes: 44 additions & 0 deletions example/components/quick-selection/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import _ from 'underscore';
import Selection from './selection';

const QuickSelection = React.createClass({
propTypes: {
dates: React.PropTypes.object.isRequired,
value: React.PropTypes.object,
onSelect: React.PropTypes.func.isRequired,
},

isCurrentlySelected(date) {
const { value } = this.props;

if (!value) {
return false;
}

return date.isSame(value);
},

renderSelections() {
return _.map(this.props.dates, (date, label) => {
return (
<Selection key={label}
className='quickSelection__selection'
onSelect={this.props.onSelect}
date={date}
disabled={this.isCurrentlySelected(date)}
label={label} />
);
});
},

render() {
return (
<div className='quickSelection'>
{this.renderSelections()}
</div>
);
},
});

export default QuickSelection;
33 changes: 33 additions & 0 deletions example/components/quick-selection/selection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';

const Selection = React.createClass({
propTypes: {
className: React.PropTypes.string.isRequired,
date: React.PropTypes.object.isRequired,
disabled: React.PropTypes.bool.isRequired,
label: React.PropTypes.string.isRequired,
onSelect: React.PropTypes.func.isRequired,
},

getDefaultProps() {
return {
disabled: false,
};
},

onSelect() {
this.props.onSelect(this.props.date);
},

render() {
return (
<input className={this.props.className}
type='button'
onClick={this.onSelect}
disabled={this.props.disabled}
value={this.props.label} />
);
},
});

export default Selection;
27 changes: 27 additions & 0 deletions example/css/example.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,30 @@ input {
margin-top: 0;
}
}

.singleDateRange {
.DateRangePicker {
float: left;
width: 50%;
}

.quickSelection {
float: right;
width: 50%;
padding-top: 75px;

&__selection {
width: 100px;
padding: 6px;
margin: 0 auto 15px;
display: block;
float:none;
}
}
}

.rangeDateContainer {
.quickSelection {
padding-top: 10px;
}
}
107 changes: 102 additions & 5 deletions example/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import GithubRibbon from './components/github-ribbon';
import CodeSnippet from './components/code-snippet';
import Install from './components/install';
import Features from './components/features';
import QuickSelection from './components/quick-selection';


const today = moment();
// freeze date to April 1st
timekeeper.freeze(new Date('2016-04-01'));

Expand All @@ -24,7 +25,6 @@ function processCodeSnippet(src) {
return lines.join('\n');
}


const DatePickerRange = React.createClass({
propTypes: {
value: React.PropTypes.object,
Expand Down Expand Up @@ -89,13 +89,96 @@ const DatePickerSingle = React.createClass({
},
});

const DatePickerSingleWithSetDateButtons = React.createClass({
getInitialState() {
return {
value: null,
};
},

handleSelect(value) {
this.setState({ value });
},

setDate(value) {
this.setState({ value });
},

render() {
const dateRanges = {
'Today': today,
'Next Month': today.clone().add(1, 'month'),
'Last Month': today.clone().subtract(1, 'month'),

'Next Year': today.clone().add(1, 'year'),
'Last Year': today.clone().subtract(1, 'year'),
};

return (
<div className="singleDateRange">
<RangePicker {...this.props} onSelect={this.handleSelect} value={this.state.value} />
<QuickSelection dates={dateRanges} value={this.state.value} onSelect={this.setDate} />
<div>
<input type="text"
value={this.state.value ? this.state.value.format('LL') : null}
readOnly={true} />
</div>
</div>
);
},
});

const DatePickerRangeWithSetRangeButtons = React.createClass({
getInitialState() {
return {
value: null,
states: null,
};
},

handleSelect(value, states) {
this.setState({ value, states });
},

setRange(value){
this.setState({ value });
},

render() {
const dateRanges = {
'Last 7 days': moment.range(
today.clone().subtract(7, 'days'),
today.clone()
),
'This Year': moment.range(
today.clone().startOf('year'),
today.clone()
),
};

return (
<div className="rangeDateContainer">
<QuickSelection dates={dateRanges} value={this.state.value} onSelect={this.setRange} />
<RangePicker {...this.props} onSelect={this.handleSelect} value={this.state.value} />
<div>
<input type="text"
value={this.state.value ? this.state.value.start.format('LL') : null}
readOnly={true}
placeholder="Start date"/>
<input type="text"
value={this.state.value ? this.state.value.end.format('LL') : null}
readOnly={true}
placeholder="End date" />
</div>
</div>
);
},
});

var mainCodeSnippet = fs.readFileSync(__dirname + '/code-snippets/main.jsx', 'utf8');
var i18nCodeSnippet = fs.readFileSync(__dirname + '/code-snippets/i18n.jsx', 'utf8');


const Index = React.createClass({

getInitialState() {
return {
locale: 'en',
Expand Down Expand Up @@ -233,9 +316,23 @@ const Index = React.createClass({
</CodeSnippet>
</div>

<div className="example">
<h4>Setting Calendar Externally</h4>
<DatePickerSingleWithSetDateButtons
numberOfCalendars={1}
selectionType="single"
/>
</div>

<div className="example">
<h4>Setting Calendar Range Externally</h4>
<DatePickerRangeWithSetRangeButtons
numberOfCalendars={2}
selectionType="range"
/>
</div>
</div>
</div>

<Footer />
</main>
);
Expand Down
68 changes: 45 additions & 23 deletions src/DateRangePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import CalendarDate from './calendar/CalendarDate';
import PaginationArrow from './PaginationArrow';

import isMomentRange from './utils/isMomentRange';
import hasUpdatedValue from './utils/hasUpdatedValue';
import { getYearMonth, getYearMonthProps } from './utils/getYearMonth';

import PureRenderMixin from 'react-addons-pure-render-mixin';

Expand All @@ -22,7 +24,6 @@ const absoluteMaximum = moment(new Date(8640000000000000 / 2)).startOf('day');

function noop() {}


const DateRangePicker = React.createClass({
mixins: [BemMixin, PureRenderMixin],

Expand Down Expand Up @@ -92,18 +93,33 @@ const DateRangePicker = React.createClass({
},

componentWillReceiveProps(nextProps) {
var nextDateStates = this.getDateStates(nextProps);
var nextEnabledRange = this.getEnabledRange(nextProps);
const nextDateStates = this.getDateStates(nextProps);
const nextEnabledRange = this.getEnabledRange(nextProps);

this.setState({
const updatedState = {
selectedStartDate: null,
hideSelection: false,
dateStates: this.state.dateStates && Immutable.is(this.state.dateStates, nextDateStates) ? this.state.dateStates : nextDateStates,
enabledRange: this.state.enabledRange && this.state.enabledRange.isSame(nextEnabledRange) ? this.state.enabledRange : nextEnabledRange,
});
};

if (hasUpdatedValue(this.props, nextProps)) {
const isNewValueVisible = this.isStartOrEndVisible(nextProps);

if (!isNewValueVisible) {
const yearMonth = getYearMonthProps(nextProps);

updatedState.year = yearMonth.year;
updatedState.month = yearMonth.month;
}
}

this.setState(updatedState);
},

getInitialState() {
let now = new Date();
let {initialYear, initialMonth, initialFromValue, selectionType, value} = this.props;
let {initialYear, initialMonth, initialFromValue, value} = this.props;
let year = now.getFullYear();
let month = now.getMonth();

Expand All @@ -113,20 +129,15 @@ const DateRangePicker = React.createClass({
}

if (initialFromValue && value) {
if (selectionType === 'single') {
year = value.year();
month = value.month();
} else {
year = value.start.year();
month = value.start.month();
}
const yearMonth = getYearMonthProps(this.props);
month = yearMonth.month;
year = yearMonth.year;
}

return {
year: year,
month: month,
selectedStartDate: null,
highlightStartDate: null,
highlightedDate: null,
highlightRange: null,
hideSelection: false,
Expand Down Expand Up @@ -359,6 +370,24 @@ const DateRangePicker = React.createClass({
return moment(new Date(this.state.year, this.state.month, 1));
},

isStartOrEndVisible(props) {
const { value, selectionType, numberOfCalendars } = props;

const isVisible = (date) => {
const yearMonth = getYearMonth(date);
const isSameYear = (yearMonth.year === this.state.year);
const isMonthVisible = (yearMonth.month === this.state.month) || (numberOfCalendars === 2 && (yearMonth.month - 1 === this.state.month));

return isSameYear && isMonthVisible;
};

if (selectionType === 'single') {
return isVisible(value);
}

return isVisible(value.start) || isVisible(value.end);
},

canMoveBack() {
if (this.getMonthDate().subtract(1, 'days').isBefore(this.state.enabledRange.start)) {
return false;
Expand All @@ -372,10 +401,7 @@ const DateRangePicker = React.createClass({
if (this.canMoveBack()) {
monthDate = this.getMonthDate();
monthDate.subtract(1, 'months');
this.setState({
year: monthDate.year(),
month: monthDate.month(),
});
this.setState(getYearMonth(monthDate));
}
},

Expand All @@ -392,10 +418,7 @@ const DateRangePicker = React.createClass({
if (this.canMoveForward()) {
monthDate = this.getMonthDate();
monthDate.add(1, 'months');
this.setState({
year: monthDate.year(),
month: monthDate.month(),
});
this.setState(getYearMonth(monthDate));
}
},

Expand Down Expand Up @@ -439,7 +462,6 @@ const DateRangePicker = React.createClass({
highlightedDate,
highlightedRange,
} = this.state;

let monthDate = this.getMonthDate();
let year = monthDate.year();
let month = monthDate.month();
Expand Down
Loading

0 comments on commit b2fa6ac

Please sign in to comment.