diff --git a/packages/react/src/GadgetProvider.tsx b/packages/react/src/GadgetProvider.tsx index 7b55f2f75..fcfdeb06c 100644 --- a/packages/react/src/GadgetProvider.tsx +++ b/packages/react/src/GadgetProvider.tsx @@ -18,6 +18,8 @@ export interface GadgetAuthConfiguration { signInPath: string; /** The API identifier of the `User` `signOut` action. Defaults to `signOut` */ signOutActionApiIdentifier: string; + /** The path that users are redirected to after they sign in successfully. */ + redirectOnSuccessfulSignInPath: string; } /** Provides the api client instance, if present, as well as the Gadget auth configuration for the application. */ @@ -61,6 +63,7 @@ export interface DeprecatedProviderProps { const defaultSignInPath = "/"; const defaultSignOutApiIdentifier = "signOut"; +const defaultRedirectOnSuccessfulSignInPath = "/"; /** * Provider wrapper component that passes an api client instance to the other hooks. @@ -109,11 +112,13 @@ export function Provider(props: ProviderProps | DeprecatedProviderProps) { let signInPath = defaultSignInPath; let signOutActionApiIdentifier = defaultSignOutApiIdentifier; + let redirectOnSuccessfulSignInPath = defaultRedirectOnSuccessfulSignInPath; if ("auth" in props) { const { auth } = props; if (auth?.signInPath) signInPath = auth.signInPath; if (auth?.signOutActionApiIdentifier) signOutActionApiIdentifier = auth.signOutActionApiIdentifier; + if (auth?.redirectOnSuccessfulSignInPath) redirectOnSuccessfulSignInPath = auth.redirectOnSuccessfulSignInPath; } return ( @@ -124,6 +129,7 @@ export function Provider(props: ProviderProps | DeprecatedProviderProps) { auth: { signInPath, signOutActionApiIdentifier, + redirectOnSuccessfulSignInPath, }, }} > diff --git a/packages/react/src/auth/SignedInOrRedirect.tsx b/packages/react/src/auth/SignedInOrRedirect.tsx index aefd48e6c..514ab8993 100644 --- a/packages/react/src/auth/SignedInOrRedirect.tsx +++ b/packages/react/src/auth/SignedInOrRedirect.tsx @@ -6,7 +6,7 @@ import { useAuth } from "./useAuth.js"; /** * Renders its `children` if the current `Session` is signed in, otherwise redirects the browser to the `signInPath` configured in the `Provider`. Uses `window.location.assign` to perform the redirect. */ -export const SignedInOrRedirect = (props: { children: ReactNode }) => { +export const SignedInOrRedirect = (props: { path?: string; children: ReactNode }) => { const [redirected, setRedirected] = useState(false); const { user, isSignedIn } = useAuth(); @@ -16,11 +16,12 @@ export const SignedInOrRedirect = (props: { children: ReactNode }) => { useEffect(() => { if (auth && !redirected && (!isSignedIn || !user)) { setRedirected(true); - const redirectUrl = new URL(auth.signInPath, window.location.origin); + const redirectPath = props.path ?? auth.signInPath; + const redirectUrl = new URL(redirectPath, window.location.origin); redirectUrl.searchParams.set("redirectTo", window.location.pathname); window.location.assign(redirectUrl.toString()); } - }, [redirected, isSignedIn, auth]); + }, [props.path, redirected, isSignedIn, auth, user]); if (user && isSignedIn) { return <>{props.children}; diff --git a/packages/react/src/auth/SignedOutOrRedirect.tsx b/packages/react/src/auth/SignedOutOrRedirect.tsx index 9ab7ee1ea..34b770664 100644 --- a/packages/react/src/auth/SignedOutOrRedirect.tsx +++ b/packages/react/src/auth/SignedOutOrRedirect.tsx @@ -1,23 +1,28 @@ import type { ReactNode } from "react"; -import React, { useEffect, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; +import { GadgetConfigurationContext } from "../GadgetProvider.js"; import { useAuth } from "./useAuth.js"; /** * Renders its `children` if the current `Session` is signed out, otherwise redirects the browser to the `path` prop. Uses `window.location.assign` to perform the redirect. */ -export const SignedOutOrRedirect = (props: { path: string; children: ReactNode }) => { +export const SignedOutOrRedirect = (props: { path?: string; children: ReactNode }) => { const [redirected, setRedirected] = useState(false); const { path, children } = props; const { user, isSignedIn } = useAuth(); + const context = useContext(GadgetConfigurationContext); + const { auth } = context ?? {}; useEffect(() => { if (!redirected && (isSignedIn || user)) { setRedirected(true); - const redirectUrl = new URL(path, window.location.origin); + const searchParams = new URLSearchParams(window.location.search); + const redirectPath = searchParams.get("redirectTo") ?? path ?? auth?.signInPath ?? "/"; + const redirectUrl = new URL(redirectPath, window.location.origin); window.location.assign(redirectUrl.toString()); } - }, [redirected, isSignedIn, path, user]); + }, [redirected, isSignedIn, path, user, auth]); if (!user && !isSignedIn) { return <>{children};