import Head from "next/head"; import Link from "next/link"; import prisma from "../../lib/prisma"; import Shell from "../../components/Shell"; import { useEffect, useState, useRef } from "react"; import { getSession, useSession } from "next-auth/client"; import { CheckCircleIcon, ChevronRightIcon, PlusIcon, XCircleIcon } from "@heroicons/react/solid"; import { InformationCircleIcon } from "@heroicons/react/outline"; import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTrigger } from "@components/Dialog"; import Switch from "@components/ui/Switch"; import Loader from "@components/Loader"; import AddCalDavIntegration from "@lib/integrations/CalDav/components/AddCalDavIntegration"; type Integration = { installed: boolean; credential: unknown; type: string; title: string; imageSrc: string; description: string; }; type Props = { integrations: Integration[]; }; export default function Home({ integrations }: Props) { const [, loading] = useSession(); const [selectableCalendars, setSelectableCalendars] = useState([]); const addCalDavIntegrationRef = useRef(null); const [isAddCalDavIntegrationDialogOpen, setIsAddCalDavIntegrationDialogOpen] = useState(false); useEffect(loadCalendars, [integrations]); function loadCalendars() { fetch("api/availability/calendar") .then((response) => response.json()) .then((data) => { setSelectableCalendars(data); }); } function integrationHandler(type) { if (type === "caldav_calendar") { setIsAddCalDavIntegrationDialogOpen(true); return; } fetch("/api/integrations/" + type.replace("_", "") + "/add") .then((response) => response.json()) .then((data) => (window.location.href = data.url)); } const handleAddCalDavIntegration = async ({ url, username, password }) => { const requestBody = JSON.stringify({ url, username, password, }); await fetch("/api/integrations/caldav/add", { method: "POST", body: requestBody, headers: { "Content-Type": "application/json", }, }); }; function calendarSelectionHandler(calendar) { return (selected) => { const i = selectableCalendars.findIndex((c) => c.externalId === calendar.externalId); selectableCalendars[i].selected = selected; if (selected) { fetch("api/availability/calendar", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(selectableCalendars[i]), }).then((response) => response.json()); } else { fetch("api/availability/calendar", { method: "DELETE", headers: { "Content-Type": "application/json", }, body: JSON.stringify(selectableCalendars[i]), }).then((response) => response.json()); } }; } function getCalendarIntegrationImage(integrationType: string) { switch (integrationType) { case "google_calendar": return "integrations/google-calendar.svg"; case "office365_calendar": return "integrations/outlook.svg"; case "caldav_calendar": return "integrations/generic-calendar.png"; default: return ""; } } function onCloseSelectCalendar() { setSelectableCalendars([...selectableCalendars]); } const ConnectNewAppDialog = () => ( Connect a new App
    {integrations .filter((integration) => integration.installed) .map((integration) => { return (
  • {integration.title}

    {integration.title}

    {integration.description}

    {integration.type === "caldav_calendar" ? ( ) : ( // )}
  • ); })}
Cancel
); const SelectCalendarDialog = () => ( !open && onCloseSelectCalendar()}> Select calendars
    {selectableCalendars.map((calendar) => (
  • {calendar.integration}

    {calendar.name}

  • ))}
Cancel
); function handleAddCalDavIntegrationSaveButtonPress() { const form = addCalDavIntegrationRef.current.elements; const url = form.url.value; const password = form.password.value; const username = form.username.value; try { handleAddCalDavIntegration({ username, password, url }); } catch (reason) { console.error(reason); } } const onSubmit = () => { const form = addCalDavIntegrationRef.current; if (form) { if (typeof form.requestSubmit === "function") { form.requestSubmit(); } else { form.dispatchEvent(new Event("submit", { cancelable: true })); } setIsAddCalDavIntegrationDialogOpen(false); } }; const ConnectCalDavServerDialog = ({ isOpen }) => { return (

Your credentials will be stored and encrypted.

Cancel
); }; if (loading) { return ; } return (
App Store | Calendso }>
{integrations.filter((ig) => ig.credential).length !== 0 ? ( ) : (

You don't have any apps connected.

You currently do not have any apps connected. Connect your first app to get started.

)}

Select calendars

Select which calendars are checked for availability to prevent double bookings.

Launch your own App

If you want to add your own App here, get in touch with us.

); } const validJson = (jsonString: string) => { try { const o = JSON.parse(jsonString); if (o && typeof o === "object") { return o; } } catch (e) { console.error(e); } return false; }; export async function getServerSideProps(context) { const session = await getSession(context); if (!session) { return { redirect: { permanent: false, destination: "/auth/login" } }; } const user = await prisma.user.findFirst({ where: { email: session.user.email, }, select: { id: true, }, }); const credentials = await prisma.credential.findMany({ where: { userId: user.id, }, select: { id: true, type: true, key: true, }, }); const integrations = [ { installed: !!(process.env.GOOGLE_API_CREDENTIALS && validJson(process.env.GOOGLE_API_CREDENTIALS)), credential: credentials.find((integration) => integration.type === "google_calendar") || null, type: "google_calendar", title: "Google Calendar", imageSrc: "integrations/google-calendar.svg", description: "For personal and business calendars", }, { installed: !!(process.env.MS_GRAPH_CLIENT_ID && process.env.MS_GRAPH_CLIENT_SECRET), type: "office365_calendar", credential: credentials.find((integration) => integration.type === "office365_calendar") || null, title: "Office 365 / Outlook.com Calendar", imageSrc: "integrations/outlook.svg", description: "For personal and business calendars", }, { installed: !!(process.env.ZOOM_CLIENT_ID && process.env.ZOOM_CLIENT_SECRET), type: "zoom_video", credential: credentials.find((integration) => integration.type === "zoom_video") || null, title: "Zoom", imageSrc: "integrations/zoom.svg", description: "Video Conferencing", }, { installed: true, type: "caldav_calendar", credential: credentials.find((integration) => integration.type === "caldav_calendar") || null, title: "CalDav Server", imageSrc: "integrations/generic-calendar.png", description: "For personal and business calendars", }, ]; return { props: { integrations }, }; }