frontend/src/screens/Schedule.js

297 lines
7.3 KiB
JavaScript
Raw Normal View History

import React, { useState, useEffect } from 'react';
import {
Panel,
Form,
FormControl,
ControlLabel,
HelpBlock,
Button,
ButtonGroup,
Message,
FormGroup,
} from 'rsuite';
import { DateTime } from 'luxon';
2020-08-22 20:49:03 +00:00
import { useHistory } from 'react-router-dom';
2020-08-21 23:08:18 +00:00
import {
NavBar,
TimezonePicker,
DaySelector,
DurationSelector,
SelectedDates,
} from '../components';
2020-08-22 20:49:03 +00:00
import { backend } from '../helpers/http-common';
import { durations } from '../assets/data/durations';
2020-08-21 23:08:18 +00:00
import './styles/Schedule.less';
2020-08-22 20:49:03 +00:00
export default function Schedule({
possibleDates,
setPossibleDates,
currentMeeting,
setCurrentMeeting,
}) {
const [eventsList, setEventsList] = useState([]);
const [datesList, setDatesList] = useState(eventsToDates(eventsList));
2020-08-22 20:49:03 +00:00
const [durationIdx, setDurationIdx] = useState(0);
const [error, setError] = useState(false);
const history = useHistory();
2020-08-22 20:49:03 +00:00
useEffect(() => {
// Push the selected dates up the state tree
// but keep all related logic here
setPossibleDates(eventsList);
}, [eventsList, setPossibleDates]);
2020-08-22 20:49:03 +00:00
useEffect(() => {
2020-06-02 14:40:08 +00:00
let updatedDates = eventsToDates(eventsList).sort();
setDatesList(updatedDates);
}, [eventsList]);
// EVENTS & DATES
2020-08-22 20:49:03 +00:00
const handleSelectDates = (info) => {
let updatedEvents = [];
let datesList = new Set();
/// Add each date selected to datesList
let start = DateTime.fromISO(info.startStr);
let end = DateTime.fromISO(info.endStr);
// Check if selection contains only one day
let singleDay = end.toISODate() === start.plus({ days: 1 }).toISODate();
if (singleDay) {
// When a single date is selected
let selectedDate = info.startStr;
let selectedEvent = { start: selectedDate, display: 'background' };
// If selectedEvent exists in the list, find and set its index
let selectedEventIndex;
for (let index = 0; index < eventsList.length; index++) {
const eventDate = eventsList[index].start;
if (selectedDate === eventDate) {
// If it's the case, set current index to selectedEventIndex
selectedEventIndex = index;
break;
}
}
if (selectedEventIndex !== undefined) {
// If selectedEventIndex exists, remove the corresponding event from the list
eventsList.splice(selectedEventIndex, 1);
updatedEvents = [...eventsList];
} else {
// Add selected event to the list
updatedEvents = [...eventsList, selectedEvent];
}
} else {
// When a range of dates is selected
let currentDate = start;
while (!(+end === +currentDate)) {
// Add currentDate to the datesList
datesList.add(currentDate.toISODate());
let newDate = currentDate.plus({ days: 1 });
currentDate = newDate;
}
// Add each date from the eventsList to datesList
eventsList.forEach((event) => {
datesList.add(event.start);
});
// Create events from datesList and add them to updatedEvents
datesList.forEach((date) => {
updatedEvents.push({ start: date, display: 'background' });
});
}
setEventsList(updatedEvents);
};
const handleDelete = (date) => {
let currentEvent = {
start: date.toFormat('yyyy-MM-dd'),
display: 'background',
};
// Find the event corresponding to the date
let selectedEventIndex;
for (let index = 0; index < eventsList.length; index++) {
const eventDate = eventsList[index].start;
if (currentEvent.start === eventDate) {
// When it's the case, set current index to selectedEventIndex
selectedEventIndex = index;
break;
}
}
// Create updated eventsList
eventsList.splice(selectedEventIndex, 1);
let updatedEvents = [...eventsList];
// Update the eventsList
setEventsList(updatedEvents);
};
2020-08-22 20:49:03 +00:00
const handleClear = () => {
setEventsList([]);
};
// MEETING
const handleSchedule = () => {
backend
.post('/meetings', currentMeeting)
.then((response) => {
history.push('/availability');
})
.catch((error) => {
setError('Failed to add new account.');
});
};
const handleSelectTimezone = (value, item, event) => {
setCurrentMeeting({
...currentMeeting,
timezone: item.timezone,
});
};
const handleClean = (event) => {
setCurrentMeeting({
...currentMeeting,
timezone: '',
});
};
const handleChangeMeeting = (value, evt) => {
setCurrentMeeting({
...currentMeeting,
[evt.target.name]: value,
});
};
const handleIncrement = () => {
if (durationIdx <= durations.length - 2) {
setDurationIdx(durationIdx + 1);
}
setCurrentMeeting({
...currentMeeting,
duration: durations[durationIdx].duration,
});
};
const handleDecrement = () => {
if (durationIdx > 0) {
setDurationIdx(durationIdx - 1);
}
setCurrentMeeting({
...currentMeeting,
duration: durations[durationIdx].duration,
});
};
return (
<>
2020-08-19 18:04:52 +00:00
<NavBar title='Schedule a meeting' />
2020-08-21 23:08:18 +00:00
<Panel className={'app-container'}>
<Form className={'meeting-container'}>
<div className={'meeting-info'}>
<FormGroup>
<ControlLabel>Title</ControlLabel>
2020-08-22 20:49:03 +00:00
<FormControl
name='title'
type='text'
formValue={currentMeeting.title}
onChange={handleChangeMeeting}
/>
<HelpBlock>This field is required</HelpBlock>
</FormGroup>
<FormGroup>
<ControlLabel>Description</ControlLabel>
2020-08-22 20:49:03 +00:00
<FormControl
name='description'
componentClass='textarea'
type='text'
rows={3}
placeholder='(optional)'
2020-08-22 20:49:03 +00:00
formValue={currentMeeting.description}
onChange={handleChangeMeeting}
/>
</FormGroup>
<div className='meeting-options-inline'>
<FormGroup className='meeting-timezone'>
<ControlLabel>Timezone</ControlLabel>
2020-08-22 20:49:03 +00:00
<TimezonePicker
handleSelect={handleSelectTimezone}
handleClean={handleClean}
timezone={currentMeeting.timezone}
/>
</FormGroup>
<FormGroup className='meeting-duration'>
<ControlLabel>Duration</ControlLabel>
2020-08-22 20:49:03 +00:00
<DurationSelector
durationIdx={durationIdx}
handleDecrement={handleDecrement}
handleIncrement={handleIncrement}
/>
</FormGroup>
</div>
<ButtonGroup justified>
<Button
appearance='ghost'
block
size='lg'
disabled={datesList.length === 0}
onClick={() => handleClear()}
>
Clear selection
</Button>
<Button
appearance='primary'
size='lg'
block
disabled={datesList.length === 0}
2020-08-22 20:49:03 +00:00
onClick={handleSchedule}
>
Confirm dates
</Button>
2020-08-22 20:49:03 +00:00
{error && (
<Message type='error' description={error} />
)}
</ButtonGroup>
<div className={'selected-dates'}></div>
{datesList.length > 0 && (
<>
<SelectedDates
datesList={datesList}
handleDelete={handleDelete}
/>
</>
)}
</div>
<div className={'day-selector'}>
<Message
showIcon
type='info'
description='Select possible meetings dates on the calendar.'
/>
<DaySelector
eventsList={eventsList}
2020-08-22 20:49:03 +00:00
handleSelect={handleSelectDates}
handleClear={handleClear}
/>
</div>
</Form>
</Panel>
</>
);
}
// Convert events to Luxon Datetime objects
const eventsToDates = (events) => {
let dates = [];
events.forEach((event) => {
dates.push(DateTime.fromFormat(event.start, 'yyyy-MM-dd'));
});
return dates;
};