Skip to content

Commit

Permalink
display index updates to most currently modified date within range array
Browse files Browse the repository at this point in the history
header click events work correctly now based upon multidate and withRange
  • Loading branch information
akaidc2 committed Nov 17, 2017
1 parent c104d28 commit 8f02af9
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 32 deletions.
57 changes: 27 additions & 30 deletions src/Calendar/withMultipleRanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import classNames from 'classnames';
import {withDefaultProps} from './';
import {sanitizeDate, withImmutableProps} from '../utils';
import isBefore from 'date-fns/is_before';
import enhanceHeader from '../Header/withRange';
import enhanceHeader from '../Header/withMultipleRanges';
import format from 'date-fns/format';
import parse from 'date-fns/parse';
import styles from '../Day/Day.scss';

let isTouchDevice = false;

export const EVENT_TYPE = {
export const EVENT_TYPES = {
DELETE: 4,
END: 3,
HOVER: 2,
Expand Down Expand Up @@ -50,6 +50,7 @@ export const enhanceDay = withPropsOnChange(['selected'], ({date, selected, them
// Enhancer to handle selecting and displaying multiple dates
export const withMultipleRanges = compose(
withDefaultProps,
withState('displayIndex', 'setDisplayIndex', 0),
withState('scrollDate', 'setScrollDate', getInitialDate),
withState('displayKey', 'setDisplayKey', getInitialDate),
withState('selectionStart', 'setSelectionStart', null),
Expand All @@ -62,23 +63,25 @@ export const withMultipleRanges = compose(
DayComponent: enhanceDay(DayComponent),
HeaderComponent: enhanceHeader(HeaderComponent),
})),
withProps(({displayKey, passThrough, selected, setDisplayKey, ...props}) => ({
withProps(({displayKey, passThrough, selected, setDisplayKey, setDisplayIndex, displayIndex, ...props}) => ({
/* eslint-disable sort-keys */
passThrough: {
...passThrough,
Day: {
onClick: (date) => handleSelect(date, {selected, ...props}),
onClick: (date) => handleSelect(date, {selected, setDisplayIndex, ...props}),
handlers: {
onMouseOver: !isTouchDevice && props.selectionStart
? (e) => handleMouseOver(e, {selected, ...props})
: null,
},
},
Years: {
selected: selected && selected[displayKey],
onSelect: (date) => handleYearSelect(date, {displayKey, selected, ...props}),
selected: selected[displayIndex] && parse(selected[displayIndex][displayKey]),
onSelect: (date, e, callback) => handleYearSelect(date, callback),
},
Header: {
setDisplayIndex,
displayIndex,
onYearClick: (date, e, key) => setDisplayKey(key || 'start'),
},
},
Expand All @@ -98,42 +101,40 @@ function getSortedSelection({start, end}) {
: {start: end, end: start};
}

function handleSelect(date, {onSelect, selected, selectionStart, setSelectionStart, selectionStartIdx, setSelectionStartIdx}) {
function handleSelect(date, {onSelect, selected, selectionStart, setSelectionStart, selectionStartIdx, setSelectionStartIdx, setDisplayIndex}) {
const positionOfDate = determineIfDateAlreadySelected(date, selected);
const funcs = {onSelect, setSelectionStart, setSelectionStartIdx, setDisplayIndex};

if(positionOfDate.value && !selectionStart) { //selecting an already defined range
const selectedDate = selected[positionOfDate.index];//not clone so modding this is modding selected
selectedDate.end = date; //not possible to have start/end reversed when clicking on already set range
selectedDate.eventType = EVENT_TYPE.START;

onSelect(selected);
setSelectionStart(selectedDate.start);
setSelectionStartIdx(positionOfDate.index);//grab index of selected and set in state
} else if (selectionStart) { //ending new date range
updateSelectedState(positionOfDate.index, selectedDate.start, positionOfDate.index, selected, funcs);//grab index of selected and set in state
} else if (selectionStart) { //ending date range selection
if (positionOfDate.value === PositionTypes.START && !(date < selectionStart)) { //if in process and selecting start, assume they want to cancel
selected[selectionStartIdx].eventType = EVENT_TYPE.DELETE
onSelect(selected); //call twice to notify parent component something is about to be deleted
onSelect([...selected.slice(0, positionOfDate.index), ...selected.slice(positionOfDate.index+1)]);
const displayIdx = positionOfDate.index > 0 ? positionOfDate.index -1 : 0;
updateSelectedState(displayIdx, null, null, [...selected.slice(0, positionOfDate.index), ...selected.slice(positionOfDate.index+1)], funcs);
} else {
selected[selectionStartIdx] = { //modifying passed in object without clone due to immediate set state
eventType: EVENT_TYPE.END,
...getSortedSelection({
start: selectionStart,
end: date,
}),
};
onSelect(selected);
updateSelectedState(positionOfDate.index, null, null, selected, funcs);
}
setSelectionStart(null);
setSelectionStartIdx(null);
} else { //starting new date range
onSelect(selected.concat({eventType:EVENT_TYPE.START, start: date, end: date}));

setSelectionStart(date);
setSelectionStartIdx(selected.length);//accounts for increase due to concat
updateSelectedState(selected.length, date, selected.length, selected.concat({eventType:EVENT_TYPES.START, start: date, end: date}), funcs)//length accounts for increase due to concat
}
}

function updateSelectedState(displayIdx, selectStart, selectStartIdx, selected, {onSelect, setSelectionStart, setSelectionStartIdx, setDisplayIndex}) {
onSelect(selected);
setDisplayIndex(displayIdx);
setSelectionStart(selectStart);
setSelectionStartIdx(selectStartIdx);
}

function handleMouseOver(e, {onSelect, selectionStart, selectionStartIdx, selected}) {
const dateStr = e.target.getAttribute('data-date');
const date = dateStr && parse(dateStr);
Expand All @@ -142,7 +143,7 @@ function handleMouseOver(e, {onSelect, selectionStart, selectionStartIdx, select
if (selectionStartIdx === null) { return; }

selected[selectionStartIdx] = {
eventType: EVENT_TYPE.HOVER,
eventType: EVENT_TYPES.HOVER,
...getSortedSelection({
start: selectionStart,
end: date,
Expand All @@ -151,12 +152,8 @@ function handleMouseOver(e, {onSelect, selectionStart, selectionStartIdx, select
onSelect(selected);
}

function handleYearSelect(date, {displayKey, onSelect, selected, setScrollDate}) {

setScrollDate(date);
onSelect(getSortedSelection(
Object.assign({}, selected, {[displayKey]: parse(date)}))
);
function handleYearSelect(date, callback) {
callback(parse(date));
}

function getInitialDate({selected}) { //add
Expand Down
2 changes: 1 addition & 1 deletion src/Calendar/withRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const withRange = compose(
onSelect: (date) => handleYearSelect(date, {displayKey, selected, ...props}),
},
Header: {
onYearClick: (date, e, key) => setDisplayKey(key || 'start'),
onYearClick: (date, e, key) => setDisplayKey( key || 'start'),
},
},
selected: {
Expand Down
1 change: 1 addition & 0 deletions src/Header/defaultSelectionRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default function defaultSelectionRenderer(value, {
scrollToDate,
setDisplay,
shouldAnimate,
idx,
}) {
const date = parse(value);
const values = date && [
Expand Down
45 changes: 45 additions & 0 deletions src/Header/withMultipleRanges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import {withImmutableProps} from '../utils';
import defaultSelectionRenderer from './defaultSelectionRenderer';
import styles from './Header.scss';
import Slider from './Slider';

export default withImmutableProps(({renderSelection}) => ({
renderSelection: (values, props) => {
if (!values.length || !values[0].start && !values[0].end) {
return null;
}

const dates = values.sort(function (a, b) {
return a.start > b.start;
});
const index = props.displayIndex;

const dateFormat = props.locale && props.locale.headerFormat || 'MMM Do';

const dateElements = values.map((value, idx) => {
if (value.start === value.end) {
return defaultSelectionRenderer(value.start, {...props, key: value.start+idx});
} else {
return (
<div key={value.start+idx} className={styles.range} style={{color: props.theme.headerColor}}>
{defaultSelectionRenderer(value.start, {...props, dateFormat, idx, key: 'start', shouldAnimate: false})}
{defaultSelectionRenderer(value.end, {...props, dateFormat, idx, key: 'end', shouldAnimate: false})}
</div>
);
}
});
return (
<Slider
index={index !== -1 ? index : dates.length - 1}
onChange={chIndex =>
props.setDisplayIndex(chIndex, () =>
setTimeout(() => props.scrollToDate(dates[chIndex].start, 0, true), 50)
)
}
>
{dateElements}
</Slider>
);
},
}));
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export {withDateSelection} from './Calendar/withDateSelection';
export {withKeyboardSupport} from './Calendar/withKeyboardSupport';
export {withMultipleDates, defaultMultipleDateInterpolation} from './Calendar/withMultipleDates';
export {withRange, EVENT_TYPE} from './Calendar/withRange';
export {withMultipleRanges} from './Calendar/withMultipleRanges';
export {withMultipleRanges, EVENT_TYPES} from './Calendar/withMultipleRanges';

/*
* By default, Calendar is a controlled component.
Expand Down

0 comments on commit 8f02af9

Please sign in to comment.