Skip to content

Instantly share code, notes, and snippets.

@vlucas
Created June 8, 2022 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vlucas/464428f8a5f6d668ea7275883c647202 to your computer and use it in GitHub Desktop.
Save vlucas/464428f8a5f6d668ea7275883c647202 to your computer and use it in GitHub Desktop.
Next.js Login Page (POSTs back to itself and handles everything)
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="user@example.com"
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