React Timeline Block Past Event Creation
Get started with this exampleUsage
theme="ios" You can turn auto theming on and let it decide based on the platform.
Usage
themeVariant="light" You can turn auto dark mode on based on system settings.
Usage
clickToCreate={true}
// click to create is on dragToCreate={true}
// drag to create is on dragToMove={true}
// reordering is on dragToResize={true}
// resizing is on eventDelete={true}
// deleting is on Fine-tune drag & drop with these options, which are false by default.
Usage
locale={localeEn} Selecting the locale loads the localized settings and the translated UI text.
Block Past Event Creation
Sometimes we don't want users to be able to create events in the past or to alter past events. This might be role based in some cases or applied in general to the calendar.
To disable past event creation and manipulation, a couple of things need to be handled:
- Invalidate dates that are before today - this takes care of validating event drop and event creation on past dates
- Mark past events as fixed - to do this, set the
editableproperty of the event object tofalsefor the events that should remain fixed - Handle past occurrences of recurring events - recurring events are loaded as a single event and the occurrences are generated by the timeline. Moving the past occurrences need to be handled in the
onEventUpdateandonEventCreatelifecycle events - Give feedback to the user - optionally, a toast can be displayed to give feedback to the user why an event cannot be dropped, moved and created in the past. For this we can use the
onEventCreateFailedandonEventUpdateFailedlifecycle events
Demo

