-
-
Save AbhishekThorat/fd68cdfe759539c2fc41e519c50563d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import PropTypes from 'prop-types'; | |
import { accessor } from 'react-big-calendar/lib/utils/accessors'; | |
import { accessor as accessorPropType } from 'react-big-calendar/lib/utils/propTypes'; | |
import { noop } from 'lodash'; | |
import { zonedToLocal, localToZoned } from '/client/utils/timezones'; | |
import { hasTime, shiftDate, shiftHour } from '/client/utils/date'; | |
/** | |
* withTimeZone - HOC to add time zone support to react-big-calendar | |
* | |
* import Calendar from 'react-big-calendar'; | |
* import withTimeZone from './withTimeZone'; | |
* const ZonedCalendar = withTimeZone(Calendar) | |
* | |
* render() { | |
* return <ZonedCalendar zone="Pacific/Honolulu" ... /> | |
* } | |
*/ | |
export default function withTimeZone(Calendar) { | |
return class TimeZoneCalendar extends Component { | |
static propTypes = { | |
events: PropTypes.array, | |
date: PropTypes.instanceOf(Date).isRequired, | |
zone: PropTypes.string.isRequired, | |
startAccessor: accessorPropType, | |
endAccessor: accessorPropType, | |
allDayAccessor: accessorPropType, | |
onEventDrop: PropTypes.func, | |
onEventResize: PropTypes.func, | |
onSelectSlot: PropTypes.func | |
}; | |
static defaultProps = { | |
startAccessor: 'start', | |
endAccessor: 'end', | |
allDayAccessor: 'allDay', | |
onEventDrop: noop, | |
onEventResize: noop, | |
onSelectSlot: noop | |
}; | |
startAccessor = (event) => this.timeAccessor(event, 'startAccessor'); | |
endAccessor = (event) => this.timeAccessor(event, 'endAccessor'); | |
timeAccessor = (event, accessorName) => { | |
const value = accessor(event, this.props[accessorName]); | |
const allDay = accessor(event, this.props.allDayAccessor); | |
const zone = allDay ? 'UTC' : this.props.zone; | |
// see discussion in timeszones.js about zonedToLocal. allDay events are in UTC | |
return zonedToLocal(value, zone); | |
} | |
handleSelectSlot = ({ start, end, slots }) => { | |
// FIXME: this is basically the same logic as toZonedUpdate! DRY it out | |
const allDay = !hasTime(start) && !hasTime(end); | |
const zone = allDay ? 'UTC' : this.props.zone; | |
// r-b-c has no time zones - whatever time it says is really in the | |
// local time zone and we need to convert it to the same time in | |
// the target zones (except allDay events are always in UTC). | |
// | |
// also, when selecting allDay events, r-b-c gives the end time | |
// as an INCLUSIVE date (e.g. a one day allDay will start and end | |
// on the same date), but events have the end as an EXCLUSIVE time | |
// (e.g. one day events have end on the NEXT day) - so fix that here. | |
start = localToZoned(start, zone); | |
if (allDay) end = shiftDate(end, 1); // FIXME: does this really belong in withTimeZone - fix up with new r-b-c allDay, etc. | |
end = localToZoned(end, zone); | |
slots = slots.map(date => localToZoned(date, zone)); // TODO: I don't understand the slots arg to onSelectSlot | |
this.props.onSelectSlot({ start, end, allDay, slots }); | |
} | |
handleEventDrop = ({ event, start, end }) => | |
this.props.onEventDrop(this.toZonedUpdate({ event, start, end })); | |
handleResize = (resizeType, { event, start, end }) => | |
this.props.onEventResize(resizeType, this.toZonedUpdate({ event, start, end })); | |
toZonedUpdate = ({ event, start, end }) => { | |
// since we have nothing better, allDay is determined by the start date | |
// only because RBC computes the end date as start+duration | |
const allDay = !hasTime(start); | |
const zone = allDay ? 'UTC' : this.props.zone; | |
// if we're dropping an allDay event onto the grid (non-allDay), | |
// make a 1 hour event | |
if (event.allDay && !allDay) { | |
end = shiftHour(start, 1); | |
} | |
// TODO: there's a bug in rbc where dragging from a non-allDay | |
// to an allDay just returns the drag as if it was the same | |
// time on the new day, so alas, this case won't work: | |
// if (allDay && !event.allDay) { | |
// end = addOne(start, 'day'); | |
// } | |
// TODO: fix this in r-b-c | |
// just like selection, if we're creating an allDay event, | |
// create it in UTC zone. | |
start = localToZoned(start, zone); | |
end = localToZoned(end, zone); | |
return { event, start, end, allDay }; | |
} | |
render() { | |
const { date, zone, ...props } = this.props; | |
const bigCalendarProps = { | |
...props, | |
date: zonedToLocal(date, zone), | |
getNow: () => zonedToLocal(new Date(), zone), | |
startAccessor: this.startAccessor, | |
endAccessor: this.endAccessor, | |
onSelectSlot: this.handleSelectSlot, | |
onSelectEvent: this.handleSelectEvent, | |
onEventDrop: this.handleEventDrop, | |
onEventResize: this.handleResize | |
}; | |
return <Calendar {...bigCalendarProps} />; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment