diff --git a/packages/client/auth/src/CrossmintAuthClient.ts b/packages/client/auth/src/CrossmintAuthClient.ts index 378e11e29..3886bc98b 100644 --- a/packages/client/auth/src/CrossmintAuthClient.ts +++ b/packages/client/auth/src/CrossmintAuthClient.ts @@ -306,4 +306,5 @@ export class CrossmintAuthClient extends CrossmintAuth { type CrossmintAuthClientCallbacks = { onTokenRefresh?: (authMaterial: AuthMaterialWithUser) => void; onLogout?: () => void; + onLoginSuccess?: () => void; }; diff --git a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx index 4e51653e5..b7bc1f3a2 100644 --- a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx @@ -1,4 +1,13 @@ -import { type ReactNode, type MouseEvent, createContext, useEffect, useMemo, useRef, useState } from "react"; +import { + type ReactNode, + type MouseEvent, + createContext, + useEffect, + useMemo, + useRef, + useState, + useCallback, +} from "react"; import { CrossmintAuth, getCookie } from "@crossmint/client-sdk-auth"; import type { EVMSmartWalletChain } from "@crossmint/client-sdk-smart-wallet"; @@ -24,7 +33,7 @@ export type CrossmintAuthProviderProps = { embeddedWallets?: CrossmintAuthWalletConfig; appearance?: UIConfig; termsOfServiceText?: string | ReactNode; - onLoginSuccess?: () => void; + EXPERIMENTAL_onLoginSuccess?: () => void; authModalTitle?: string; children: ReactNode; loginMethods?: LoginMethod[]; @@ -68,7 +77,7 @@ export function CrossmintAuthProvider({ appearance, termsOfServiceText, authModalTitle, - onLoginSuccess, + EXPERIMENTAL_onLoginSuccess, loginMethods = ["email", "google"], refreshRoute, logoutRoute, @@ -104,6 +113,10 @@ export function CrossmintAuthProvider({ const [initialized, setInitialized] = useState(false); const [defaultEmail, setdefaultEmail] = useState(undefined); + const triggerHasJustLoggedIn = useCallback(() => { + EXPERIMENTAL_onLoginSuccess?.(); + }, [EXPERIMENTAL_onLoginSuccess]); + useEffect(() => { if (crossmint.jwt == null) { const jwt = getCookie(SESSION_PREFIX); @@ -113,19 +126,11 @@ export function CrossmintAuthProvider({ }, []); useEffect(() => { - if (crossmint.jwt == null) { - return; + if (crossmint.jwt != null && dialogOpen) { + setDialogOpen(false); + triggerHasJustLoggedIn(); } - - setDialogOpen(false); - - // FOR STANDALONE AUTH ONLY! EXCLUDING PASSKEY HELPERS. - // not for existing sessions or page refreshes. - // Skip for passkey-enabled flows as they handle success separately. - if (dialogOpen && onLoginSuccess != null && !(embeddedWallets.showPasskeyHelpers ?? true)) { - onLoginSuccess(); - } - }, [crossmint.jwt, dialogOpen, onLoginSuccess, embeddedWallets.showPasskeyHelpers]); + }, [crossmint.jwt, dialogOpen, EXPERIMENTAL_onLoginSuccess]); const login = (defaultEmail?: string | MouseEvent) => { if (crossmint.jwt != null) { @@ -186,14 +191,16 @@ export function CrossmintAuthProvider({ defaultChain={embeddedWallets.defaultChain} showPasskeyHelpers={embeddedWallets.showPasskeyHelpers} appearance={appearance} - onLoginSuccess={onLoginSuccess} - dialogOpen={dialogOpen} > { + setDialogOpen(false); + // This will be triggered from most likely the OTP form + triggerHasJustLoggedIn(); + }} preFetchOAuthUrls={getAuthStatus() === "logged-out"} initialState={{ appearance, - setDialogOpen, loginMethods, termsOfServiceText, authModalTitle, diff --git a/packages/client/ui/react-ui/src/providers/CrossmintWalletProvider.tsx b/packages/client/ui/react-ui/src/providers/CrossmintWalletProvider.tsx index b2ffda2a8..c13386a2e 100644 --- a/packages/client/ui/react-ui/src/providers/CrossmintWalletProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/CrossmintWalletProvider.tsx @@ -59,15 +59,11 @@ export function CrossmintWalletProvider({ defaultChain, showPasskeyHelpers = true, appearance, - onLoginSuccess, - dialogOpen, }: { children: ReactNode; defaultChain: EVMSmartWalletChain; showPasskeyHelpers?: boolean; appearance?: UIConfig; - onLoginSuccess?: () => void; - dialogOpen: boolean; }) { const { crossmint } = useCrossmint("CrossmintWalletProvider must be used within CrossmintProvider"); const smartWalletSDK = useMemo(() => SmartWalletSDK.init({ clientApiKey: crossmint.apiKey }), [crossmint.apiKey]); @@ -95,12 +91,6 @@ export function CrossmintWalletProvider({ enhanceConfigWithPasskeyPrompts(config) ); setWalletState({ status: "loaded", wallet }); - - // Upon getting/creating a wallet, trigger the onLoginSuccess callback - // Only fire if the dialog is open - if (onLoginSuccess != null && dialogOpen) { - onLoginSuccess(); - } } catch (error: unknown) { console.error("There was an error creating a wallet ", error); setWalletState(deriveErrorState(error)); diff --git a/packages/client/ui/react-ui/src/providers/auth/AuthFormProvider.tsx b/packages/client/ui/react-ui/src/providers/auth/AuthFormProvider.tsx index 796297176..39a765d21 100644 --- a/packages/client/ui/react-ui/src/providers/auth/AuthFormProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/auth/AuthFormProvider.tsx @@ -40,6 +40,7 @@ type ContextInitialStateProps = { }; type AuthFormProviderProps = { + setDialogOpen?: (open: boolean) => void; preFetchOAuthUrls: boolean; initialState: ContextInitialStateProps; children: ReactNode; @@ -55,23 +56,20 @@ export const useAuthForm = () => { return context; }; -export const AuthFormProvider = ({ preFetchOAuthUrls, initialState, children }: AuthFormProviderProps) => { +export const AuthFormProvider = ({ + setDialogOpen, + preFetchOAuthUrls, + initialState, + children, +}: AuthFormProviderProps) => { const { crossmintAuth } = useCrossmintAuth(); const [step, setStep] = useState("initial"); const [error, setError] = useState(null); const [oauthUrlMap, setOauthUrlMap] = useState(initialOAuthUrlMap); const [isLoadingOauthUrlMap, setIsLoadingOauthUrlMap] = useState(true); - const { - loginMethods, - baseUrl, - setDialogOpen, - appearance, - embeddedWallets, - termsOfServiceText, - authModalTitle, - defaultEmail, - } = initialState; + const { loginMethods, baseUrl, appearance, embeddedWallets, termsOfServiceText, authModalTitle, defaultEmail } = + initialState; if (loginMethods.includes("web3") && embeddedWallets?.createOnLogin === "all-users") { throw new Error("Creating wallets on login is not yet supported for web3 login method");