import React, { useState, useEffect } from 'react'; import { Panel, Form, FormControl, ControlLabel, HelpBlock, Button, ButtonGroup, Message, FormGroup, } from 'rsuite'; import { DateTime } from 'luxon'; import { useHistory } from 'react-router-dom'; import { NavBar, DaySelector, DurationSelector, SelectedDates, } from '../components'; import { backend } from '../helpers/http-common'; import { durations } from '../assets/data/durations'; import './styles/Schedule.less'; export default function Schedule({ possibleDates, setPossibleDates, currentMeeting, setCurrentMeeting, currentUser, }) { const [eventsList, setEventsList] = useState([]); const [datesList, setDatesList] = useState(eventsToDates(eventsList)); const [durationIdx, setDurationIdx] = useState(0); const [error, setError] = useState(false); const history = useHistory(); useEffect(() => { // Push the selected dates up the state tree // but keep all related logic here setPossibleDates(eventsList); }, [eventsList, setPossibleDates]); useEffect(() => { let updatedDates = eventsToDates(eventsList).sort(); setDatesList(updatedDates); }, [eventsList]); // EVENTS & DATES 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); }; const handleClear = () => { setEventsList([]); }; // MEETING const handleSchedule = () => { // ADD THE MEETING backend .post('/meetings', currentMeeting) .then((response) => { setCurrentMeeting({ ...currentMeeting, id: response.data.id, }); addParticipant({ account_id: currentUser.id, meeting_id: response.data.id, quorum: 0, // 'false' while functionality not implemented mandatory: 0, // 'false' while functionality not implemented host: 1, answered: 0, }); history.push('/availability'); }) .catch((error) => { setError('Failed to add new meeting.'); }); const addParticipant = (data) => { backend .post('/participants', data) .then((response) => { addPossibleDates({ meeting_id: response.data.meeting_id }); }) .catch((error) => { setError( "Current user couldn't be set as participant to the meeting.", ); }); }; const addPossibleDates = ({ meeting_id }) => { // Post the possible dates and set add their ID to state const postPossibleDate = (data) => { return backend.post('/possible-dates', data); }; const createRequest = ({ start }) => { let data = { meeting_id, possible_date: start, }; return postPossibleDate(data); }; const requests = possibleDates.map((possibleDate) => createRequest(possibleDate), ); // Perform concurrent requests and update possible dates with id Promise.all(requests) .then(function (results) { const addID = ({ data }) => { let possibleDate = { id: data.id, start: data.possible_date.substring(0, 10), display: 'background', }; return possibleDate; }; const possibleDatesWithID = results.map((result) => addID(result), ); setPossibleDates(possibleDatesWithID); }) .catch((error) => { setError("Couldn't add possible dates to the meeting."); }); }; }; 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 ( <> Title This field is required Description Duration handleClear()} > Clear selection Confirm dates {error && } {datesList.length > 0 && ( <> > )} > ); } // 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; };