11import type { ActionArgs , LoaderArgs } from "@remix-run/node" ;
22import { redirect } from "@remix-run/node" ;
3- import { Form , useTransition } from "@remix-run/react" ;
3+ import { Form , useNavigation , useTransition } from "@remix-run/react" ;
44import { TypedMetaFunction , typedjson , useTypedLoaderData } from "remix-typedjson" ;
55import { z } from "zod" ;
66import { LogoIcon } from "~/components/LogoIcon" ;
@@ -20,6 +20,7 @@ import magicLinkIcon from "./login.magic.svg";
2020import type { LoaderType as RootLoader } from "~/root" ;
2121import { appEnvTitleTag } from "~/utils" ;
2222import { TextLink } from "~/components/primitives/TextLink" ;
23+ import { FormError } from "~/components/primitives/FormError" ;
2324
2425export const meta : TypedMetaFunction < typeof loader , { root : RootLoader } > = ( { parentsData } ) => ( {
2526 title : `Login to Trigger.dev${ appEnvTitleTag ( parentsData ?. root . appEnv ) } ` ,
@@ -31,10 +32,26 @@ export async function loader({ request }: LoaderArgs) {
3132 } ) ;
3233
3334 const session = await getUserSession ( request ) ;
35+ const error = session . get ( "auth:error" ) ;
3436
35- return typedjson ( {
36- magicLinkSent : session . has ( "triggerdotdev:magiclink" ) ,
37- } ) ;
37+ let magicLinkError : string | undefined ;
38+ if ( error ) {
39+ if ( "message" in error ) {
40+ magicLinkError = error . message ;
41+ } else {
42+ magicLinkError = JSON . stringify ( error , null , 2 ) ;
43+ }
44+ }
45+
46+ return typedjson (
47+ {
48+ magicLinkSent : session . has ( "triggerdotdev:magiclink" ) ,
49+ magicLinkError,
50+ } ,
51+ {
52+ headers : { "Set-Cookie" : await commitSession ( session ) } ,
53+ }
54+ ) ;
3855}
3956
4057export async function action ( { request } : ActionArgs ) {
@@ -49,7 +66,7 @@ export async function action({ request }: ActionArgs) {
4966 . parse ( payload ) ;
5067
5168 if ( action === "send" ) {
52- await authenticator . authenticate ( "email-link" , request , {
69+ return authenticator . authenticate ( "email-link" , request , {
5370 successRedirect : "/login/magic" ,
5471 failureRedirect : "/login/magic" ,
5572 } ) ;
@@ -66,13 +83,13 @@ export async function action({ request }: ActionArgs) {
6683}
6784
6885export default function LoginMagicLinkPage ( ) {
69- const { magicLinkSent } = useTypedLoaderData < typeof loader > ( ) ;
70- const transition = useTransition ( ) ;
86+ const { magicLinkSent, magicLinkError } = useTypedLoaderData < typeof loader > ( ) ;
87+ const navigate = useNavigation ( ) ;
7188
7289 const isLoading =
73- ( transition . state === "loading" || transition . state === "submitting" ) &&
74- transition . type === "actionSubmission" &&
75- transition . submission . formData . get ( "action" ) === "send" ;
90+ ( navigate . state === "loading" || navigate . state === "submitting" ) &&
91+ navigate . formAction !== undefined &&
92+ navigate . formData ? .get ( "action" ) === "send" ;
7693
7794 return (
7895 < AppContainer showBackgroundGradient = { true } >
@@ -152,6 +169,7 @@ export default function LoginMagicLinkPage() {
152169 />
153170 { isLoading ? "Sending…" : "Send a magic link" }
154171 </ Button >
172+ { magicLinkError && < FormError > { magicLinkError } </ FormError > }
155173 </ Fieldset >
156174 < Paragraph variant = "extra-small" className = "my-4 text-center" >
157175 By logging in with your email you agree to our{ " " }
0 commit comments