From 850497ea80355758aba0dd98b12db3fb642ee9c7 Mon Sep 17 00:00:00 2001 From: Alex Johansson Date: Thu, 9 Dec 2021 16:51:37 +0100 Subject: [PATCH] add select primary calendar (#1133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add primary * fix * refactor eventmanager to take `CalendarDestination` * `DestinationCalendar` * fix * wip * wip * Minor fixes (#1156) * Followup for #1242 * Updates schema * Renames fields to destinationCalendar * Migration fixes * Updates user destination calendar * Abstracts convertDate to BaseCalendarApiAdapter * Type fixes * Uses abstracted convertDate method * Abstracts getDuration and getAttendees * Fixes circular dependecy issue * Adds notEmpty util * Reverts empty location string * Fixes property name * Removes deprecated code * WIP * AppleCal is basically CalDav * Fixes missing destinationCalendar * Type fixes * Select primary calendar on Office and gCal * Adds pretty basic instructions for destination calendar * Cleanup * Type fix * Test fixes * Updates test snapshot * Local test fixes * Type fixes Co-authored-by: Peer Richelsen Co-authored-by: Omar López Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../integrations/CalendarListContainer.tsx | 184 ++++++--- ee/lib/stripe/server.ts | 11 +- .../api/integrations/stripepayment/webhook.ts | 3 +- jest.playwright.config.js | 1 + lib/BaseCalendarApiAdapter.ts | 349 ++++++++++++++++++ lib/CalEventParser.ts | 2 +- lib/calendarClient.ts | 122 ++---- lib/events/EventManager.ts | 34 +- .../Apple/AppleCalendarAdapter.ts | 344 +---------------- .../CalDav/CalDavCalendarAdapter.ts | 345 +---------------- .../GoogleCalendarApiAdapter.ts | 26 +- .../Office365CalendarApiAdapter.ts | 11 +- lib/notEmpty.ts | 3 + lib/videoClient.ts | 2 +- pages/[user].tsx | 6 +- pages/api/availability/calendar.ts | 33 +- pages/api/book/confirm.ts | 7 +- pages/api/book/event.ts | 12 +- pages/team/[slug]/[type].tsx | 2 + playwright/integrations.test.ts | 4 +- .../migration.sql | 29 ++ prisma/schema.prisma | 92 +++-- public/static/locales/en/common.json | 1 + scripts/seed.ts | 1 + server/createContext.ts | 1 + server/routers/viewer.tsx | 37 +- 26 files changed, 745 insertions(+), 917 deletions(-) create mode 100644 lib/BaseCalendarApiAdapter.ts create mode 100644 lib/notEmpty.ts create mode 100644 prisma/migrations/20211207010154_add_destination_calendar/migration.sql diff --git a/components/integrations/CalendarListContainer.tsx b/components/integrations/CalendarListContainer.tsx index cbab1c94b5..f07b769e09 100644 --- a/components/integrations/CalendarListContainer.tsx +++ b/components/integrations/CalendarListContainer.tsx @@ -1,5 +1,6 @@ -import React, { Fragment } from "react"; +import React, { Fragment, useState } from "react"; import { useMutation } from "react-query"; +import Select from "react-select"; import { QueryCell } from "@lib/QueryCell"; import { useLocale } from "@lib/hooks/useLocale"; @@ -98,59 +99,124 @@ function ConnectedCalendarsList(props: Props) { null} - success={({ data }) => ( - - {data.map((item) => ( - - {item.calendars ? ( - ( - - )} - onOpenChange={props.onChanged} - /> - }> -
    - {item.calendars.map((cal) => ( - { + if (!data.connectedCalendars.length) { + return null; + } + return ( + + {data.connectedCalendars.map((item) => ( + + {item.calendars ? ( + ( + + )} + onOpenChange={props.onChanged} /> - ))} -
-
- ) : ( - ( - - )} - onOpenChange={() => props.onChanged()} - /> - } - /> - )} -
- ))} -
- )} + }> +
    + {item.calendars.map((cal) => ( + + ))} +
+ + ) : ( + ( + + )} + onOpenChange={() => props.onChanged()} + /> + } + /> + )} + + ))} + + ); + }} + /> + ); +} + +function PrimaryCalendarSelector() { + const query = trpc.useQuery(["viewer.connectedCalendars"], { + suspense: true, + }); + const [selectedOption, setSelectedOption] = useState(() => { + const selected = query.data?.connectedCalendars + .map((connected) => connected.calendars ?? []) + .flat() + .find((cal) => cal.externalId === query.data.destinationCalendar?.externalId); + + if (!selected) { + return null; + } + + return { + value: `${selected.integration}:${selected.externalId}`, + label: selected.name, + }; + }); + + const mutation = trpc.useMutation("viewer.setUserDestinationCalendar"); + + if (!query.data?.connectedCalendars.length) { + return null; + } + const options = + query.data.connectedCalendars.map((selectedCalendar) => ({ + key: selectedCalendar.credentialId, + label: `${selectedCalendar.integration.title} (${selectedCalendar.primary?.name})`, + options: (selectedCalendar.calendars ?? []).map((cal) => ({ + label: cal.name || "", + value: `${cal.integration}:${cal.externalId}`, + })), + })) ?? []; + return ( +