Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion app/components/alerts.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CheckCircleIcon } from '@heroicons/react/solid'
import { CheckCircleIcon, XCircleIcon } from '@heroicons/react/solid'
import { ReactNode } from 'react'

export function Alert({ children }: { children: ReactNode }) {
Expand All @@ -18,3 +18,18 @@ export function Alert({ children }: { children: ReactNode }) {
</div>
)
}

export function ErrorAlert({ children }: { children: ReactNode }) {
return (
<div className="bg-red-50 border-l-4 border-red-400 py-3 px-4 mt-4">
<div className="flex">
<div className="flex-shrink-0">
<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
</div>
<div className="ml-3">
<p className="text-sm font-medium text-red-900">{children}</p>
</div>
</div>
</div>
)
}
29 changes: 22 additions & 7 deletions app/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import type { ActionFunction, LoaderFunction } from '@remix-run/node'
import { json } from '@remix-run/node'
import { Form, useLoaderData, useNavigation } from '@remix-run/react'
import { Alert } from '~/components/alerts'
import { Alert, ErrorAlert } from '~/components/alerts'
import { Button } from '~/components/form-elements'
import { auth } from '~/services/auth.server'
import { getUserSession } from '~/services/session.server'
import { commitSession, getUserSession } from '~/services/session.server'

export const loader: LoaderFunction = async ({ request }) => {
await auth.isAuthenticated(request, { successRedirect: '/dashboard' })
const session = await getUserSession(request)
// This session key `auth:magiclink` is the default one used by the EmailLinkStrategy
// you can customize it passing a `sessionMagicLinkKey` when creating an
// instance.
return json({
user: session.get('user'),
magicLinkSent: session.has('zain:magiclink'),
})
const error = session.get(auth.sessionErrorKey) as
| { message: string }
| undefined
return json(
{
user: session.get('user'),
magicLinkSent: session.has('zain:magiclink'),
error: error?.message,
},
{
headers: {
'Set-Cookie': await commitSession(session),
},
}
)
}

export const action: ActionFunction = async ({ request }) => {
Expand All @@ -31,7 +42,10 @@ export const action: ActionFunction = async ({ request }) => {
}

export default function Login() {
const { magicLinkSent } = useLoaderData<{ magicLinkSent: boolean }>()
const { magicLinkSent, error } = useLoaderData<{
magicLinkSent: boolean
error?: string
}>()
const { state } = useNavigation()

return (
Expand Down Expand Up @@ -79,6 +93,7 @@ export default function Login() {
</Button>
</div>
</Form>
{error ? <ErrorAlert>{error}</ErrorAlert> : null}
{magicLinkSent ? (
<Form action="/logout" method="post">
<input type="hidden" name="redirectTo" value="/login" />
Expand Down
2 changes: 1 addition & 1 deletion app/services/session.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const sessionStorage = createCookieSessionStorage({
sameSite: 'lax',
path: '/',
httpOnly: true,
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
maxAge: 7 * 24 * 60 * 60, // 7 days in seconds
secrets: [getRequiredServerEnvVar('SESSION_SECRET')],
// normally you want this to be `secure: true`
// but that doesn't work on localhost for Safari
Expand Down
Loading