frontend/src/components/Interval/IntervalSelector.js

154 lines
4.0 KiB
JavaScript

import React from 'react';
import { DateTime } from 'luxon';
import { Icon, IconButton } from 'rsuite';
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';
// 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)}
/>
);
}