Fix/duplicate events on onboarding (#716)

pull/721/head
Femi Odugbesan 2021-09-22 02:25:33 -05:00 committed by GitHub
parent d4f29464f2
commit a047177e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 16 deletions

View File

@ -0,0 +1,10 @@
import * as fetch from "@lib/core/http/fetch-wrapper";
import { EventType } from "@prisma/client";
type GetEventsResponse = { message: string; data: EventType[] };
const getEventTypes = async () => {
const response = await fetch.get<GetEventsResponse>("/api/event-type");
return response.data;
};
export default getEventTypes;

View File

@ -72,6 +72,7 @@
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/jest": "^27.0.1",
"@types/lodash.debounce": "^4.0.6",
"@types/node": "^16.6.1",
"@types/nodemailer": "^6.4.4",
"@types/qrcode": "^1.4.1",

View File

@ -0,0 +1,44 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getSession } from "@lib/auth";
import prisma from "@lib/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const session = await getSession({ req: req });
if (!session) {
res.status(401).json({ message: "Not authenticated" });
return;
}
if (!session.user?.id) {
console.error("Session is missing a user id");
return res.status(500).json({ message: "Something went wrong" });
}
if (req.method === "GET") {
const user = await prisma.user.findUnique({
where: {
id: session.user.id,
},
select: {
id: true,
eventTypes: {
where: {
team: null,
},
select: {
id: true,
title: true,
description: true,
length: true,
schedulingType: true,
slug: true,
hidden: true,
},
},
},
});
return res.status(200).json({ message: "Events.", data: user.eventTypes });
}
}

View File

