fix onboarding login glitch (#1118)
This commit is contained in:
parent
9befd4abb9
commit
df687009bd
4 changed files with 59 additions and 20 deletions
1
.github/workflows/e2e.yml
vendored
1
.github/workflows/e2e.yml
vendored
|
@ -9,6 +9,7 @@ jobs:
|
||||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||||
BASE_URL: http://localhost:3000
|
BASE_URL: http://localhost:3000
|
||||||
JWT_SECRET: secret
|
JWT_SECRET: secret
|
||||||
|
GOOGLE_API_CREDENTIALS: "{}"
|
||||||
# GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
# GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||||
# CRON_API_KEY: xxx
|
# CRON_API_KEY: xxx
|
||||||
# CALENDSO_ENCRYPTION_KEY: xxx
|
# CALENDSO_ENCRYPTION_KEY: xxx
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
import { signOut, useSession } from "next-auth/client";
|
import { signOut, useSession } from "next-auth/client";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { ReactNode, useEffect } from "react";
|
import React, { ReactNode, useEffect, useState } from "react";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
|
|
||||||
import LicenseBanner from "@ee/components/LicenseBanner";
|
import LicenseBanner from "@ee/components/LicenseBanner";
|
||||||
|
@ -37,7 +37,11 @@ import { useViewerI18n } from "./I18nLanguageHandler";
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
|
|
||||||
function useMeQuery() {
|
function useMeQuery() {
|
||||||
const meQuery = trpc.useQuery(["viewer.me"]);
|
const meQuery = trpc.useQuery(["viewer.me"], {
|
||||||
|
retry(failureCount) {
|
||||||
|
return failureCount > 3;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return meQuery;
|
return meQuery;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +49,6 @@ function useMeQuery() {
|
||||||
function useRedirectToLoginIfUnauthenticated() {
|
function useRedirectToLoginIfUnauthenticated() {
|
||||||
const [session, loading] = useSession();
|
const [session, loading] = useSession();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const query = useMeQuery();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && !session) {
|
if (!loading && !session) {
|
||||||
|
@ -56,28 +59,36 @@ function useRedirectToLoginIfUnauthenticated() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [loading, session, router]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [loading, session]);
|
||||||
|
|
||||||
if (query.status !== "loading" && !query.data) {
|
return {
|
||||||
router.replace("/auth/login");
|
loading: loading && !session,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function useRedirectToOnboardingIfNeeded() {
|
function useRedirectToOnboardingIfNeeded() {
|
||||||
const [session, loading] = useSession();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const query = useMeQuery();
|
const query = useMeQuery();
|
||||||
const user = query.data;
|
const user = query.data;
|
||||||
|
|
||||||
|
const [isRedirectingToOnboarding, setRedirecting] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && user) {
|
if (user && shouldShowOnboarding(user)) {
|
||||||
if (shouldShowOnboarding(user)) {
|
setRedirecting(true);
|
||||||
router.replace({
|
|
||||||
pathname: "/getting-started",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [loading, session, router, user]);
|
}, [router, user]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (isRedirectingToOnboarding) {
|
||||||
|
router.replace({
|
||||||
|
pathname: "/getting-started",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isRedirectingToOnboarding]);
|
||||||
|
return {
|
||||||
|
isRedirectingToOnboarding,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ShellSubHeading(props: {
|
export function ShellSubHeading(props: {
|
||||||
|
@ -109,8 +120,8 @@ export default function Shell(props: {
|
||||||
}) {
|
}) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
useRedirectToLoginIfUnauthenticated();
|
const { loading } = useRedirectToLoginIfUnauthenticated();
|
||||||
useRedirectToOnboardingIfNeeded();
|
const { isRedirectingToOnboarding } = useRedirectToOnboardingIfNeeded();
|
||||||
|
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
|
||||||
|
@ -157,7 +168,7 @@ export default function Shell(props: {
|
||||||
|
|
||||||
const i18n = useViewerI18n();
|
const i18n = useViewerI18n();
|
||||||
|
|
||||||
if (i18n.status === "loading") {
|
if (i18n.status === "loading" || isRedirectingToOnboarding || loading) {
|
||||||
// show spinner whilst i18n is loading to avoid language flicker
|
// show spinner whilst i18n is loading to avoid language flicker
|
||||||
return (
|
return (
|
||||||
<div className="z-50 absolute w-full h-screen bg-gray-50 flex items-center">
|
<div className="z-50 absolute w-full h-screen bg-gray-50 flex items-center">
|
||||||
|
|
|
@ -45,7 +45,7 @@ export function loginProvider(opts: {
|
||||||
if (cachedCookies) {
|
if (cachedCookies) {
|
||||||
await context.addCookies(cachedCookies);
|
await context.addCookies(cachedCookies);
|
||||||
} else {
|
} else {
|
||||||
await page.goto("http://localhost:3000/event-types");
|
await page.goto("http://localhost:3000/auth/login");
|
||||||
// Click input[name="email"]
|
// Click input[name="email"]
|
||||||
await page.click('input[name="email"]');
|
await page.click('input[name="email"]');
|
||||||
// Fill input[name="email"]
|
// Fill input[name="email"]
|
||||||
|
@ -57,7 +57,12 @@ export function loginProvider(opts: {
|
||||||
// Press Enter
|
// Press Enter
|
||||||
await page.press('input[name="password"]', "Enter");
|
await page.press('input[name="password"]', "Enter");
|
||||||
|
|
||||||
await page.waitForSelector("[data-testid=event-types]");
|
await page.waitForNavigation({
|
||||||
|
url(url) {
|
||||||
|
return !url.pathname.startsWith("/auth");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const cookies = await context.cookies();
|
const cookies = await context.cookies();
|
||||||
cookieCache.set(opts.user, cookies);
|
cookieCache.set(opts.user, cookies);
|
||||||
}
|
}
|
||||||
|
|
22
playwright/onboarding.test.ts
Normal file
22
playwright/onboarding.test.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { kont } from "kont";
|
||||||
|
|
||||||
|
import { loginProvider } from "./lib/loginProvider";
|
||||||
|
|
||||||
|
jest.setTimeout(60e3);
|
||||||
|
jest.retryTimes(2);
|
||||||
|
|
||||||
|
const ctx = kont()
|
||||||
|
.useBeforeEach(
|
||||||
|
loginProvider({
|
||||||
|
user: "onboarding",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.done();
|
||||||
|
|
||||||
|
test("redirects to /getting-started after login", async () => {
|
||||||
|
await ctx.page.waitForNavigation({
|
||||||
|
url(url) {
|
||||||
|
return url.pathname === "/getting-started";
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue