From 84d75cf69318584ec075752405a28f6b3e54740a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Fri, 7 Jan 2022 13:23:37 -0700 Subject: [PATCH] Upgrades next-auth to v4 (#1185) * Upgrades next-auth to v4 * Fixes next-auth session types * Type fixes * Fixes login issue * Team page fixes * Type fixes * Fixes secret * Adds test for forgotten password * Skips if pw secret is undefined * Prevents error if PW secret is undefined * Adds PLAYWRIGHT_SECRET explainer * Adds pending auth TODOs * Adds missing secret * Fixed imports * Fixed imports * Type fixes * Test fixes Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .env.example | 2 + .github/workflows/build.yml | 1 + .github/workflows/e2e.yml | 2 + .gitignore | 3 +- components/Shell.tsx | 5 +- lib/app-providers.tsx | 6 +- lib/auth.ts | 15 +- package.json | 2 +- pages/api/auth/[...nextauth].tsx | 25 +- pages/api/auth/forgot-password.ts | 11 +- pages/api/auth/reset-password.ts | 15 +- pages/api/eventType.ts | 3 +- pages/api/me.ts | 8 +- pages/api/user/[id].ts | 9 +- pages/auth/forgot-password/[id].tsx | 77 ++--- pages/auth/forgot-password/index.tsx | 4 +- pages/auth/login.tsx | 4 +- pages/auth/signup.tsx | 2 +- pages/call/[uid].tsx | 34 +- pages/call/meeting-ended/[uid].tsx | 10 +- pages/call/meeting-not-started/[uid].tsx | 10 +- pages/cancel/success.tsx | 27 +- pages/getting-started.tsx | 7 +- pages/settings/teams.tsx | 5 +- playwright.config.ts | 1 + playwright/auth/auth-index.test.ts | 5 + playwright/auth/forgot-password.test.ts | 49 +++ server/createContext.ts | 8 +- tsconfig.json | 1 + types/next-auth.d.ts | 16 + yarn.lock | 397 ++++------------------- 31 files changed, 298 insertions(+), 466 deletions(-) create mode 100644 playwright/auth/auth-index.test.ts create mode 100644 playwright/auth/forgot-password.test.ts create mode 100644 types/next-auth.d.ts diff --git a/.env.example b/.env.example index 64c3ac32cb..b3b791579d 100644 --- a/.env.example +++ b/.env.example @@ -16,6 +16,8 @@ BASE_URL='http://localhost:3000' NEXT_PUBLIC_APP_URL='http://localhost:3000' JWT_SECRET='secret' +# This is used so we can bypass emails in auth flows for E2E testing +PLAYWRIGHT_SECRET= # @see: https://github.com/calendso/calendso/issues/263 # Required for Vercel hosting - set NEXTAUTH_URL to equal your BASE_URL diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cdec2b8ea6..b757c07d79 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,7 @@ jobs: NODE_ENV: test BASE_URL: http://localhost:3000 JWT_SECRET: secret + PLAYWRIGHT_SECRET: ${{ secrets.CI_PLAYWRIGHT_SECRET }} services: postgres: image: postgres:12.1 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1c9e915164..cc87ceb149 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -9,6 +9,7 @@ jobs: DATABASE_URL: postgresql://postgres:@localhost:5432/calendso BASE_URL: http://localhost:3000 JWT_SECRET: secret + PLAYWRIGHT_SECRET: ${{ secrets.CI_PLAYWRIGHT_SECRET }} GOOGLE_API_CREDENTIALS: "{}" # GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }} # CRON_API_KEY: xxx @@ -91,3 +92,4 @@ jobs: path: | playwright/screenshots playwright/videos + playwright/results diff --git a/.gitignore b/.gitignore index fbbd07c1cb..47bcaa2963 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ playwright/videos playwright/screenshots playwright/artifacts +playwright/results # next.js /.next/ @@ -57,4 +58,4 @@ yarn-error.log* .history/ # Typescript -tsconfig.tsbuildinfo \ No newline at end of file +tsconfig.tsbuildinfo diff --git a/components/Shell.tsx b/components/Shell.tsx index 707d688373..caccb5409b 100644 --- a/components/Shell.tsx +++ b/components/Shell.tsx @@ -9,7 +9,7 @@ import { LogoutIcon, PuzzleIcon, } from "@heroicons/react/solid"; -import { signOut, useSession } from "next-auth/client"; +import { signOut, useSession } from "next-auth/react"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { ReactNode, useEffect, useState } from "react"; @@ -51,7 +51,8 @@ export function useMeQuery() { } function useRedirectToLoginIfUnauthenticated() { - const [session, loading] = useSession(); + const { data: session, status } = useSession(); + const loading = status === "loading"; const router = useRouter(); useEffect(() => { diff --git a/lib/app-providers.tsx b/lib/app-providers.tsx index c2952cee46..47280b98b9 100644 --- a/lib/app-providers.tsx +++ b/lib/app-providers.tsx @@ -1,5 +1,5 @@ import { IdProvider } from "@radix-ui/react-id"; -import { Provider } from "next-auth/client"; +import { SessionProvider } from "next-auth/react"; import { appWithTranslation } from "next-i18next"; import type { AppProps as NextAppProps } from "next/app"; import React, { ComponentProps, ReactNode } from "react"; @@ -44,9 +44,9 @@ const AppProviders = (props: AppPropsWithChildren) => { - + {props.children} - + diff --git a/lib/auth.ts b/lib/auth.ts index b3b262f4f6..cf5013bb83 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,6 +1,6 @@ import { compare, hash } from "bcryptjs"; -import { DefaultSession } from "next-auth"; -import { getSession as getSessionInner, GetSessionOptions } from "next-auth/client"; +import { Session } from "next-auth"; +import { getSession as getSessionInner, GetSessionParams } from "next-auth/react"; export async function hashPassword(password: string) { const hashedPassword = await hash(password, 12); @@ -12,16 +12,7 @@ export async function verifyPassword(password: string, hashedPassword: string) { return isValid; } -type DefaultSessionUser = NonNullable; -type CalendsoSessionUser = DefaultSessionUser & { - id: number; - username: string; -}; -export interface Session extends DefaultSession { - user?: CalendsoSessionUser; -} - -export async function getSession(options: GetSessionOptions): Promise { +export async function getSession(options: GetSessionParams): Promise { const session = await getSessionInner(options); // that these are equal are ensured in `[...nextauth]`'s callback diff --git a/package.json b/package.json index 7ea0ceea5b..96463f2b1d 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "lodash": "^4.17.21", "micro": "^9.3.4", "next": "^12.0.7", - "next-auth": "^3.29.0", + "next-auth": "^4.0.6", "next-i18next": "^8.9.0", "next-seo": "^4.26.0", "next-transpile-modules": "^9.0.0", diff --git a/pages/api/auth/[...nextauth].tsx b/pages/api/auth/[...nextauth].tsx index c13174691d..ca675c8481 100644 --- a/pages/api/auth/[...nextauth].tsx +++ b/pages/api/auth/[...nextauth].tsx @@ -1,32 +1,37 @@ -import NextAuth from "next-auth"; -import Providers from "next-auth/providers"; +import NextAuth, { Session } from "next-auth"; +import CredentialsProvider from "next-auth/providers/credentials"; import { authenticator } from "otplib"; -import { ErrorCode, Session, verifyPassword } from "@lib/auth"; +import { ErrorCode, verifyPassword } from "@lib/auth"; import { symmetricDecrypt } from "@lib/crypto"; import prisma from "@lib/prisma"; export default NextAuth({ session: { - jwt: true, - }, - jwt: { - secret: process.env.JWT_SECRET, + strategy: "jwt", }, + secret: process.env.JWT_SECRET, pages: { signIn: "/auth/login", signOut: "/auth/logout", error: "/auth/error", // Error code passed in query string as ?error= }, providers: [ - Providers.Credentials({ + CredentialsProvider({ + id: "credentials", name: "Cal.com", + type: "credentials", credentials: { email: { label: "Email Address", type: "email", placeholder: "john.doe@example.com" }, password: { label: "Password", type: "password", placeholder: "Your super secure password" }, totpCode: { label: "Two-factor Code", type: "input", placeholder: "Code from authenticator app" }, }, async authorize(credentials) { + if (!credentials) { + console.error(`For some reason credentials are missing`); + throw new Error(ErrorCode.InternalServerError); + } + const user = await prisma.user.findUnique({ where: { email: credentials.email.toLowerCase(), @@ -85,14 +90,14 @@ export default NextAuth({ }), ], callbacks: { - async jwt(token, user) { + async jwt({ token, user }) { if (user) { token.id = user.id; token.username = user.username; } return token; }, - async session(session, token) { + async session({ session, token }) { const calendsoSession: Session = { ...session, user: { diff --git a/pages/api/auth/forgot-password.ts b/pages/api/auth/forgot-password.ts index 5831ed8887..80d0fe676c 100644 --- a/pages/api/auth/forgot-password.ts +++ b/pages/api/auth/forgot-password.ts @@ -54,14 +54,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) passwordRequest = createdResetPasswordRequest; } + const resetLink = `${process.env.BASE_URL}/auth/forgot-password/${passwordRequest.id}`; const passwordEmail: PasswordReset = { language: t, user: maybeUser, - resetLink: `${process.env.BASE_URL}/auth/forgot-password/${passwordRequest.id}`, + resetLink, }; await sendPasswordResetEmail(passwordEmail); + /** So we can test the password reset flow on CI */ + if ( + process.env.PLAYWRIGHT_SECRET && + req.headers["x-playwright-secret"] === process.env.PLAYWRIGHT_SECRET + ) { + return res.status(201).json({ message: "Reset Requested", resetLink }); + } + return res.status(201).json({ message: "Reset Requested" }); } catch (reason) { // console.error(reason); diff --git a/pages/api/auth/reset-password.ts b/pages/api/auth/reset-password.ts index 6f69258621..c401afd79f 100644 --- a/pages/api/auth/reset-password.ts +++ b/pages/api/auth/reset-password.ts @@ -1,14 +1,7 @@ -import { User, ResetPasswordRequest } from "@prisma/client"; -import dayjs from "dayjs"; -import timezone from "dayjs/plugin/timezone"; -import utc from "dayjs/plugin/utc"; import { NextApiRequest, NextApiResponse } from "next"; -import { hashPassword } from "../../../lib/auth"; -import prisma from "../../../lib/prisma"; - -dayjs.extend(utc); -dayjs.extend(timezone); +import { hashPassword } from "@lib/auth"; +import prisma from "@lib/prisma"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") { @@ -23,7 +16,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(400).json({ message: "Couldn't find an account for this email" }); } - const maybeRequest: ResetPasswordRequest = await prisma.resetPasswordRequest.findUnique({ + const maybeRequest = await prisma.resetPasswordRequest.findUnique({ where: { id: rawRequestId, }, @@ -33,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(400).json({ message: "Couldn't find an account for this email" }); } - const maybeUser: User = await prisma.user.findUnique({ + const maybeUser = await prisma.user.findUnique({ where: { email: maybeRequest.email, }, diff --git a/pages/api/eventType.ts b/pages/api/eventType.ts index 66f5ef9b36..f4be6d1ea8 100644 --- a/pages/api/eventType.ts +++ b/pages/api/eventType.ts @@ -1,6 +1,6 @@ import { Prisma } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { getSession } from "next-auth/client"; +import { getSession } from "next-auth/react"; import prisma from "@lib/prisma"; @@ -32,6 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }); const user = await prisma.user.findUnique({ + rejectOnNotFound: true, where: { id: session.user.id, }, diff --git a/pages/api/me.ts b/pages/api/me.ts index 6cec62b525..bf33f248f7 100644 --- a/pages/api/me.ts +++ b/pages/api/me.ts @@ -4,14 +4,18 @@ import { getSession } from "@lib/auth"; import prisma from "@lib/prisma"; import { defaultAvatarSrc } from "@lib/profile"; +/** + * @deprecated Use TRCP's viewer.me query + */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { - const session = await getSession({ req: req }); + const session = await getSession({ req }); if (!session) { res.status(401).json({ message: "Not authenticated" }); return; } - const user: User = await prisma.user.findUnique({ + const user = await prisma.user.findUnique({ + rejectOnNotFound: true, where: { id: session.user.id, }, diff --git a/pages/api/user/[id].ts b/pages/api/user/[id].ts index 2e92d64192..8eb5e53b7a 100644 --- a/pages/api/user/[id].ts +++ b/pages/api/user/[id].ts @@ -5,18 +5,19 @@ 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 }); + const session = await getSession({ req }); - if (!session) { + if (!session?.user.id) { return res.status(401).json({ message: "Not authenticated" }); } const userIdQuery = req.query?.id ?? null; - const userId = Array.isArray(userIdQuery) ? parseInt(userIdQuery.pop()) : parseInt(userIdQuery); + const userId = Array.isArray(userIdQuery) ? parseInt(userIdQuery.pop() || "") : parseInt(userIdQuery); const authenticatedUser = await prisma.user.findFirst({ + rejectOnNotFound: true, where: { - email: session.user.email, + id: session.user.id, }, select: { id: true, diff --git a/pages/auth/forgot-password/[id].tsx b/pages/auth/forgot-password/[id].tsx index c6288b0d6c..9cf850ccc4 100644 --- a/pages/auth/forgot-password/[id].tsx +++ b/pages/auth/forgot-password/[id].tsx @@ -2,7 +2,7 @@ import { ResetPasswordRequest } from "@prisma/client"; import dayjs from "dayjs"; import debounce from "lodash/debounce"; import { GetServerSidePropsContext } from "next"; -import { getCsrfToken } from "next-auth/client"; +import { getCsrfToken } from "next-auth/react"; import Link from "next/link"; import React, { useMemo } from "react"; @@ -20,15 +20,12 @@ type Props = { export default function Page({ resetPasswordRequest, csrfToken }: Props) { const { t } = useLocale(); const [loading, setLoading] = React.useState(false); - const [error, setError] = React.useState(null); + const [error, setError] = React.useState<{ message: string } | null>(null); const [success, setSuccess] = React.useState(false); const [password, setPassword] = React.useState(""); - const handleChange = (e) => { - setPassword(e.target.value); - }; - const submitChangePassword = async ({ password, requestId }) => { + const submitChangePassword = async ({ password, requestId }: { password: string; requestId: string }) => { try { const res = await fetch("/api/auth/reset-password", { method: "POST", @@ -56,30 +53,12 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { const debouncedChangePassword = debounce(submitChangePassword, 250); - const handleSubmit = async (e) => { - e.preventDefault(); - - if (!password) { - return; - } - - if (loading) { - return; - } - - setLoading(true); - setError(null); - setSuccess(false); - - await debouncedChangePassword({ password, requestId: resetPasswordRequest.id }); - }; - const Success = () => { return ( <>
-

+

{t("success")}

@@ -87,7 +66,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { @@ -101,14 +80,14 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { <>
-

{t("whoops")}

-

{t("request_is_expired")}

+

{t("whoops")}

+

{t("request_is_expired")}

{t("request_is_expired_instructions")}

@@ -123,21 +102,40 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { }, [resetPasswordRequest]); return ( -
+
-
+
{isRequestExpired && } {!isRequestExpired && !success && ( <>
-

+

{t("reset_password")}

{t("enter_new_password")}

{error &&

{error.message}

}
-
+ { + e.preventDefault(); + + if (!password) { + return; + } + + if (loading) { + return; + } + + setLoading(true); + setError(null); + setSuccess(false); + + await debouncedChangePassword({ password, requestId: resetPasswordRequest.id }); + }} + action="#">
{ + setPassword(e.target.value); + }} id="password" name="password" type="password" autoComplete="password" required - className="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-black focus:border-brand sm:text-sm" + className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-black focus:border-brand sm:text-sm" />
@@ -165,7 +165,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { }`}> {loading && ( @@ -200,12 +200,13 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) { } export async function getServerSideProps(context: GetServerSidePropsContext) { - const id = context.params.id; + const id = context.params?.id as string; try { const resetPasswordRequest = await prisma.resetPasswordRequest.findUnique({ + rejectOnNotFound: true, where: { - id: id, + id, }, select: { id: true, diff --git a/pages/auth/forgot-password/index.tsx b/pages/auth/forgot-password/index.tsx index dd0e81a09d..22ea1a78b0 100644 --- a/pages/auth/forgot-password/index.tsx +++ b/pages/auth/forgot-password/index.tsx @@ -1,6 +1,6 @@ import debounce from "lodash/debounce"; import { GetServerSidePropsContext } from "next"; -import { getCsrfToken } from "next-auth/client"; +import { getCsrfToken } from "next-auth/react"; import React, { SyntheticEvent } from "react"; import { getSession } from "@lib/auth"; @@ -35,6 +35,8 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) { const json = await res.json(); if (!res.ok) { setError(json); + } else if ("resetLink" in json) { + window.location = json.resetLink; } else { setSuccess(true); } diff --git a/pages/auth/login.tsx b/pages/auth/login.tsx index 69358ee769..84a1f4e6c9 100644 --- a/pages/auth/login.tsx +++ b/pages/auth/login.tsx @@ -1,5 +1,5 @@ import { GetServerSidePropsContext } from "next"; -import { getCsrfToken, signIn } from "next-auth/client"; +import { getCsrfToken, signIn } from "next-auth/react"; import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; @@ -46,7 +46,7 @@ export default function Login({ csrfToken }: inferSSRProps("credentials", { redirect: false, email, password, diff --git a/pages/auth/signup.tsx b/pages/auth/signup.tsx index 7b28e1087f..73a9d84ee8 100644 --- a/pages/auth/signup.tsx +++ b/pages/auth/signup.tsx @@ -1,5 +1,5 @@ import { GetServerSidePropsContext } from "next"; -import { signIn } from "next-auth/client"; +import { signIn } from "next-auth/react"; import { useRouter } from "next/router"; import { useForm, SubmitHandler, FormProvider } from "react-hook-form"; diff --git a/pages/call/[uid].tsx b/pages/call/[uid].tsx index 065e05f74d..7d44700a40 100644 --- a/pages/call/[uid].tsx +++ b/pages/call/[uid].tsx @@ -1,15 +1,20 @@ import DailyIframe from "@daily-co/daily-js"; -import { getSession } from "next-auth/client"; +import { NextPageContext } from "next"; +import { getSession } from "next-auth/react"; import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useEffect } from "react"; +import prisma from "@lib/prisma"; +import { inferSSRProps } from "@lib/types/inferSSRProps"; + import { HeadSeo } from "@components/seo/head-seo"; -import prisma from "../../lib/prisma"; +export type JoinCallPageProps = inferSSRProps; -export default function JoinCall(props, session) { +export default function JoinCall(props: JoinCallPageProps) { + const session = props.session; const router = useRouter(); //if no booking redirectis to the 404 page @@ -23,8 +28,8 @@ export default function JoinCall(props, session) { console.log(enterDate); //find out if the meeting is upcoming or in the past - const isPast = new Date(props.booking.endTime) <= exitDate; - const isUpcoming = new Date(props.booking.startTime) >= enterDate; + const isPast = new Date(props.booking?.endTime || "") <= exitDate; + const isUpcoming = new Date(props.booking?.startTime || "") >= enterDate; const meetingUnavailable = isUpcoming == true || isPast == true; useEffect(() => { @@ -33,16 +38,16 @@ export default function JoinCall(props, session) { } if (isUpcoming) { - router.push(`/call/meeting-not-started/${props.booking.uid}`); + router.push(`/call/meeting-not-started/${props.booking?.uid}`); } if (isPast) { - router.push(`/call/meeting-ended/${props.booking.uid}`); + router.push(`/call/meeting-ended/${props.booking?.uid}`); } }); useEffect(() => { - if (!meetingUnavailable && !emptyBooking && session.userid !== props.booking.user.id) { + if (!meetingUnavailable && !emptyBooking && session?.userid !== props.booking.user?.id) { const callFrame = DailyIframe.createFrame({ theme: { colors: { @@ -66,11 +71,11 @@ export default function JoinCall(props, session) { }, }); callFrame.join({ - url: props.booking.dailyRef.dailyurl, + url: props.booking.dailyRef?.dailyurl, showLeaveButton: true, }); } - if (!meetingUnavailable && !emptyBooking && session.userid === props.booking.user.id) { + if (!meetingUnavailable && !emptyBooking && session?.userid === props.booking.user?.id) { const callFrame = DailyIframe.createFrame({ theme: { colors: { @@ -94,9 +99,9 @@ export default function JoinCall(props, session) { }, }); callFrame.join({ - url: props.booking.dailyRef.dailyurl, + url: props.booking.dailyRef?.dailyurl, showLeaveButton: true, - token: props.booking.dailyRef.dailytoken, + token: props.booking.dailyRef?.dailytoken, }); } }, []); @@ -128,10 +133,10 @@ export default function JoinCall(props, session) { ); } -export async function getServerSideProps(context) { +export async function getServerSideProps(context: NextPageContext) { const booking = await prisma.booking.findUnique({ where: { - uid: context.query.uid, + uid: context.query.uid as string, }, select: { uid: true, @@ -142,6 +147,7 @@ export async function getServerSideProps(context) { endTime: true, user: { select: { + id: true, credentials: true, }, }, diff --git a/pages/call/meeting-ended/[uid].tsx b/pages/call/meeting-ended/[uid].tsx index d7c35c9542..b9a570abc8 100644 --- a/pages/call/meeting-ended/[uid].tsx +++ b/pages/call/meeting-ended/[uid].tsx @@ -1,17 +1,19 @@ import { CalendarIcon, XIcon } from "@heroicons/react/outline"; import { ArrowRightIcon } from "@heroicons/react/solid"; import dayjs from "dayjs"; -import { getSession } from "next-auth/client"; +import { NextPageContext } from "next"; +import { getSession } from "next-auth/react"; import { useRouter } from "next/router"; import { useState } from "react"; import { useEffect } from "react"; import prisma from "@lib/prisma"; +import { inferSSRProps } from "@lib/types/inferSSRProps"; import { HeadSeo } from "@components/seo/head-seo"; import Button from "@components/ui/Button"; -export default function MeetingUnavailable(props) { +export default function MeetingUnavailable(props: inferSSRProps) { const router = useRouter(); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -79,10 +81,10 @@ export default function MeetingUnavailable(props) { return null; } -export async function getServerSideProps(context) { +export async function getServerSideProps(context: NextPageContext) { const booking = await prisma.booking.findUnique({ where: { - uid: context.query.uid, + uid: context.query.uid as string, }, select: { uid: true, diff --git a/pages/call/meeting-not-started/[uid].tsx b/pages/call/meeting-not-started/[uid].tsx index c2d1aceb8f..f3807660d9 100644 --- a/pages/call/meeting-not-started/[uid].tsx +++ b/pages/call/meeting-not-started/[uid].tsx @@ -1,17 +1,19 @@ import { CalendarIcon, XIcon } from "@heroicons/react/outline"; import { ArrowRightIcon } from "@heroicons/react/solid"; import dayjs from "dayjs"; -import { getSession } from "next-auth/client"; +import { NextPageContext } from "next"; +import { getSession } from "next-auth/react"; import { useRouter } from "next/router"; import { useState } from "react"; import { useEffect } from "react"; import prisma from "@lib/prisma"; +import { inferSSRProps } from "@lib/types/inferSSRProps"; import { HeadSeo } from "@components/seo/head-seo"; import Button from "@components/ui/Button"; -export default function MeetingUnavailable(props) { +export default function MeetingNotStarted(props: inferSSRProps) { const router = useRouter(); //if no booking redirectis to the 404 page @@ -83,10 +85,10 @@ export default function MeetingUnavailable(props) { return null; } -export async function getServerSideProps(context) { +export async function getServerSideProps(context: NextPageContext) { const booking = await prisma.booking.findUnique({ where: { - uid: context.query.uid, + uid: context.query.uid as string, }, select: { uid: true, diff --git a/pages/cancel/success.tsx b/pages/cancel/success.tsx index b574d30987..9a8fc3bc86 100644 --- a/pages/cancel/success.tsx +++ b/pages/cancel/success.tsx @@ -1,6 +1,6 @@ import { CheckIcon } from "@heroicons/react/outline"; import { ArrowRightIcon } from "@heroicons/react/solid"; -import { useSession } from "next-auth/client"; +import { useSession } from "next-auth/react"; import { useRouter } from "next/router"; import { useLocale } from "@lib/hooks/useLocale"; @@ -13,7 +13,8 @@ export default function CancelSuccess() { // Get router variables const router = useRouter(); const { title, name, eventPage } = router.query; - const [session, loading] = useSession(); + const { data: session, status } = useSession(); + const loading = status === "loading"; return (
-
-
-