110 lines
2.8 KiB
TypeScript
110 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useMemo,
|
|
useState,
|
|
type ReactNode,
|
|
} from "react";
|
|
import { useTranslation } from "./MessagesContext";
|
|
import Login from "../components/modals/Login";
|
|
import LoginForm from "../components/modals/Login/LoginForm";
|
|
|
|
export type AuthModalLoginVariant =
|
|
| "default"
|
|
| "saveProgress"
|
|
| "keepRule"
|
|
| "invite";
|
|
|
|
export type AuthModalBackdropVariant = "solid" | "blurredYellow";
|
|
|
|
export type OpenLoginOptions = {
|
|
variant?: AuthModalLoginVariant;
|
|
/** Passed to `requestMagicLink` as `next` (internal path). */
|
|
nextPath?: string;
|
|
backdropVariant?: AuthModalBackdropVariant;
|
|
/**
|
|
* `keepRule` only: **Continue without saving**. Default is close the overlay.
|
|
* Guest completed Save & Exit passes leave-the-flow.
|
|
*/
|
|
onDismiss?: () => void;
|
|
};
|
|
|
|
type AuthModalContextValue = {
|
|
openLogin: (_opts?: OpenLoginOptions) => void;
|
|
closeLogin: () => void;
|
|
};
|
|
|
|
const AuthModalContext = createContext<AuthModalContextValue | null>(null);
|
|
|
|
export function AuthModalProvider({ children }: { children: ReactNode }) {
|
|
const tLogin = useTranslation("pages.login");
|
|
const [open, setOpen] = useState(false);
|
|
const [opts, setOpts] = useState<OpenLoginOptions>({});
|
|
|
|
const openLogin = useCallback((o?: OpenLoginOptions) => {
|
|
setOpts(o ?? {});
|
|
setOpen(true);
|
|
}, []);
|
|
|
|
const closeLogin = useCallback(() => {
|
|
setOpen(false);
|
|
setOpts({});
|
|
}, []);
|
|
|
|
const value = useMemo(
|
|
() => ({ openLogin, closeLogin }),
|
|
[openLogin, closeLogin],
|
|
);
|
|
|
|
const backdropVariant = opts.backdropVariant ?? "blurredYellow";
|
|
const keepRuleDismiss =
|
|
opts.variant === "keepRule"
|
|
? () => {
|
|
const extra = opts.onDismiss;
|
|
closeLogin();
|
|
extra?.();
|
|
}
|
|
: undefined;
|
|
|
|
return (
|
|
<AuthModalContext.Provider value={value}>
|
|
{children}
|
|
<Login
|
|
isOpen={open}
|
|
onClose={closeLogin}
|
|
backdropVariant={backdropVariant}
|
|
usePortal
|
|
ariaLabelledBy="login-modal-heading"
|
|
belowCard={
|
|
opts.variant === "invite" ? (
|
|
<button
|
|
type="button"
|
|
onClick={closeLogin}
|
|
className="w-full text-center text-small-paragraph text-[var(--color-content-default-tertiary)]"
|
|
>
|
|
{tLogin("backToYourRule")}
|
|
</button>
|
|
) : undefined
|
|
}
|
|
>
|
|
<LoginForm
|
|
variant={opts.variant ?? "default"}
|
|
magicLinkNextPath={opts.nextPath}
|
|
onDismiss={keepRuleDismiss}
|
|
/>
|
|
</Login>
|
|
</AuthModalContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useAuthModal(): AuthModalContextValue {
|
|
const ctx = useContext(AuthModalContext);
|
|
if (!ctx) {
|
|
throw new Error("useAuthModal must be used within AuthModalProvider");
|
|
}
|
|
return ctx;
|
|
}
|