From 161c44924e07fff2a1a66334a136331cfce30fd3 Mon Sep 17 00:00:00 2001 From: Jorge Vargas Date: Tue, 11 Feb 2025 11:32:11 -0600 Subject: [PATCH] Register auth flow --- messages/en.json | 71 ++++----- src/auth.ts | 6 +- src/components/form/Input.tsx | 15 ++ src/components/header/LoginButton.tsx | 11 +- src/components/header/RegisterButton.tsx | 83 +++++----- src/utils/verifyTemplate.ts | 188 +++++++++++++++++++++++ 6 files changed, 293 insertions(+), 81 deletions(-) create mode 100644 src/components/form/Input.tsx create mode 100644 src/utils/verifyTemplate.ts diff --git a/messages/en.json b/messages/en.json index c552f95..cdba67d 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1,36 +1,37 @@ { - "$schema": "https://inlang.com/schema/inlang-message-format", - "register": "Register", - "login": "Login", - "logout": "Logout", - "username": "Username", - "password": "Password", - "email": "Email", - "recoverPassword": "Recover Password", - "home": "Home", - "lastaddednav": "Last Added", - "albumlist": "Album List", - "games": "Games", - "albums": "Albums", - "series": "Series", - "publishers": "Publishers", - "platforms": "Platforms", - "gamelist": "Game List", - "animation": "Animation", - "animationlist": "Animation List", - "studios": "Studios", - "requests": "Requests", - "submitalbum": "Submit Album", - "adminGrounds": "Admin Grounds", - "manageAlbums": "Manage Albums", - "manageUsers": "Manage Users", - "manageRequests": "Manage Requests", - "manageSubmissions": "Manage Submissions", - "profilePic": "Profile picture", - "emailSuccess": "An email with further instructions has been sent to the address linked to the account. Check your spam folder.", - "close": "Close", - "newPassword": "New password", - "newPasswordRetype": "Re-type new password", - "savePassword": "Save Password", - "passwordResetSuccesful": "Password reset succesfully" -} + "$schema": "https://inlang.com/schema/inlang-message-format", + "register": "Register", + "login": "Login", + "logout": "Logout", + "username": "Username", + "password": "Password", + "email": "Email", + "recoverPassword": "Recover Password", + "home": "Home", + "lastaddednav": "Last Added", + "albumlist": "Album List", + "games": "Games", + "albums": "Albums", + "series": "Series", + "publishers": "Publishers", + "platforms": "Platforms", + "gamelist": "Game List", + "animation": "Animation", + "animationlist": "Animation List", + "studios": "Studios", + "requests": "Requests", + "submitalbum": "Submit Album", + "adminGrounds": "Admin Grounds", + "manageAlbums": "Manage Albums", + "manageUsers": "Manage Users", + "manageRequests": "Manage Requests", + "manageSubmissions": "Manage Submissions", + "profilePic": "Profile picture", + "emailSuccess": "An email with further instructions has been sent to the address linked to the account. Check your spam folder.", + "close": "Close", + "newPassword": "New password", + "newPasswordRetype": "Re-type new password", + "savePassword": "Save Password", + "passwordResetSuccesful": "Password reset succesfully", + "displayName": "Display name" +} \ No newline at end of file diff --git a/src/auth.ts b/src/auth.ts index 626a562..af95db4 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -5,6 +5,7 @@ import { username } from 'better-auth/plugins' import prismaClient from './utils/prisma-client' import { sendEmail } from 'utils/email' import forgorTemplate from 'utils/forgorTemplate' +import verifyTemplate from 'utils/verifyTemplate' export const auth = betterAuth({ database: prismaAdapter(prismaClient, { provider: 'mysql' }), @@ -12,7 +13,10 @@ export const auth = betterAuth({ plugins: [username()], emailVerification: { sendOnSignUp: true, - autoSignInAfterVerification: true + autoSignInAfterVerification: true, + async sendVerificationEmail({ user, url }) { + await sendEmail(user.email, 'Verify your email address', verifyTemplate.replaceAll('{{verify_link}}', url)) + } }, emailAndPassword: { enabled: true, diff --git a/src/components/form/Input.tsx b/src/components/form/Input.tsx new file mode 100644 index 0000000..26e80cd --- /dev/null +++ b/src/components/form/Input.tsx @@ -0,0 +1,15 @@ +import type { ComponentProps, PropsWithChildren } from 'react' +import clsx from 'clsx' + +export default function Input(props: PropsWithChildren>) { + const { name, className, children, ...attrs } = props + + return ( +
+ + +
+ ) +} diff --git a/src/components/header/LoginButton.tsx b/src/components/header/LoginButton.tsx index 86e96d8..205a315 100644 --- a/src/components/header/LoginButton.tsx +++ b/src/components/header/LoginButton.tsx @@ -38,10 +38,13 @@ function LoginForm(props: { setForm: SetState; setModalOpen: SetSta const variables = Object.fromEntries(formData) setLoading(true) - const { error } = await signIn.username({ - username: variables.username as string, - password: variables.password as string - }) + const { error } = await signIn.username( + { + username: variables.username as string, + password: variables.password as string + }, + {} + ) setLoading(false) if (error) { diff --git a/src/components/header/RegisterButton.tsx b/src/components/header/RegisterButton.tsx index 0fcee70..325766e 100644 --- a/src/components/header/RegisterButton.tsx +++ b/src/components/header/RegisterButton.tsx @@ -1,26 +1,39 @@ -import { useState } from 'react' -// import toast from 'react-hot-toast' +import { useState, type FormEvent } from 'react' +import toast from 'react-hot-toast' import * as m from 'paraglide/messages.js' import Button from 'components/Button' import Modal from 'components/Modal' +import Input from 'components/form/Input' +import { signUp } from 'utils/auth-client' export default function RegisterBtn() { const [modalOpen, setModalOpen] = useState(false) + const [loading, setLoading] = useState(false) - const handleSubmit = (ev) => { + async function handleSubmit(ev: FormEvent) { ev.preventDefault() - const formData = new FormData(ev.target) - const variables = Object.fromEntries(formData) + const formData = new FormData(ev.currentTarget) + const variables = Object.fromEntries(formData) as { + username: string + name: string + password: string + email: string + } - /* mutate({ variables }) - .then(() => { - toast.success(m.emailSuccess()) + setLoading(true) + await signUp.email(variables, { + onSuccess: () => { + toast.success(m.emailSuccess(), { duration: Infinity }) + setLoading(false) setModalOpen(false) - }) - .catch((err) => { - toast.error(err.message) - }) */ + }, + onError: (ctx) => { + console.log(ctx.error) + toast.error(ctx.error.message) + setLoading(false) + } + }) } return ( @@ -31,39 +44,27 @@ export default function RegisterBtn() { {modalOpen ? (
-
+
-
- - -
-
- - -
+ + {m.username()} + + + {m.displayName()} +
-
- - + + {m.email()} + + + {m.password()} + +
+
-
- - {/* */} -
) : null} diff --git a/src/utils/verifyTemplate.ts b/src/utils/verifyTemplate.ts new file mode 100644 index 0000000..1d59ead --- /dev/null +++ b/src/utils/verifyTemplate.ts @@ -0,0 +1,188 @@ +const verifyTemplate = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` + +export default verifyTemplate