152 lines
4.0 KiB
JavaScript
152 lines
4.0 KiB
JavaScript
import React from 'react';
|
|
import FullCalendar from '@fullcalendar/react';
|
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
|
import interaction from '@fullcalendar/interaction';
|
|
import scrollGrid from '@fullcalendar/scrollgrid';
|
|
import { DateTime } from 'luxon';
|
|
import { Icon, IconButton } from 'rsuite';
|
|
|
|
// FullCalendar props
|
|
const dayMinWidth = 110;
|
|
const slotMinTime = '08:00:00';
|
|
const slotMaxTime = '18:00:00';
|
|
|
|
export default function IntervalSelector({
|
|
selectedDates,
|
|
handleSelect,
|
|
availability,
|
|
setAvailability,
|
|
}) {
|
|
/// DATES DISPLAY
|
|
let startDate = selectedDates[0].start;
|
|
// create a Datetime object from the last event date,
|
|
// add one day, and change it to a date string
|
|
let lastEventDate = selectedDates[selectedDates.length - 1].start;
|
|
let endDate = DateTime.fromFormat(lastEventDate, 'yyyy-MM-dd')
|
|
.plus({ days: 1 })
|
|
.toFormat('yyyy-MM-dd');
|
|
|
|
// Create an event dates list used to create the days columns
|
|
const daysList = [];
|
|
selectedDates.forEach((event) => {
|
|
daysList.push(event.start);
|
|
});
|
|
|
|
const handleDayDidMount = (info) => {
|
|
let currentDate = DateTime.fromJSDate(info.date).toFormat('yyyy-MM-dd');
|
|
if (!daysList.includes(currentDate)) {
|
|
info.el.remove();
|
|
}
|
|
};
|
|
const handleViewMount = ({ el }) => {
|
|
// Adapt column width to number of dates present
|
|
const timegridBody = el.querySelectorAll('div.fc-timegrid-body');
|
|
const timegridSlots = el.querySelectorAll(
|
|
'div.fc-timegrid-slots table',
|
|
);
|
|
// Update width based on rendered dates number
|
|
let newWidth = daysList.length * dayMinWidth;
|
|
timegridBody[0].style['min-width'] = `${newWidth}px`;
|
|
timegridSlots[0].style['min-width'] = `${newWidth}px`;
|
|
};
|
|
|
|
/// AVAILABILITY INTERACTION
|
|
// Create an array of stringified availability
|
|
let avListJson = [];
|
|
availability.forEach((event) => {
|
|
avListJson.push(JSON.stringify(event));
|
|
});
|
|
|
|
const handleClick = (eventStart, eventEnd) => {
|
|
let updatedAvailibility = [];
|
|
// Create an event object to compare
|
|
let currentAvailability = {
|
|
start: eventStart,
|
|
end: eventEnd,
|
|
};
|
|
// Make it to JSON
|
|
let currentAvJson = JSON.stringify(currentAvailability);
|
|
|
|
// Check if there's a similar event obj in the availability
|
|
let index = avListJson.findIndex(
|
|
(availability) => currentAvJson === availability,
|
|
);
|
|
if (index > -1) {
|
|
updatedAvailibility = [...availability];
|
|
updatedAvailibility.splice(index, 1);
|
|
}
|
|
|
|
setAvailability([...updatedAvailibility]);
|
|
};
|
|
|
|
const handleContent = ({ event }) => {
|
|
let eventStart = event.start;
|
|
let eventEnd = event.end;
|
|
|
|
let evStartDT = DateTime.fromJSDate(eventStart);
|
|
let evEndDT = DateTime.fromJSDate(eventEnd);
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
flexDirection: 'row',
|
|
}}
|
|
>
|
|
<p>
|
|
{evStartDT.toFormat('HH:mm')} -{' '}
|
|
{evEndDT.toFormat('HH:mm')}
|
|
</p>
|
|
<IconButton
|
|
className={'event-close'}
|
|
icon={<Icon icon='close' />}
|
|
appearance='default'
|
|
size='xs'
|
|
circle
|
|
onClick={() => handleClick(eventStart, eventEnd)}
|
|
></IconButton>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<FullCalendar
|
|
plugins={[dayGridPlugin, interaction, timeGridPlugin, scrollGrid]}
|
|
// timeZone={'UTC'}
|
|
events={availability}
|
|
// View props
|
|
headerToolbar={{ right: '' }}
|
|
initialView='timeGrid'
|
|
visibleRange={{
|
|
start: startDate,
|
|
end: endDate,
|
|
}}
|
|
allDaySlot={false}
|
|
dayMinWidth={dayMinWidth}
|
|
dayHeaderFormat={{
|
|
weekday: 'short',
|
|
day: 'numeric',
|
|
month: 'short',
|
|
omitCommas: true,
|
|
}}
|
|
slotMinTime={slotMinTime}
|
|
slotMaxTime={slotMaxTime}
|
|
dayCellDidMount={(arg) => handleDayDidMount(arg)}
|
|
dayHeaderDidMount={(arg) => handleDayDidMount(arg)}
|
|
viewDidMount={(arg) => handleViewMount(arg)}
|
|
// Interaction props
|
|
selectable={true}
|
|
unselectAuto={true}
|
|
selectOverlap={false}
|
|
select={(info) => handleSelect(info)}
|
|
longPressDelay={150}
|
|
eventContent={(arg) => handleContent(arg)}
|
|
/>
|
|
);
|
|
}
|