+ );
+}
+
+export default TimeOptions;
\ No newline at end of file
diff --git a/lib/clock.ts b/lib/clock.ts
new file mode 100644
index 00000000..2b065cf4
--- /dev/null
+++ b/lib/clock.ts
@@ -0,0 +1,43 @@
+// handles logic related to user clock display using 24h display / timeZone options.
+import dayjs, {Dayjs} from 'dayjs';
+
+interface TimeOptions { is24hClock: boolean, inviteeTimeZone: string };
+
+const timeOptions: TimeOptions = {
+ is24hClock: false,
+ inviteeTimeZone: '',
+}
+
+const isInitialized: boolean = false;
+
+const initClock = () => {
+ if (typeof localStorage === "undefined" || isInitialized) {
+ return;
+ }
+ timeOptions.is24hClock = localStorage.getItem('timeOption.is24hClock') === "true";
+ timeOptions.inviteeTimeZone = localStorage.getItem('timeOption.preferredTimeZone') || dayjs.tz.guess();
+}
+
+const is24h = (is24hClock?: boolean) => {
+ initClock();
+ if(typeof is24hClock !== "undefined") set24hClock(is24hClock);
+ return timeOptions.is24hClock;
+}
+
+const set24hClock = (is24hClock: boolean) => {
+ localStorage.setItem('timeOption.is24hClock', is24hClock.toString());
+ timeOptions.is24hClock = is24hClock;
+}
+
+function setTimeZone(selectedTimeZone: string) {
+ localStorage.setItem('timeOption.preferredTimeZone', selectedTimeZone);
+ timeOptions.inviteeTimeZone = selectedTimeZone;
+}
+
+const timeZone = (selectedTimeZone?: string) => {
+ initClock();
+ if (selectedTimeZone) setTimeZone(selectedTimeZone)
+ return timeOptions.inviteeTimeZone;
+}
+
+export {is24h, timeZone};
\ No newline at end of file
diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx
index aa57bd48..1a9d7c47 100644
--- a/pages/[user]/[type].tsx
+++ b/pages/[user]/[type].tsx
@@ -4,369 +4,221 @@ import Link from 'next/link';
import prisma from '../../lib/prisma';
import { useRouter } from 'next/router';
import dayjs, { Dayjs } from 'dayjs';
-import { Switch } from '@headlessui/react';
-import TimezoneSelect from 'react-timezone-select';
import { ClockIcon, GlobeIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
-import isBetween from 'dayjs/plugin/isBetween';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
-import Avatar from '../../components/Avatar';
dayjs.extend(isSameOrBefore);
-dayjs.extend(isBetween);
dayjs.extend(utc);
dayjs.extend(timezone);
-import getSlots from '../../lib/slots';
import {collectPageParameters, telemetryEventTypes, useTelemetry} from "../../lib/telemetry";
-
-function classNames(...classes) {
- return classes.filter(Boolean).join(' ')
-}
+import AvailableTimes from "../../components/booking/AvailableTimes";
+import TimeOptions from "../../components/booking/TimeOptions"
+import Avatar from '../../components/Avatar';
+import {timeZone} from "../../lib/clock";
export default function Type(props) {
- // Initialise state
- const [selectedDate, setSelectedDate] = useState();
- const [selectedMonth, setSelectedMonth] = useState(dayjs().month());
- const [loading, setLoading] = useState(false);
- const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
- const [is24h, setIs24h] = useState(false);
- const [busy, setBusy] = useState([]);
- const telemetry = useTelemetry();
- const [selectedTimeZone, setSelectedTimeZone] = useState('');
+ // Get router variables
+ const router = useRouter();
+ const { rescheduleUid } = router.query;
- function toggleTimeOptions() {
- setIsTimeOptionsOpen(!isTimeOptionsOpen);
- }
-
- function toggleClockSticky() {
- localStorage.setItem('timeOption.is24hClock', (!is24h).toString());
- setIs24h(!is24h);
- }
-
- function setPreferredTimeZoneSticky({ value }: string) {
- localStorage.setItem('timeOption.preferredTimeZone', value);
- setSelectedTimeZone(value);
- }
-
- function initializeTimeOptions() {
- setSelectedTimeZone(localStorage.getItem('timeOption.preferredTimeZone') || dayjs.tz.guess());
- setIs24h(!!localStorage.getItem('timeOption.is24hClock'));
- }
+ // Initialise state
+ const [selectedDate, setSelectedDate] = useState();
+ const [selectedMonth, setSelectedMonth] = useState(dayjs().month());
+ const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
+ const [timeFormat, setTimeFormat] = useState('hh:mm');
+ const telemetry = useTelemetry();
useEffect(() => {
telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.pageView, collectPageParameters()))
}, []);
- // Handle date change and timezone change
- useEffect(() => {
+ // Handle month changes
+ const incrementMonth = () => {
+ setSelectedMonth(selectedMonth + 1);
+ }
- if ( ! selectedTimeZone ) {
- initializeTimeOptions();
- }
+ const decrementMonth = () => {
+ setSelectedMonth(selectedMonth - 1);
+ }
- const changeDate = async () => {
- if (!selectedDate) {
- return
- }
+ // Set up calendar
+ var daysInMonth = dayjs().month(selectedMonth).daysInMonth();
+ var days = [];
+ for (let i = 1; i <= daysInMonth; i++) {
+ days.push(i);
+ }
- setLoading(true);
- const res = await fetch(`/api/availability/${user}?dateFrom=${lowerBound.utc().format()}&dateTo=${upperBound.utc().format()}`);
- const busyTimes = await res.json();
- if (busyTimes.length > 0) setBusy(busyTimes);
- setLoading(false);
- }
- changeDate();
- }, [selectedDate, selectedTimeZone]);
-
- // Get router variables
- const router = useRouter();
- const { user, rescheduleUid } = router.query;
-
- // Handle month changes
- const incrementMonth = () => {
- setSelectedMonth(selectedMonth + 1);
- }
-
- const decrementMonth = () => {
- setSelectedMonth(selectedMonth - 1);
- }
-
- // Need to define the bounds of the 24-hour window
- const lowerBound = useMemo(() => {
- if(!selectedDate) {
- return
- }
-
- return selectedDate.startOf('day')
- }, [selectedDate])
-
- const upperBound = useMemo(() => {
- if(!selectedDate) return
-
- return selectedDate.endOf('day')
- }, [selectedDate])
-
- // Set up calendar
- var daysInMonth = dayjs().month(selectedMonth).daysInMonth();
- var days = [];
- for (let i = 1; i <= daysInMonth; i++) {
- days.push(i);
- }
-
- // Create placeholder elements for empty days in first week
- let weekdayOfFirst = dayjs().month(selectedMonth).date(1).day();
- if (props.user.weekStart === 'Monday') {
- weekdayOfFirst -= 1;
- if (weekdayOfFirst < 0)
- weekdayOfFirst = 6;
- }
- const emptyDays = Array(weekdayOfFirst).fill(null).map((day, i) =>
-
- {null}
-
- );
-
- // Combine placeholder days with actual days
- const calendar = [...emptyDays, ...days.map((day) =>
-
- )];
-
- const times = useMemo(() =>
- getSlots({
- calendarTimeZone: props.user.timeZone,
- selectedTimeZone: selectedTimeZone,
- eventLength: props.eventType.length,
- selectedDate: selectedDate,
- dayStartTime: props.user.startTime,
- dayEndTime: props.user.endTime,
- })
- , [selectedDate, selectedTimeZone])
-
- // Check for conflicts
- for(let i = times.length - 1; i >= 0; i -= 1) {
- busy.forEach(busyTime => {
- let startTime = dayjs(busyTime.start);
- let endTime = dayjs(busyTime.end);
-
- // Check if start times are the same
- if (dayjs(times[i]).format('HH:mm') == startTime.format('HH:mm')) {
- times.splice(i, 1);
- }
-
- // Check if time is between start and end times
- if (dayjs(times[i]).isBetween(startTime, endTime)) {
- times.splice(i, 1);
- }
-
- // Check if slot end time is between start and end time
- if (dayjs(times[i]).add(props.eventType.length, 'minutes').isBetween(startTime, endTime)) {
- times.splice(i, 1);
- }
-
- // Check if startTime is between slot
- if(startTime.isBetween(dayjs(times[i]), dayjs(times[i]).add(props.eventType.length, 'minutes'))) {
- times.splice(i, 1);
- }
- });
- }
-
- // Display available times
- const availableTimes = times.map((time) =>
-