From a047177e72d6912113f30bc587cf94fffb4dbf05 Mon Sep 17 00:00:00 2001 From: Femi Odugbesan Date: Wed, 22 Sep 2021 02:25:33 -0500 Subject: [PATCH] Fix/duplicate events on onboarding (#716) --- lib/queries/event-types/get-event-types.ts | 10 ++++ package.json | 1 + pages/api/event-type/index.ts | 44 +++++++++++++++ pages/api/user/[id].ts | 2 +- pages/getting-started.tsx | 62 ++++++++++++++++------ yarn.lock | 12 +++++ 6 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 lib/queries/event-types/get-event-types.ts create mode 100644 pages/api/event-type/index.ts diff --git a/lib/queries/event-types/get-event-types.ts b/lib/queries/event-types/get-event-types.ts new file mode 100644 index 0000000000..f86d2fb5cd --- /dev/null +++ b/lib/queries/event-types/get-event-types.ts @@ -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("/api/event-type"); + return response.data; +}; + +export default getEventTypes; diff --git a/package.json b/package.json index 825b600494..1234af717a 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pages/api/event-type/index.ts b/pages/api/event-type/index.ts new file mode 100644 index 0000000000..5ff855cce1 --- /dev/null +++ b/pages/api/event-type/index.ts @@ -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 }); + } +} diff --git a/pages/api/user/[id].ts b/pages/api/user/[id].ts index f764c72cf6..1e9a656eb0 100644 --- a/pages/api/user/[id].ts +++ b/pages/api/user/[id].ts @@ -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, diff --git a/pages/getting-started.tsx b/pages/getting-started.tsx index 8bd48801ea..a30f8c1132 100644 --- a/pages/getting-started.tsx +++ b/pages/getting-started.tsx @@ -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 ( -
  • integrationHandler(integration.type)} key={integration.type} className="flex py-4"> +
  • handleAddIntegration(integration.type)} key={integration.type} className="flex py-4">
    {integration.title}
    @@ -148,7 +152,7 @@ export default function Onboarding(props: OnboardingProps) {
    -
    @@ -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) { - Promise.all( - DEFAULT_EVENT_TYPES.map(async (event) => { - return await createEventType(event); - }) - ); + 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) { { 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) { + {isSubmitting && ( +
    + +
    + )}
    -
    +
    @@ -572,7 +600,11 @@ export default function Onboarding(props: OnboardingProps) { {!steps[currentStep].hideConfirm && (
    -
    @@ -580,11 +612,11 @@ export default function Onboarding(props: OnboardingProps) {
    - {currentStep !== 0 && ( - )} diff --git a/yarn.lock b/yarn.lock index 66b7658a5f..e58e023dff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"