Calendar: implement basic recurrence support.

At the moment it only shows recurrence in the calendar. You can't edit
specific instances, only the whole series (the first event). You can't
event edit the rrule at the moment. It's view only (mostly).

While this is not much, this is already a major boost to the usability
of etesync web.

Fixes #15.
master
Tom Hacohen 6 years ago
parent 048c591b95
commit 0a9d4f8a10

@ -3,6 +3,7 @@ import BigCalendar, { View } from 'react-big-calendar';
import 'react-big-calendar/lib/css/react-big-calendar.css'; import 'react-big-calendar/lib/css/react-big-calendar.css';
import * as moment from 'moment'; import * as moment from 'moment';
import 'moment/locale/en-gb'; import 'moment/locale/en-gb';
import * as ICAL from 'ical.js';
import { EventType } from '../pim-types'; import { EventType } from '../pim-types';
@ -11,6 +12,9 @@ import './Calendar.css';
moment.locale('en-gb'); moment.locale('en-gb');
const calendarLocalizer = BigCalendar.momentLocalizer(moment); const calendarLocalizer = BigCalendar.momentLocalizer(moment);
const MAX_RECURRENCE_DATE = ICAL.Time.now();
MAX_RECURRENCE_DATE.adjust(800, 0, 0, 0);
function eventPropGetter(event: EventType) { function eventPropGetter(event: EventType) {
return { return {
style: { style: {
@ -60,12 +64,34 @@ class Calendar extends React.PureComponent {
} }
render() { render() {
const entries = [] as Array<EventType>;
this.props.entries.forEach((event) => {
entries.push(event);
if (event.isRecurring()) {
const recur = event.iterator();
let next = recur.next(); // Skip the first one
while ((next = recur.next())) {
if (next.compare(MAX_RECURRENCE_DATE) > 0) {
break;
}
const shift = next.subtractDateTz(event.startDate);
const ev = event.clone();
ev.startDate.addDuration(shift);
ev.endDate.addDuration(shift);
entries.push(ev);
}
}
});
return ( return (
<div style={{width: '100%', height: 'calc(100vh - 230px)', minHeight: 500}}> <div style={{width: '100%', height: 'calc(100vh - 230px)', minHeight: 500}}>
<BigCalendar <BigCalendar
defaultDate={new Date()} defaultDate={new Date()}
localizer={calendarLocalizer} localizer={calendarLocalizer}
events={this.props.entries} events={entries}
selectable={true} selectable={true}
onSelectEvent={this.props.onItemClick as any} onSelectEvent={this.props.onItemClick as any}
onSelectSlot={this.slotClicked as any} onSelectSlot={this.slotClicked as any}

@ -205,11 +205,20 @@ class EventEdit extends React.PureComponent {
}, },
}; };
const recurring = this.props.item && this.props.item.isRecurring;
return ( return (
<React.Fragment> <React.Fragment>
<h2> <h2>
{this.props.item ? 'Edit Event' : 'New Event'} {this.props.item ? 'Edit Event' : 'New Event'}
</h2> </h2>
{recurring && (
<div>
<span style={{ color: 'red' }}>IMPORTANT: </span>
This is a recurring event, for now, only editing the whole series
(by editing the first instance) is supported.
</div>
)}
{this.state.error && ( {this.state.error && (
<div>ERROR! {this.state.error}</div> <div>ERROR! {this.state.error}</div>
)} )}

@ -43,7 +43,9 @@ export class EventType extends ICAL.Event implements PimType {
} }
clone() { clone() {
return new EventType(new ICAL.Component(this.component.toJSON())); const ret = new EventType(new ICAL.Component(this.component.toJSON()));
ret.color = this.color;
return ret;
} }
} }

Loading…
Cancel
Save