Created
June 8, 2022 18:53
-
-
Save vlucas/464428f8a5f6d668ea7275883c647202 to your computer and use it in GitHub Desktop.
Next.js Login Page (POSTs back to itself and handles everything)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { GetServerSidePropsContext } from 'next'; | |
import React from 'react'; | |
import AuthLayout from 'src/layouts/AuthLayout'; | |
import AlertErrors from 'src/components/AlertErrors'; | |
import { addRequestBody } from 'src/server/bodyParser'; | |
import { userLogin, userSessionInsert } from 'src/server/queries'; | |
import { redirectUserToApp, setUserAuthCookie } from 'src/server/auth'; | |
import Link from 'next/link'; | |
// Types | |
import type { TUser } from 'src/models/User'; | |
type LoginPageProps = { | |
errors: string[]; | |
formData: { email: string; password: string }; | |
pageUrl: string; | |
user: TUser | null; | |
}; | |
export default function LoginPage(props: LoginPageProps) { | |
const { errors, formData, pageUrl } = props; | |
return ( | |
<AuthLayout> | |
<fieldset className="p-6 border border-gray-500"> | |
<legend> | |
<h1 className="text-3xl font-bold">Login</h1> | |
</legend> | |
{errors && errors.length ? <AlertErrors messages={errors} /> : null} | |
<form action={pageUrl} method="POST"> | |
<div className="form-control w-full"> | |
<label className="label"> | |
<span className="label-text">Your email address</span> | |
</label> | |
<input | |
name="email" | |
type="email" | |
placeholder="[email protected]" | |
defaultValue={formData?.email} | |
className="input input-bordered w-full" | |
required | |
/> | |
</div> | |
<div className="form-control w-full"> | |
<label className="label"> | |
<span className="label-text">Password</span> | |
</label> | |
<input | |
name="password" | |
type="password" | |
placeholder="*********" | |
className="input input-bordered w-full" | |
required | |
/> | |
</div> | |
<div className="pt-6"> | |
<button className="btn btn-primary w-full">Login</button> | |
</div> | |
</form> | |
<p className="mt-6"> | |
Need an account?{' '} | |
<Link href="/auth/register"> | |
<a className="link">Register instead</a> | |
</Link> | |
</p> | |
</fieldset> | |
</AuthLayout> | |
); | |
} | |
export async function getServerSideProps(context: GetServerSidePropsContext) { | |
const method: string = context.req.method?.toUpperCase() || 'GET'; | |
const { req, res } = context; | |
const pageUrl: string = req.url || '/auth/login'; | |
if (method !== 'POST') { | |
return { props: {} }; | |
} | |
await addRequestBody(req, res); | |
// @ts-ignore - 'body' property was added by 'body-parser' middleware, but TS doesn't know about it... | |
const formData = req.body; | |
try { | |
if (!formData.email) { | |
throw new Error('Must provide an email address'); | |
} | |
if (!formData.password) { | |
throw new Error('Must provide a password'); | |
} | |
// User login | |
const user = await userLogin(formData.email, formData.password); | |
// Create new user session (log user in) | |
const userSession = await userSessionInsert(user.id); | |
// Set cookie and redirect user | |
setUserAuthCookie(req, res, user.id, userSession.id); | |
redirectUserToApp(res); | |
return { props: { user, pageUrl, formData, errors: [] } }; | |
} catch (e) { | |
const err = e as Error; | |
const errors = [err.message]; | |
res.statusCode = 400; | |
return { props: { user: null, pageUrl, formData, errors } }; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment