diff --git a/package.json b/package.json
index bb53770..b506a8f 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,8 @@
"@fullcalendar/interaction": "^5.0.0-beta.4",
"@fullcalendar/luxon": "^4.4.2",
"@fullcalendar/react": "^5.0.0-beta.4",
+ "@fullcalendar/scrollgrid": "5.0.0-beta.4",
+ "@fullcalendar/timegrid": "5.0.0-beta.4",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
diff --git a/src/components/Availability/IntervalSelector.js b/src/components/Availability/IntervalSelector.js
deleted file mode 100644
index e169c7e..0000000
--- a/src/components/Availability/IntervalSelector.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react'
-
-export default function IntervalSelector() {
- return (
-
- It's empty for now
-
- )
-}
diff --git a/src/components/Interval/IntervalSelector.js b/src/components/Interval/IntervalSelector.js
new file mode 100644
index 0000000..e9c8a70
--- /dev/null
+++ b/src/components/Interval/IntervalSelector.js
@@ -0,0 +1,153 @@
+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 (
+ <>
+
+
+ {evStartDT.toFormat('HH:mm')} -{' '}
+ {evEndDT.toFormat('HH:mm')}
+
+
}
+ appearance="default"
+ size="xs"
+ circle
+ onClick={() => handleClick(eventStart, eventEnd)}
+ >
+
+ >
+ );
+ };
+
+ return (
+ 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)}
+ />
+ );
+}
diff --git a/src/components/Navbar/MenuDropdown.js b/src/components/Navbar/MenuDropdown.js
index 1aabcbe..14cc006 100644
--- a/src/components/Navbar/MenuDropdown.js
+++ b/src/components/Navbar/MenuDropdown.js
@@ -18,7 +18,7 @@ export default function MenuDropdown() {
Login
Register
Dashboard
- Schedule a Meeting
+ Schedule a Meeting
Account Settings
Log Out
diff --git a/src/components/Schedule/DaySelector.js b/src/components/Schedule/DaySelector.js
index 8f81eaa..cdfc222 100644
--- a/src/components/Schedule/DaySelector.js
+++ b/src/components/Schedule/DaySelector.js
@@ -9,18 +9,18 @@ export default function DaySelector({ eventsList, handleSelect, handleClear }) {
return (
handleSelect(info)}
- defaultAllDay={true}
events={eventsList}
+ // view props
+ initialView='dayGridMonth'
+ defaultAllDay={true}
customButtons={{
resetSelection: { text: 'clear selection', click: handleClear },
}}
headerToolbar={{ right: 'resetSelection today prev,next' }}
+ // interaction props
+ selectable={true}
+ longPressDelay={150}
+ select={(info) => handleSelect(info)}
/>
);
}
diff --git a/src/screens/Availability/Availability.js b/src/screens/Availability/Availability.js
index c115001..ee9a50f 100644
--- a/src/screens/Availability/Availability.js
+++ b/src/screens/Availability/Availability.js
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
+
import {
Panel,
Form,
@@ -9,43 +10,32 @@ import {
Message,
FormGroup,
} from 'rsuite';
-import { DateTime } from 'luxon';
import NavBar from '../../components/Navbar/NavBar';
import TimezonePicker from '../../components/General/TimezonePicker';
-import IntervalSelector from '../../components/Availability/IntervalSelector';
+import IntervalSelector from '../../components/Interval/IntervalSelector';
import './Availability.less';
-const eventsList = [
- {
- start: '2020-06-10',
- display: 'background',
- },
- {
- start: '2020-06-11',
- display: 'background',
- },
- {
- start: '2020-06-12',
- display: 'background',
- },
- {
- start: '2020-06-13',
- display: 'background',
- },
-];
-
export default function Availability({ title }) {
- // const [eventsList, setEventsList] = useState([]);
- const [availability, setAvailability] = useState([]);
+ const [availability, setAvailability] = useState([...availabilityList]);
+
+ useEffect(() => {
+ console.log(availability);
+ }, [availability]);
const handleClear = () => {
setAvailability([]);
};
- const handleSelect = () => {
- console.log('Congrats, you have selected!');
+ const handleSelect = ({ start, end }) => {
+ let updatedEvents = [];
+ let newAvailability = {
+ start: start,
+ end: end,
+ };
+ updatedEvents.push(newAvailability);
+ setAvailability([...availability, ...updatedEvents]);
};
return (
@@ -95,7 +85,9 @@ export default function Availability({ title }) {
description='Select your availibility on the calendar.'
/>
@@ -106,18 +98,76 @@ export default function Availability({ title }) {
);
}
-// 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;
-};
-
const containerStyle = {
// TODO Move to a .less file
maxWidth: '1200px',
margin: '30px auto',
backgroundColor: 'rgba(255,255,255,0.6)',
};
+
+// TODO Remove fake data
+const eventsList = [
+ {
+ start: '2020-06-05',
+ display: 'background',
+ },
+ {
+ start: '2020-06-06',
+ display: 'background',
+ },
+ {
+ start: '2020-06-08',
+ display: 'background',
+ },
+ {
+ start: '2020-06-10',
+ display: 'background',
+ },
+ {
+ start: '2020-06-11',
+ display: 'background',
+ },
+ {
+ start: '2020-06-21',
+ display: 'background',
+ },
+ {
+ start: '2020-06-29',
+ display: 'background',
+ },
+];
+
+const availabilityList = [
+ {
+ start: '2020-06-08T08:00:00.000Z',
+ end: '2020-06-08T12:00:00.000Z',
+ },
+ {
+ start: '2020-06-10T09:00:00.000Z',
+ end: '2020-06-10T13:00:00.000Z',
+ },
+ {
+ start: '2020-06-11T09:00:00.000Z',
+ end: '2020-06-11T13:00:00.000Z',
+ },
+ {
+ start: '2020-06-11T06:30:00.000Z',
+ end: '2020-06-11T08:30:00.000Z',
+ },
+ {
+ start: '2020-06-21T07:00:00.000Z',
+ end: '2020-06-21T11:30:00.000Z',
+ },
+ {
+ start: '2020-06-21T12:00:00.000Z',
+ end: '2020-06-21T15:30:00.000Z',
+ },
+ {
+ start: '2020-06-06T08:00:00.000Z',
+ end: '2020-06-06T14:00:00.000Z',
+ },
+ {
+ start: '2020-06-05T10:30:00.000Z',
+ end: '2020-06-05T14:30:00.000Z',
+ },
+];
diff --git a/src/screens/Login.js b/src/screens/Login.js
index d019808..a9d2952 100644
--- a/src/screens/Login.js
+++ b/src/screens/Login.js
@@ -1,6 +1,6 @@
import React from 'react';
-import { Panel, Form, FormGroup, FormControl, ControlLabel, HelpBlock, Button } from 'rsuite';
+import { Panel, Form, FormGroup, FormControl, ControlLabel, Button } from 'rsuite';
import NavBar from './../components/Navbar/NavBar';
diff --git a/yarn.lock b/yarn.lock
index 8fd6bcf..98444e2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1061,7 +1061,7 @@
preact "^10.0.5"
tslib "^1.9.3"
-"@fullcalendar/daygrid@^5.0.0-beta.4":
+"@fullcalendar/daygrid@5.0.0-beta.4", "@fullcalendar/daygrid@^5.0.0-beta.4":
version "5.0.0-beta.4"
resolved "https://registry.yarnpkg.com/@fullcalendar/daygrid/-/daygrid-5.0.0-beta.4.tgz#b5616fddfe9a5496e5e98f20d6fafdcb6393a42e"
integrity sha512-ZWCF4dUCDngPqOJ3iUGl/ZiSOah8mgo9fayPR3WLazGMoQTsSAqMBGSuhFaNNdMDWQ+dhcT2JBa8e9DNoe2S+g==
@@ -1082,6 +1082,14 @@
resolved "https://registry.yarnpkg.com/@fullcalendar/luxon/-/luxon-4.4.2.tgz#27b4913abd6fb323da8fda63e1bd03df96b21815"
integrity sha512-NQFPsdDAyk152JzsyNMrfZWpnZUTxCrP3to/0es8Eoa97i/UxjxB5+N0SVwJqcNO0rQpaLHmeg5piHhraABShQ==
+"@fullcalendar/premium-common@5.0.0-beta.4":
+ version "5.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/@fullcalendar/premium-common/-/premium-common-5.0.0-beta.4.tgz#fd6571f2cba1026a9a42da8385c6e8febfdc7065"
+ integrity sha512-ZxmlzzjKAVy/xPP/HKkgxit0utPmHyjLw8Zj83KhmWHM7DRo9Eko0rNrSm/gDvsk0YkWpoiJRKcRRu022ulzLQ==
+ dependencies:
+ "@fullcalendar/common" "5.0.0-beta.4"
+ tslib "^1.9.3"
+
"@fullcalendar/react@^5.0.0-beta.4":
version "5.0.0-beta.4"
resolved "https://registry.yarnpkg.com/@fullcalendar/react/-/react-5.0.0-beta.4.tgz#9c721093bfb49f938469f93960a10894623e152c"
@@ -1090,6 +1098,24 @@
"@fullcalendar/common" "5.0.0-beta.4"
tslib "^1.9.3"
+"@fullcalendar/scrollgrid@5.0.0-beta.4":
+ version "5.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/@fullcalendar/scrollgrid/-/scrollgrid-5.0.0-beta.4.tgz#e4651af5f44b0156aa838b8a292358da9897d41c"
+ integrity sha512-E9pkjqW5+BDWXo07SBaHei7VMNR5OozzRXFGDRMU1W/u+BzMP4IypBp0M8wDtL78IoJK3fNsv49vOWsHi4x7Mg==
+ dependencies:
+ "@fullcalendar/common" "5.0.0-beta.4"
+ "@fullcalendar/premium-common" "5.0.0-beta.4"
+ tslib "^1.9.3"
+
+"@fullcalendar/timegrid@5.0.0-beta.4":
+ version "5.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/@fullcalendar/timegrid/-/timegrid-5.0.0-beta.4.tgz#e31b92772705738191617c9f1af4b91d27fcf8c6"
+ integrity sha512-kdI3NQ0Yt7bPxn0v6d01AyQeW5gKVPgGA8J2hsTpITkN/eaQJUxrmmOGEFhSVwvvJU0m+ji71Z30eKESNs/leA==
+ dependencies:
+ "@fullcalendar/common" "5.0.0-beta.4"
+ "@fullcalendar/daygrid" "5.0.0-beta.4"
+ tslib "^1.9.3"
+
"@hapi/address@2.x.x":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"