From 394be8612b81f1683b05d1b0de5367287590d11a Mon Sep 17 00:00:00 2001 From: mihaic195 Date: Thu, 22 Jul 2021 15:16:21 +0300 Subject: [PATCH 01/70] fix: settings page was missing value prop and restyled dark theme elements on booking page --- pages/[user]/book.tsx | 8 ++++++-- pages/settings/profile.tsx | 15 ++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/pages/[user]/book.tsx b/pages/[user]/book.tsx index 34430e30..4bc1eea2 100644 --- a/pages/[user]/book.tsx +++ b/pages/[user]/book.tsx @@ -218,7 +218,9 @@ export default function Book(props: any): JSX.Element { {locations.length > 1 && (
- Location + + Location + {locations.map((location) => ( ))}
diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx index 6f7836eb..86f99256 100644 --- a/pages/settings/profile.tsx +++ b/pages/settings/profile.tsx @@ -12,6 +12,11 @@ import TimezoneSelect from "react-timezone-select"; import { UsernameInput } from "../../components/ui/UsernameInput"; import ErrorAlert from "../../components/ui/alerts/Error"; +const themeOptions = [ + { value: "light", label: "Light" }, + { value: "dark", label: "Dark" }, +]; + export default function Settings(props) { const [successModalOpen, setSuccessModalOpen] = useState(false); const usernameRef = useRef(); @@ -19,18 +24,13 @@ export default function Settings(props) { const descriptionRef = useRef(); const avatarRef = useRef(); const hideBrandingRef = useRef(); - const [selectedTheme, setSelectedTheme] = useState({ value: "" }); + const [selectedTheme, setSelectedTheme] = useState({ value: props.user.theme }); const [selectedTimeZone, setSelectedTimeZone] = useState({ value: props.user.timeZone }); - const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: "" }); + const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: props.user.weekStart }); const [hasErrors, setHasErrors] = useState(false); const [errorMessage, setErrorMessage] = useState(""); - const themeOptions = [ - { value: "light", label: "Light" }, - { value: "dark", label: "Dark" }, - ]; - useEffect(() => { setSelectedTheme( props.user.theme ? themeOptions.find((theme) => theme.value === props.user.theme) : null @@ -182,6 +182,7 @@ export default function Settings(props) { id="theme" isDisabled={!selectedTheme} defaultValue={selectedTheme || themeOptions[0]} + value={selectedTheme || themeOptions[0]} onChange={setSelectedTheme} className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" options={themeOptions} From c745416a6a94a3c1eb9204f2beadaa9ccdcdcd11 Mon Sep 17 00:00:00 2001 From: Pedro Duarte Date: Thu, 22 Jul 2021 14:16:54 +0200 Subject: [PATCH 02/70] Make collapsible time options accessible to screen readers --- package.json | 1 + pages/[user]/[type].tsx | 29 ++++++++------ yarn.lock | 87 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2875cf53..3194fd27 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@heroicons/react": "^1.0.1", "@jitsu/sdk-js": "^2.0.1", "@prisma/client": "^2.23.0", + "@radix-ui/react-collapsible": "^0.0.16", "@tailwindcss/forms": "^0.2.1", "async": "^3.2.0", "bcryptjs": "^2.4.3", diff --git a/pages/[user]/[type].tsx b/pages/[user]/[type].tsx index 04cdbd76..ec8677f4 100644 --- a/pages/[user]/[type].tsx +++ b/pages/[user]/[type].tsx @@ -4,6 +4,7 @@ import Head from "next/head"; import { ChevronDownIcon, ClockIcon, GlobeIcon } from "@heroicons/react/solid"; import { useRouter } from "next/router"; import dayjs, { Dayjs } from "dayjs"; +import * as Collapsible from "@radix-ui/react-collapsible"; import prisma, { whereAndSelect } from "@lib/prisma"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; @@ -139,19 +140,21 @@ export default function Type(props): Type { {props.eventType.length} minutes

- - {isTimeOptionsOpen && ( - - )} + + + + + {timeZone()} + + + + + + +

{props.eventType.description}

Date: Fri, 30 Jul 2021 15:19:40 +0300 Subject: [PATCH 03/70] fix chevron text color --- components/booking/DatePicker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/booking/DatePicker.tsx b/components/booking/DatePicker.tsx index c6a49fa0..92d94773 100644 --- a/components/booking/DatePicker.tsx +++ b/components/booking/DatePicker.tsx @@ -171,10 +171,10 @@ const DatePicker = ({ {dayjs().month(selectedMonth).format("MMMM YYYY")} -
+
From 9f8b1f372e4a619652f08e4524342c628473a113 Mon Sep 17 00:00:00 2001 From: Marc Seitz Date: Fri, 30 Jul 2021 15:48:51 +0300 Subject: [PATCH 04/70] add dark and light variants chevron color --- components/booking/DatePicker.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/booking/DatePicker.tsx b/components/booking/DatePicker.tsx index 92d94773..3dddd1e5 100644 --- a/components/booking/DatePicker.tsx +++ b/components/booking/DatePicker.tsx @@ -171,10 +171,13 @@ const DatePicker = ({ {dayjs().month(selectedMonth).format("MMMM YYYY")} -
+
From 04d7a280ef74a7f7fcdc80833a6f33428ebf311c Mon Sep 17 00:00:00 2001 From: Jan Vereecken Date: Sat, 31 Jul 2021 15:00:27 +0200 Subject: [PATCH 05/70] Use calendarView instead of events When calling Microsoft Graph use calendars/calendarView instead of calendars/events to allow occurences to be returned. --- lib/calendarClient.ts | 111 ++++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/lib/calendarClient.ts b/lib/calendarClient.ts index 9d3964b0..09668fa4 100644 --- a/lib/calendarClient.ts +++ b/lib/calendarClient.ts @@ -10,8 +10,14 @@ import CalEventParser from "./CalEventParser"; const { google } = require("googleapis"); const googleAuth = (credential) => { - const { client_secret, client_id, redirect_uris } = JSON.parse(process.env.GOOGLE_API_CREDENTIALS).web; - const myGoogleAuth = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]); + const { client_secret, client_id, redirect_uris } = JSON.parse( + process.env.GOOGLE_API_CREDENTIALS + ).web; + const myGoogleAuth = new google.auth.OAuth2( + client_id, + client_secret, + redirect_uris[0] + ); myGoogleAuth.setCredentials(credential.key); const isExpired = () => myGoogleAuth.isTokenExpiring(); @@ -43,7 +49,8 @@ const googleAuth = (credential) => { }); return { - getToken: () => (!isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken()), + getToken: () => + !isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken(), }; }; @@ -81,7 +88,9 @@ const o365Auth = (credential) => { .then(handleErrorsJson) .then((responseBody) => { credential.key.access_token = responseBody.access_token; - credential.key.expiry_date = Math.round(+new Date() / 1000 + responseBody.expires_in); + credential.key.expiry_date = Math.round( + +new Date() / 1000 + responseBody.expires_in + ); return prisma.credential .update({ where: { @@ -139,7 +148,11 @@ export interface CalendarApiAdapter { deleteEvent(uid: string); - getAvailability(dateFrom, dateTo, selectedCalendars: IntegrationCalendar[]): Promise; + getAvailability( + dateFrom, + dateTo, + selectedCalendars: IntegrationCalendar[] + ): Promise; listCalendars(): Promise; } @@ -206,7 +219,7 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => { return { getAvailability: (dateFrom, dateTo, selectedCalendars) => { - const filter = "?$filter=start/dateTime ge '" + dateFrom + "' and end/dateTime le '" + dateTo + "'"; + const filter = "?startdatetime=" + dateFrom + "&enddatetime=" + dateTo; return auth .getToken() .then((accessToken) => { @@ -229,7 +242,7 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => { headers: { Prefer: 'outlook.timezone="Etc/GMT"', }, - url: `/me/calendars/${calendarId}/events${filter}`, + url: `/me/calendars/${calendarId}/calendarView${filter}`, })); return fetch("https://graph.microsoft.com/v1.0/$batch", { @@ -309,7 +322,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { getAvailability: (dateFrom, dateTo, selectedCalendars) => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); const selectedCalendarIds = selectedCalendars .filter((e) => e.integration === integrationType) .map((e) => e.externalId); @@ -320,7 +336,9 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { } (selectedCalendarIds.length == 0 - ? calendar.calendarList.list().then((cals) => cals.data.items.map((cal) => cal.id)) + ? calendar.calendarList + .list() + .then((cals) => cals.data.items.map((cal) => cal.id)) : Promise.resolve(selectedCalendarIds) ) .then((calsIds) => { @@ -336,12 +354,19 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { if (err) { reject(err); } - resolve(Object.values(apires.data.calendars).flatMap((item) => item["busy"])); + resolve( + Object.values(apires.data.calendars).flatMap( + (item) => item["busy"] + ) + ); } ); }) .catch((err) => { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); reject(err); }); }) @@ -375,7 +400,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { payload["conferenceData"] = event.conferenceData; } - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.insert( { auth: myGoogleAuth, @@ -385,7 +413,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -418,7 +449,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { payload["location"] = event.location; } - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.update( { auth: myGoogleAuth, @@ -430,7 +464,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -441,7 +478,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { deleteEvent: (uid: string) => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.events.delete( { auth: myGoogleAuth, @@ -452,7 +492,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { }, function (err, event) { if (err) { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); return reject(err); } return resolve(event.data); @@ -463,7 +506,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { listCalendars: () => new Promise((resolve, reject) => auth.getToken().then((myGoogleAuth) => { - const calendar = google.calendar({ version: "v3", auth: myGoogleAuth }); + const calendar = google.calendar({ + version: "v3", + auth: myGoogleAuth, + }); calendar.calendarList .list() .then((cals) => { @@ -480,7 +526,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => { ); }) .catch((err) => { - console.error("There was an error contacting google calendar service: ", err); + console.error( + "There was an error contacting google calendar service: ", + err + ); reject(err); }); }) @@ -503,19 +552,29 @@ const calendars = (withCredentials): CalendarApiAdapter[] => }) .filter(Boolean); -const getBusyCalendarTimes = (withCredentials, dateFrom, dateTo, selectedCalendars) => +const getBusyCalendarTimes = ( + withCredentials, + dateFrom, + dateTo, + selectedCalendars +) => Promise.all( - calendars(withCredentials).map((c) => c.getAvailability(dateFrom, dateTo, selectedCalendars)) + calendars(withCredentials).map((c) => + c.getAvailability(dateFrom, dateTo, selectedCalendars) + ) ).then((results) => { return results.reduce((acc, availability) => acc.concat(availability), []); }); const listCalendars = (withCredentials) => - Promise.all(calendars(withCredentials).map((c) => c.listCalendars())).then((results) => - results.reduce((acc, calendars) => acc.concat(calendars), []) + Promise.all(calendars(withCredentials).map((c) => c.listCalendars())).then( + (results) => results.reduce((acc, calendars) => acc.concat(calendars), []) ); -const createEvent = async (credential: Credential, calEvent: CalendarEvent): Promise => { +const createEvent = async ( + credential: Credential, + calEvent: CalendarEvent +): Promise => { const parser: CalEventParser = new CalEventParser(calEvent); const uid: string = parser.getUid(); /* @@ -525,7 +584,9 @@ const createEvent = async (credential: Credential, calEvent: CalendarEvent): Pro */ const richEvent: CalendarEvent = parser.asRichEventPlain(); - const creationResult = credential ? await calendars([credential])[0].createEvent(richEvent) : null; + const creationResult = credential + ? await calendars([credential])[0].createEvent(richEvent) + : null; const maybeHangoutLink = creationResult?.hangoutLink; const maybeEntryPoints = creationResult?.entryPoints; From e5550b72ba1d39115bf531440e1ff63e55b7eee9 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Mon, 2 Aug 2021 22:57:58 +0200 Subject: [PATCH 06/70] added component --- components/Loader.tsx | 3 +++ pages/availability/index.tsx | 5 +++-- pages/availability/troubleshoot.tsx | 9 +++------ pages/event-types/index.tsx | 3 ++- pages/index.tsx | 4 ++++ pages/integrations/[integration].tsx | 3 ++- pages/integrations/index.tsx | 5 ++--- pages/settings/embed.tsx | 4 ++-- pages/settings/password.tsx | 5 +++-- 9 files changed, 24 insertions(+), 17 deletions(-) create mode 100644 components/Loader.tsx diff --git a/components/Loader.tsx b/components/Loader.tsx new file mode 100644 index 00000000..b66dfe18 --- /dev/null +++ b/components/Loader.tsx @@ -0,0 +1,3 @@ +export default function Loader(){ + return
+} \ No newline at end of file diff --git a/pages/availability/index.tsx b/pages/availability/index.tsx index 53bfd4b8..99ce3bb3 100644 --- a/pages/availability/index.tsx +++ b/pages/availability/index.tsx @@ -6,7 +6,8 @@ import Shell from "../../components/Shell"; import { useRouter } from "next/router"; import { useRef, useState } from "react"; import { getSession, useSession } from "next-auth/client"; -import { ClockIcon, PlusIcon } from "@heroicons/react/outline"; +import { ClockIcon } from "@heroicons/react/outline"; +import Loader from '@components/Loader'; export default function Availability(props) { const [session, loading] = useSession(); @@ -28,7 +29,7 @@ export default function Availability(props) { const bufferMinsRef = useRef(); if (loading) { - return
; + return ; } function toggleAddModal() { diff --git a/pages/availability/troubleshoot.tsx b/pages/availability/troubleshoot.tsx index 9ade27ae..a22390a1 100644 --- a/pages/availability/troubleshoot.tsx +++ b/pages/availability/troubleshoot.tsx @@ -6,6 +6,7 @@ import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import { GetServerSideProps } from "next"; import prisma from "@lib/prisma"; +import Loader from '@components/Loader'; dayjs.extend(utc); export default function Troubleshoot({ user }) { @@ -14,7 +15,7 @@ export default function Troubleshoot({ user }) { const [selectedDate, setSelectedDate] = useState(dayjs()); if (loading) { - return
; + return ; } function convertMinsToHrsMins(mins) { @@ -80,11 +81,7 @@ export default function Troubleshoot({ user }) {
))} - {availability.length === 0 && ( -
- -
- )} + {availability.length === 0 && }
Your day ends at {convertMinsToHrsMins(user.endTime)} diff --git a/pages/event-types/index.tsx b/pages/event-types/index.tsx index d3ded115..00cf1d89 100644 --- a/pages/event-types/index.tsx +++ b/pages/event-types/index.tsx @@ -20,6 +20,7 @@ import { PlusIcon, UserIcon, } from "@heroicons/react/solid"; +import Loader from '@components/Loader'; export default function Availability({ user, types }) { const [session, loading] = useSession(); @@ -65,7 +66,7 @@ export default function Availability({ user, types }) { } if (loading) { - return
; + return ; } return ( diff --git a/pages/index.tsx b/pages/index.tsx index 894d14ea..9901e8a0 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,3 +1,4 @@ +import Loader from "@components/Loader"; import { useRouter } from "next/router"; function RedirectPage() { @@ -6,6 +7,9 @@ function RedirectPage() { router.push("/event-types"); return; } + return ( + + ); } RedirectPage.getInitialProps = (ctx) => { diff --git a/pages/integrations/[integration].tsx b/pages/integrations/[integration].tsx index 8cdaa93a..1e997470 100644 --- a/pages/integrations/[integration].tsx +++ b/pages/integrations/[integration].tsx @@ -5,6 +5,7 @@ import Shell from "../../components/Shell"; import { useState } from "react"; import { useRouter } from "next/router"; import { useSession, getSession } from "next-auth/client"; +import Loader from '@components/Loader'; export default function integration(props) { const router = useRouter(); @@ -12,7 +13,7 @@ export default function integration(props) { const [showAPIKey, setShowAPIKey] = useState(false); if (loading) { - return
; + return ; } function toggleShowAPIKey() { diff --git a/pages/integrations/index.tsx b/pages/integrations/index.tsx index fb3d84e2..36843394 100644 --- a/pages/integrations/index.tsx +++ b/pages/integrations/index.tsx @@ -13,6 +13,7 @@ import { } from "@heroicons/react/solid"; import { InformationCircleIcon } from "@heroicons/react/outline"; import { Switch } from "@headlessui/react"; +import Loader from '@components/Loader'; export default function Home({ integrations }) { const [session, loading] = useSession(); @@ -88,9 +89,7 @@ export default function Home({ integrations }) { if (loading) { return ( -
- -
+ ); } diff --git a/pages/settings/embed.tsx b/pages/settings/embed.tsx index 45409ea2..46e07646 100644 --- a/pages/settings/embed.tsx +++ b/pages/settings/embed.tsx @@ -6,13 +6,13 @@ import prisma from "../../lib/prisma"; import Shell from "../../components/Shell"; import SettingsShell from "../../components/Settings"; import { useSession, getSession } from "next-auth/client"; +import Loader from '@components/Loader'; export default function Embed(props) { const [session, loading] = useSession(); - const router = useRouter(); if (loading) { - return
; + return ; } return ( diff --git a/pages/settings/password.tsx b/pages/settings/password.tsx index 4e93a373..347d1c3a 100644 --- a/pages/settings/password.tsx +++ b/pages/settings/password.tsx @@ -5,7 +5,8 @@ import prisma from "../../lib/prisma"; import Modal from "../../components/Modal"; import Shell from "../../components/Shell"; import SettingsShell from "../../components/Settings"; -import { signIn, useSession, getSession } from "next-auth/client"; +import { useSession, getSession } from "next-auth/client"; +import Loader from '@components/Loader'; export default function Settings(props) { const [session, loading] = useSession(); @@ -14,7 +15,7 @@ export default function Settings(props) { const newPasswordRef = useRef(); if (loading) { - return
; + return ; } const closeSuccessModal = () => { From 3efc4e0fb7a3315b8be7c576a5d448b92298cce6 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Mon, 2 Aug 2021 23:17:12 +0200 Subject: [PATCH 07/70] changed logo link --- components/Shell.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Shell.tsx b/components/Shell.tsx index c5c72516..bce52a41 100644 --- a/components/Shell.tsx +++ b/components/Shell.tsx @@ -77,7 +77,7 @@ export default function Shell(props) { {/* Sidebar component, swap this element with another sidebar if you like */}
- + @@ -114,7 +114,7 @@ export default function Shell(props) {
{/* show top navigation for md and smaller (tablet and phones) */}