import React, { Suspense, useEffect } from "react"; import Login from "../../app/components/modals/Login"; import LoginForm from "../../app/components/modals/Login/LoginForm"; /** * Storybook runs outside Next.js request context; successful "Send link" needs fetch mocked * because `requestMagicLink` POSTs to `/api/auth/magic-link/request`. */ function MagicLinkFetchMock({ children }: { children: React.ReactNode }) { useEffect(() => { const orig = globalThis.fetch; globalThis.fetch = async ( input: RequestInfo | URL, init?: RequestInit, ): Promise => { const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url; if (url.includes("/api/auth/magic-link/request")) { return new Response("{}", { status: 200, headers: { "Content-Type": "application/json" }, }); } return orig(input as Request, init); }; return () => { globalThis.fetch = orig; }; }, []); return <>{children}; } /** Fake marketing page behind the overlay (header “Log in” opens `AuthModalProvider` with this look). */ function FakeMarketingPageBehindOverlay({ children, }: { children: React.ReactNode; }) { return (

Placeholder page content — the login overlay portals above this and uses backdrop blur (`blurredYellow`).

{children}
); } export default { title: "Components/Modals/Login", component: Login, parameters: { layout: "fullscreen", nextjs: { appDirectory: true, navigation: { pathname: "/", }, }, docs: { description: { component: '**Primary UX:** `AuthModalProvider` opens this as a **popup overlay** on top of the current page — `backdropVariant="blurredYellow"`, `usePortal` (default). **`/login`** is a thin full-page shell: yellow **solid** backdrop, `usePortal={false}`, same `LoginForm` inside.', }, }, }, decorators: [ (Story: () => React.ReactNode) => ( ), ], tags: ["autodocs"], }; /** Matches `AuthModalProvider`: blurred backdrop + portal over whatever route the user was on. */ export const HeaderOverlayBlurred = { name: "Header overlay (blurred — default)", parameters: { docs: { description: { story: 'Same as **Log in** from the site header: `backdropVariant="blurredYellow"`, `usePortal`, card + “Back to home” below.', }, }, }, render: () => ( {}} backdropVariant="blurredYellow" usePortal ariaLabelledBy="login-modal-heading" belowCard={ ← Back to home } > Loading…

}>
), }; /** Matches `app/login/page.tsx`: dedicated route, solid yellow, no portal. */ export const FullPageRouteSolid = { name: "Full-page route (/login — solid)", parameters: { nextjs: { navigation: { pathname: "/login" }, }, docs: { description: { story: "Verify-email **error** links and bookmarks use `/login` with a **solid** backdrop and `usePortal={false}`.", }, }, }, decorators: [ (Story: () => React.ReactNode) => (
), ], render: () => ( {}} backdropVariant="solid" usePortal={false} ariaLabelledBy="login-modal-heading" belowCard={ ← Back to home } > Loading…

}>
), }; export const ModalChromeOnly = { name: "Modal chrome only (placeholder)", render: () => (
{}} backdropVariant="solid" usePortal={false} ariaLabelledBy="login-modal-heading" belowCard={ ← Back to home } >

Placeholder body — use "Header overlay" or "Full-page route" for the real flow.

), }; export const FormOnly = { name: "Login form (card inset)", parameters: { docs: { description: { story: "Form only, for inspecting copy and layout without overlay chrome. In the app it is always wrapped by `Login` (modal) or the `/login` page shell.", }, }, }, decorators: [ (Story: () => React.ReactNode) => (
), ], render: () => (
Loading…

}>
), };