cal.pub0.org/pages/auth/signup.tsx

179 lines
6.0 KiB
TypeScript

import { signIn } from "next-auth/client";
import { useRouter } from "next/router";
import { useState } from "react";
import { useLocale } from "@lib/hooks/useLocale";
import prisma from "@lib/prisma";
import { HeadSeo } from "@components/seo/head-seo";
import { UsernameInput } from "@components/ui/UsernameInput";
import ErrorAlert from "@components/ui/alerts/Error";
export default function Signup(props) {
const { t } = useLocale();
const router = useRouter();
const [hasErrors, setHasErrors] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const handleErrors = async (resp) => {
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.message);
}
};
const signUp = (e) => {
e.preventDefault();
if (e.target.password.value !== e.target.passwordcheck.value) {
throw new Error("Password mismatch");
}
const email: string = e.target.email.value;
const password: string = e.target.password.value;
fetch("/api/auth/signup", {
body: JSON.stringify({
username: e.target.username.value,
password,
email,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
})
.then(handleErrors)
.then(() => signIn("Cal.com", { callbackUrl: (router.query.callbackUrl || "") as string }))
.catch((err) => {
setHasErrors(true);
setErrorMessage(err.message);
});
};
return (
<div
className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true">
<HeadSeo title={t("sign_up")} description={t("sign_up")} />
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="font-cal text-center text-3xl font-extrabold text-gray-900">
{t("create_your_account")}
</h2>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow mx-2 sm:rounded-lg sm:px-10">
<form method="POST" onSubmit={signUp} className="bg-white space-y-6">
{hasErrors && <ErrorAlert message={errorMessage} />}
<div>
<div className="mb-2">
<UsernameInput required />
</div>
<div className="mb-2">
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
{t("email")}
</label>
<input
type="email"
name="email"
inputMode="email"
id="email"
placeholder="jdoe@example.com"
disabled={!!props.email}
readOnly={!!props.email}
value={props.email}
className="bg-gray-100 mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-black focus:border-black sm:text-sm"
/>
</div>
<div className="mb-2">
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
{t("password")}
</label>
<input
type="password"
name="password"
id="password"
required
placeholder="•••••••••••••"
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-black focus:border-black sm:text-sm"
/>
</div>
<div>
<label htmlFor="passwordcheck" className="block text-sm font-medium text-gray-700">
{t("confirm_password")}
</label>
<input
type="password"
name="passwordcheck"
id="passwordcheck"
required
placeholder="•••••••••••••"
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-black focus:border-black sm:text-sm"
/>
</div>
</div>
<div className="mt-3 sm:mt-4 flex">
<input
type="submit"
value={t("create_account")}
className="btn btn-primary w-7/12 mr-2 inline-flex justify-center rounded-md border border-transparent cursor-pointer shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black sm:text-sm"
/>
<a
onClick={() => signIn("Cal.com", { callbackUrl: (router.query.callbackUrl || "") as string })}
className="w-5/12 inline-flex justify-center text-sm text-gray-500 font-medium border px-4 py-2 rounded btn cursor-pointer">
{t("login_instead")}
</a>
</div>
</form>
</div>
</div>
</div>
);
}
export async function getServerSideProps(ctx) {
if (!ctx.query.token) {
return {
notFound: true,
};
}
const verificationRequest = await prisma.verificationRequest.findUnique({
where: {
token: ctx.query.token,
},
});
// for now, disable if no verificationRequestToken given or token expired
if (!verificationRequest || verificationRequest.expires < new Date()) {
return {
notFound: true,
};
}
const existingUser = await prisma.user.findFirst({
where: {
AND: [
{
email: verificationRequest.identifier,
},
{
emailVerified: {
not: null,
},
},
],
},
});
if (existingUser) {
return {
redirect: { permanent: false, destination: "/auth/login?callbackUrl=" + ctx.query.callbackUrl },
};
}
return { props: { email: verificationRequest.identifier } };
}