import { InformationCircleIcon } from "@heroicons/react/outline";
import { CheckCircleIcon, ChevronRightIcon, PlusIcon, XCircleIcon } from "@heroicons/react/solid";
import { GetServerSidePropsContext } from "next";
import { useSession } from "next-auth/client";
import Link from "next/link";
import { useCallback, useEffect, useRef, useState } from "react";
import { getSession } from "@lib/auth";
import { ONBOARDING_NEXT_REDIRECT, shouldShowOnboarding } from "@lib/getting-started";
import AddAppleIntegration, {
ADD_APPLE_INTEGRATION_FORM_TITLE,
} from "@lib/integrations/Apple/components/AddAppleIntegration";
import AddCalDavIntegration, {
ADD_CALDAV_INTEGRATION_FORM_TITLE,
} from "@lib/integrations/CalDav/components/AddCalDavIntegration";
import getIntegrations from "@lib/integrations/getIntegrations";
import prisma from "@lib/prisma";
import { inferSSRProps } from "@lib/types/inferSSRProps";
import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTrigger } from "@components/Dialog";
import Loader from "@components/Loader";
import Shell from "@components/Shell";
import Button from "@components/ui/Button";
import Switch from "@components/ui/Switch";
export default function Home({ integrations }: inferSSRProps) {
const [, loading] = useSession();
const [selectableCalendars, setSelectableCalendars] = useState([]);
const addCalDavIntegrationRef = useRef(null);
const [isAddCalDavIntegrationDialogOpen, setIsAddCalDavIntegrationDialogOpen] = useState(false);
const [addCalDavError, setAddCalDavError] = useState<{ message: string } | null>(null);
const addAppleIntegrationRef = useRef(null);
const [isAddAppleIntegrationDialogOpen, setIsAddAppleIntegrationDialogOpen] = useState(false);
const [addAppleError, setAddAppleError] = useState<{ message: string } | null>(null);
useEffect(loadCalendars, [integrations]);
function loadCalendars() {
fetch("api/availability/calendar")
.then((response) => response.json())
.then((data) => {
setSelectableCalendars(data);
});
}
function integrationHandler(type) {
if (type === "caldav_calendar") {
setAddCalDavError(null);
setIsAddCalDavIntegrationDialogOpen(true);
return;
}
if (type === "apple_calendar") {
setAddAppleError(null);
setIsAddAppleIntegrationDialogOpen(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,
});
return await fetch("/api/integrations/caldav/add", {
method: "POST",
body: requestBody,
headers: {
"Content-Type": "application/json",
},
});
};
const handleAddAppleIntegration = async ({ username, password }) => {
const requestBody = JSON.stringify({
username,
password,
});
return await fetch("/api/integrations/apple/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/caldav.svg";
case "apple_calendar":
return "integrations/apple-calendar.svg";
default:
return "";
}
}
function onCloseSelectCalendar() {
setSelectableCalendars([...selectableCalendars]);
}
const ConnectNewAppDialog = () => (
);
const SelectCalendarDialog = () => (
);
const handleAddCalDavIntegrationSaveButtonPress = async () => {
const form = addCalDavIntegrationRef.current.elements;
const url = form.url.value;
const password = form.password.value;
const username = form.username.value;
try {
setAddCalDavError(null);
const addCalDavIntegrationResponse = await handleAddCalDavIntegration({ username, password, url });
if (addCalDavIntegrationResponse.ok) {
setIsAddCalDavIntegrationDialogOpen(false);
} else {
const j = await addCalDavIntegrationResponse.json();
setAddCalDavError({ message: j.message });
}
} catch (reason) {
console.error(reason);
}
};
const handleAddAppleIntegrationSaveButtonPress = async () => {
const form = addAppleIntegrationRef.current.elements;
const password = form.password.value;
const username = form.username.value;
try {
setAddAppleError(null);
const addAppleIntegrationResponse = await handleAddAppleIntegration({ username, password });
if (addAppleIntegrationResponse.ok) {
setIsAddAppleIntegrationDialogOpen(false);
} else {
const j = await addAppleIntegrationResponse.json();
setAddAppleError({ message: j.message });
}
} catch (reason) {
console.error(reason);
}
};
const ConnectCalDavServerDialog = useCallback(() => {
return (
);
}, [isAddCalDavIntegrationDialogOpen, addCalDavError]);
const ConnectAppleServerDialog = useCallback(() => {
return (
}
/>
{addAppleError && (
Error:
{addAppleError.message}
)}
{
setIsAddAppleIntegrationDialogOpen(false);
}}
asChild>
);
}, [isAddAppleIntegrationDialogOpen, addAppleError]);
if (loading) {
return ;
}
return (
}>
{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.
);
}
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getSession(context);
if (!session?.user?.email) {
return { redirect: { permanent: false, destination: "/auth/login" } };
}
const user = await prisma.user.findFirst({
where: {
email: session.user.email,
},
select: {
id: true,
credentials: {
select: {
id: true,
type: true,
key: true,
},
},
completedOnboarding: true,
createdDate: true,
},
});
if (!user)
return {
redirect: { permanent: false, destination: "/auth/login" },
};
if (
shouldShowOnboarding({ completedOnboarding: user.completedOnboarding, createdDate: user.createdDate })
) {
return ONBOARDING_NEXT_REDIRECT;
}
const integrations = getIntegrations(user.credentials);
return {
props: { session, integrations },
};
}