@ -50,7 +50,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
"theme",
"completedOnboarding",
]),
bio: req.body.description,
bio: req.body.description ?? req.body.data?.bio,
},
select: {
id: true,

View File

@ -30,6 +30,9 @@ import classnames from "classnames";
import { ArrowRightIcon } from "@heroicons/react/outline";
import { getSession } from "@lib/auth";
import Button from "@components/ui/Button";
import debounce from "lodash.debounce";
import Loader from "@components/Loader";
import getEventTypes from "../lib/queries/event-types/get-event-types";
dayjs.extend(utc);
dayjs.extend(timezone);
@ -63,6 +66,7 @@ type OnboardingProps = {
export default function Onboarding(props: OnboardingProps) {
const router = useRouter();
const [isSubmitting, setSubmitting] = React.useState(false);
const [enteredName, setEnteredName] = React.useState();
const Sess = useSession();
const [ready, setReady] = useState(false);
@ -116,7 +120,7 @@ export default function Onboarding(props: OnboardingProps) {
return responseData.data;
};
const integrationHandler = (type: string) => {
const handleAddIntegration = (type: string) => {
if (type === "caldav_calendar") {
setAddCalDavError(null);
setIsAddCalDavIntegrationDialogOpen(true);
@ -137,7 +141,7 @@ export default function Onboarding(props: OnboardingProps) {
}
return (
<li onClick={() => integrationHandler(integration.type)} key={integration.type} className="flex py-4">
<li onClick={() => handleAddIntegration(integration.type)} key={integration.type} className="flex py-4">
<div className="w-1/12 mr-4 pt-2">
<img className="h-8 w-8 mr-2" src={integration.imageSrc} alt={integration.title} />
</div>
@ -148,7 +152,7 @@ export default function Onboarding(props: OnboardingProps) {
</Text>
</div>
<div className="w-2/12 text-right pt-2">
<Button color="secondary" onClick={() => integrationHandler(integration.type)}>
<Button color="secondary" onClick={() => handleAddIntegration(integration.type)}>
Connect
</Button>
</div>
@ -280,6 +284,7 @@ export default function Onboarding(props: OnboardingProps) {
const handleConfirmStep = async () => {
try {
setSubmitting(true);
if (
steps[currentStep] &&
steps[currentStep]?.onComplete &&
@ -288,12 +293,16 @@ export default function Onboarding(props: OnboardingProps) {
await steps[currentStep].onComplete();
}
incrementStep();
setSubmitting(false);
} catch (error) {
console.log("handleConfirmStep", error);
setSubmitting(false);
setError(error);
}
};
const debouncedHandleConfirmStep = debounce(handleConfirmStep, 850);
const handleSkipStep = () => {
incrementStep();
};
@ -331,17 +340,22 @@ export default function Onboarding(props: OnboardingProps) {
* then the default availability is applied.
*/
const completeOnboarding = async () => {
setSubmitting(true);
if (!props.eventTypes || props.eventTypes.length === 0) {
const eventTypes = await getEventTypes();
if (eventTypes.length === 0) {
Promise.all(
DEFAULT_EVENT_TYPES.map(async (event) => {
return await createEventType(event);
})
);
}
}
await updateUser({
completedOnboarding: true,
});
setSubmitting(false);
router.push("/event-types");
};
@ -365,7 +379,7 @@ export default function Onboarding(props: OnboardingProps) {
id="name"
autoComplete="given-name"
placeholder="Your name"
defaultValue={props.user.name}
defaultValue={props.user.name ?? enteredName}
required
className="mt-1 block w-full border border-gray-300 rounded-sm shadow-sm py-2 px-3 focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
/>
@ -397,13 +411,16 @@ export default function Onboarding(props: OnboardingProps) {
cancelText: "Set up later",
onComplete: async () => {
try {
setSubmitting(true);
await updateUser({
name: nameRef.current.value,
timeZone: selectedTimeZone.value,
});
setEnteredName(nameRef.current.value);
setSubmitting(true);
} catch (error) {
setError(error);
setSubmitting(false);
}
},
},
@ -435,10 +452,12 @@ export default function Onboarding(props: OnboardingProps) {
<SchedulerForm
onSubmit={async (data) => {
try {
setSubmitting(true);
await createSchedule({
freeBusyTimes: data,
});
handleConfirmStep();
debouncedHandleConfirmStep();
setSubmitting(false);
} catch (error) {
setError(error);
}
@ -505,11 +524,15 @@ export default function Onboarding(props: OnboardingProps) {
cancelText: "Set up later",
onComplete: async () => {
try {
setSubmitting(true);
console.log("updating");
await updateUser({
bio: bioRef.current.value,
description: bioRef.current.value,
});
setSubmitting(false);
} catch (error) {
setError(error);
setSubmitting(false);
}
},
},
@ -532,8 +555,13 @@ export default function Onboarding(props: OnboardingProps) {
<link rel="icon" href="/favicon.ico" />
</Head>
{isSubmitting && (
<div className="fixed w-full h-full bg-white bg-opacity-25 flex flex-col justify-center items-center content-center z-10">
<Loader />
</div>
)}
<div className="mx-auto py-24 px-4">
<article>
<article className="relative">
<section className="sm:mx-auto sm:w-full sm:max-w-md space-y-4">
<header className="">
<Text className="text-white" variant="largetitle">
@ -572,7 +600,11 @@ export default function Onboarding(props: OnboardingProps) {
{!steps[currentStep].hideConfirm && (
<footer className="py-6 sm:mx-auto sm:w-full sm:max-w-md flex flex-col space-y-6 mt-8">
<Button className="justify-center" onClick={handleConfirmStep} EndIcon={ArrowRightIcon}>
<Button
className="justify-center"
disabled={isSubmitting}
onClick={debouncedHandleConfirmStep}
EndIcon={ArrowRightIcon}>
{steps[currentStep].confirmText}
</Button>
</footer>
@ -580,11 +612,11 @@ export default function Onboarding(props: OnboardingProps) {
</section>
<section className="py-6 mt-8 mx-auto max-w-xl">
<div className="flex justify-between flex-row-reverse">
<button onClick={handleSkipStep}>
<button disabled={isSubmitting} onClick={handleSkipStep}>
<Text variant="caption">Skip Step</Text>
</button>
{currentStep !== 0 && (
<button onClick={decrementStep}>
<button disabled={isSubmitting} onClick={decrementStep}>
<Text variant="caption">Prev Step</Text>
</button>
)}

View File

@ -1371,6 +1371,18 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/lodash.debounce@^4.0.6":
version "4.0.6"
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60"
integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==
dependencies:
"@types/lodash" "*"
"@types/lodash@*":
version "4.14.173"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.173.tgz#9d3b674c67a26cf673756f6aca7b429f237f91ed"
integrity sha512-vv0CAYoaEjCw/mLy96GBTnRoZrSxkGE0BKzKimdR8P3OzrNYNvBgtW7p055A+E8C31vXNUhWKoFCbhq7gbyhFg==
"@types/lodash@^4.14.165":
version "4.14.172"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.172.tgz#aad774c28e7bfd7a67de25408e03ee5a8c3d028a"