Code
View code on GitHub
import { Eventcalendar, getJson, setOptions, Toast } from '@mobiscroll/react';
import { useCallback, useEffect, useMemo, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const now = new Date(new Date().setMinutes(59));
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
function App() {
const [myEvents, setEvents] = useState([]);
const [isToastOpen, setToastOpen] = useState(false);
const [toastMessage, setToastMessage] = useState();
const myInvalid = useMemo(() => [{ recurring: { repeat: 'daily', until: yesterday } }, { start: today, end: now }], []);
const myResources = useMemo(
() => [
{ id: 1, name: 'Resource A', color: '#e20000' },
{ id: 2, name: 'Resource B', color: '#76e083' },
{ id: 3, name: 'Resource C', color: '#4981d6' },
{ id: 4, name: 'Resource D', color: '#e25dd2' },
{ id: 5, name: 'Resource E', color: '#1dab2f' },
{ id: 6, name: 'Resource F', color: '#d6d145' },
],
[],
);
const myView = useMemo(() => ({ timeline: { type: 'month' } }), []);
const handleEventCreateFailed = useCallback((args) => {
if (!args.originEvent) {
setToastMessage("Can't create event in the past");
setToastOpen(true);
}
}, []);
const handleEventUpdateFailed = useCallback((args) => {
if (!args.oldEventOccurrence) {
setToastMessage("Can't move event in the past");
setToastOpen(true);
}
}, []);
const handleEventCreate = useCallback((args) => {
const oldEvent = args.originEvent;
const start = oldEvent && oldEvent.start ? oldEvent.start : null;
// Handle recurring events
if (start && start < today) {
setToastMessage("Can't move past event");
setToastOpen(true);
return false;
}
}, []);
const handleEventUpdate = useCallback((args) => {
const oldEvent = args.oldEvent;
const start = oldEvent && oldEvent.start ? oldEvent.start : null;
const oldEventOccurrence = args.oldEventOccurrence;
const occurrenceStart = oldEventOccurrence && oldEventOccurrence.start ? oldEventOccurrence.start : null;
// Handle recurring events
if ((start && start < today) || (occurrenceStart && occurrenceStart < today)) {
return false;
}
}, []);
const handleCloseToast = useCallback(() => {
setToastOpen(false);
}, []);
useEffect(() => {
getJson(
'https://trial.mobiscroll.com/multiday-events/',
(events) => {
for (const event of events) {
// Convert dates to date objects
event.start = event.start ? new Date(event.start) : event.start;
event.end = event.end ? new Date(event.end) : event.end;
// Mark past events as fixed by setting the event.editable property to false
event.editable = event.start && today < event.start;
}
setEvents(events);
},
'jsonp',
);
}, []);
return (
<>
<Eventcalendar
className="md-disallow-past-event-creation"
view={myView}
data={myEvents}
resources={myResources}
invalid={myInvalid}
clickToCreate={true}
dragToCreate={true}
dragToMove={true}
dragToResize={true}
onEventCreateFailed={handleEventCreateFailed}
onEventUpdateFailed={handleEventUpdateFailed}
onEventCreate={handleEventCreate}
onEventUpdate={handleEventUpdate}
/>
<Toast message={toastMessage} isOpen={isToastOpen} onClose={handleCloseToast} />
</>
);
}
export default App;
import {
Eventcalendar,
getJson,
MbscCalendarEvent,
MbscEventcalendarView,
MbscEventCreateEvent,
MbscEventCreateFailedEvent,
MbscEventUpdateEvent,
MbscEventUpdateFailedEvent,
MbscResource,
setOptions,
Toast ,
} from '@mobiscroll/react';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const now = new Date(new Date().setMinutes(59));
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
const App: FC = () => {
const [myEvents, setEvents] = useState<MbscCalendarEvent[]>([]);
const [isToastOpen, setToastOpen] = useState<boolean>(false);
const [toastMessage, setToastMessage] = useState<string>('');
const myInvalid = useMemo(() => [{ recurring: { repeat: 'daily', until: yesterday } }, { start: today, end: now }], []);
const myResources = useMemo<MbscResource[]>(
() => [
{ id: 1, name: 'Resource A', color: '#e20000' },
{ id: 2, name: 'Resource B', color: '#76e083' },
{ id: 3, name: 'Resource C', color: '#4981d6' },
{ id: 4, name: 'Resource D', color: '#e25dd2' },
{ id: 5, name: 'Resource E', color: '#1dab2f' },
{ id: 6, name: 'Resource F', color: '#d6d145' },
],
[],
);
const myView = useMemo<MbscEventcalendarView>(() => ({ timeline: { type: 'month' } }), []);
const handleEventCreateFailed = useCallback((args: MbscEventCreateFailedEvent) => {
if (!args.originEvent) {
setToastMessage("Can't create event in the past");
setToastOpen(true);
}
}, []);
const handleEventUpdateFailed = useCallback((args: MbscEventUpdateFailedEvent) => {
if (!args.oldEventOccurrence) {
setToastMessage("Can't move event in the past");
setToastOpen(true);
}
}, []);
const handleEventCreate = useCallback((args: MbscEventCreateEvent) => {
const oldEvent = args.originEvent;
const start = oldEvent && oldEvent.start ? oldEvent.start : null;
// Handle recurring events
if (start && start < today) {
setToastMessage("Can't move past event");
setToastOpen(true);
return false;
}
}, []);
const handleEventUpdate = useCallback((args: MbscEventUpdateEvent) => {
const oldEvent = args.oldEvent;
const start = oldEvent && oldEvent.start ? oldEvent.start : null;
const oldEventOccurrence = args.oldEventOccurrence;
const occurrenceStart = oldEventOccurrence && oldEventOccurrence.start ? oldEventOccurrence.start : null;
// Handle recurring events
if ((start && start < today) || (occurrenceStart && occurrenceStart < today)) {
return false;
}
}, []);
const handleCloseToast = useCallback(() => {
setToastOpen(false);
}, []);
useEffect(() => {
getJson(
'https://trial.mobiscroll.com/multiday-events/',
(events) => {
for (const event of events) {
// Convert dates to date objects
event.start = event.start ? new Date(event.start) : event.start;
event.end = event.end ? new Date(event.end) : event.end;
// Mark past events as fixed by setting the event.editable property to false
event.editable = event.start && today < event.start;
}
setEvents(events);
},
'jsonp',
);
}, []);
return (
<>
<Eventcalendar
className="md-disallow-past-event-creation"
view={myView}
data={myEvents}
resources={myResources}
invalid={myInvalid}
clickToCreate={true}
dragToCreate={true}
dragToMove={true}
dragToResize={true}
onEventCreateFailed={handleEventCreateFailed}
onEventUpdateFailed={handleEventUpdateFailed}
onEventCreate={handleEventCreate}
onEventUpdate={handleEventUpdate}
/>
<Toast message={toastMessage} isOpen={isToastOpen} onClose={handleCloseToast} />
</>
);
};
export default App;
.md-disallow-past-event-creation .mbsc-readonly-event {
opacity: 0.6;
}