mirror of
https://github.com/jorgev259/soc_site-astro.git
synced 2025-06-29 07:57:41 +00:00
Register auth flow
This commit is contained in:
parent
2db1dd640d
commit
161c44924e
6 changed files with 293 additions and 81 deletions
|
|
@ -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,
|
||||
|
|
|
|||
15
src/components/form/Input.tsx
Normal file
15
src/components/form/Input.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import type { ComponentProps, PropsWithChildren } from 'react'
|
||||
import clsx from 'clsx'
|
||||
|
||||
export default function Input(props: PropsWithChildren<ComponentProps<'input'>>) {
|
||||
const { name, className, children, ...attrs } = props
|
||||
|
||||
return (
|
||||
<div className='flex flex-col'>
|
||||
<label htmlFor={name} className='font-medium text-black'>
|
||||
{children}:
|
||||
</label>
|
||||
<input {...attrs} name={name} className={clsx('bg-zinc-200 rounded p-2 mt-2 mb-3 text-black', className)} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -38,10 +38,13 @@ function LoginForm(props: { setForm: SetState<FormOptions>; 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) {
|
||||
|
|
|
|||
|
|
@ -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<HTMLFormElement>) {
|
||||
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 ? (
|
||||
<Modal setOpen={setModalOpen}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className='bg-white px-4 pt-5 pb-4 gap-x-4 flex flex-col'>
|
||||
<div className='px-4 pt-5 pb-4 gap-x-4 gap-y-1 flex flex-col'>
|
||||
<div className='flex gap-x-4'>
|
||||
<div className='flex flex-col'>
|
||||
<label htmlFor='username' className='font-medium text-black'>
|
||||
{m.username()}:
|
||||
</label>
|
||||
<input type='text' name='username' className='bg-zinc-200 rounded p-2 mt-2 mb-3 text-black' />
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<label htmlFor='email' className='font-medium text-black'>
|
||||
{m.email()}:
|
||||
</label>
|
||||
<input type='text' name='email' className='bg-zinc-200 rounded p-2 mt-2 mb-3 text-black' />
|
||||
</div>
|
||||
<Input name='username' required>
|
||||
{m.username()}
|
||||
</Input>
|
||||
<Input name='name' required>
|
||||
{m.displayName()}
|
||||
</Input>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<label htmlFor='pfp' className='font-medium text-black'>
|
||||
{m.profilePic()}:
|
||||
</label>
|
||||
<input
|
||||
type='file'
|
||||
name='pfp'
|
||||
className='bg-zinc-200 rounded p-2 mt-2 mb-3 text-black'
|
||||
accept='image/*'
|
||||
/>
|
||||
<Input name='email' type='email' required>
|
||||
{m.email()}
|
||||
</Input>
|
||||
<Input name='password' type='password' required>
|
||||
{m.password()}
|
||||
</Input>
|
||||
<div className='mx-auto'>
|
||||
<Button type='submit' loading={loading} disabled={loading}>
|
||||
{m.register()}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bg-zinc-200 px-4 py-3 text-right gap-x-2 flex justify-end'>
|
||||
<Button className='bg-zinc-500 hover:bg-zinc-600'>{m.close()}</Button>
|
||||
{/* <Button loading={loading} disabled={loading}>
|
||||
{m.register()}
|
||||
</Button> */}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
) : null}
|
||||
|
|
|
|||
188
src/utils/verifyTemplate.ts
Normal file
188
src/utils/verifyTemplate.ts
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
const verifyTemplate = `<!DOCTYPE html>
|
||||
|
||||
<html lang='en' xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:v='urn:schemas-microsoft-com:vml'>
|
||||
|
||||
<head>
|
||||
<title></title>
|
||||
<meta charset='utf-8' />
|
||||
<meta content='width=device-width, initial-scale=1.0' name='viewport' />
|
||||
<!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch><o:AllowPNG/></o:OfficeDocumentSettings></xml><![endif]-->
|
||||
<!--[if !mso]><!-->
|
||||
<link href='https://fonts.googleapis.com/css?family=Abril+Fatface' rel='stylesheet' type='text/css' />
|
||||
<link href='https://fonts.googleapis.com/css?family=Alegreya' rel='stylesheet' type='text/css' />
|
||||
<link href='https://fonts.googleapis.com/css?family=Arvo' rel='stylesheet' type='text/css' />
|
||||
<link href='https://fonts.googleapis.com/css?family=Bitter' rel='stylesheet' type='text/css' />
|
||||
<link href='https://fonts.googleapis.com/css?family=Cabin' rel='stylesheet' type='text/css' />
|
||||
<link href='https://fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet' type='text/css' />
|
||||
<!--<![endif]-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
th.column {
|
||||
padding: 0
|
||||
}
|
||||
|
||||
a[x-apple-data-detectors] {
|
||||
color: inherit !important;
|
||||
text-decoration: inherit !important;
|
||||
}
|
||||
|
||||
#MessageViewBody a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: inherit
|
||||
}
|
||||
|
||||
@media (max-width:520px) {
|
||||
.icons-inner {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icons-inner td {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.row-content {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.image_block img.big {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.stack .column {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style='background-color: #FFFFFF; margin: 0; padding: 0; -webkit-text-size-adjust: none; text-size-adjust: none;'>
|
||||
<table border='0' cellpadding='0' cellspacing='0' class='nl-container' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #FFFFFF;' width='100%'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<table align='center' border='0' cellpadding='0' cellspacing='0' class='row row-3'
|
||||
role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #f5f5f5;' width='100%'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<table align='center' border='0' cellpadding='0' cellspacing='0'
|
||||
class='row-content stack' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #ffffff; color: #000000;'
|
||||
width='500'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class='column'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; vertical-align: top; padding-top: 0px; padding-bottom: 5px; border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px;'
|
||||
width='100%'>
|
||||
<table border='0' cellpadding='0' cellspacing='0'
|
||||
class='image_block' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt;'
|
||||
width='100%'>
|
||||
<tr>
|
||||
<td
|
||||
style='padding-bottom:5px;padding-left:5px;padding-right:5px;width:100%;'>
|
||||
<div align='center' style='line-height:10px'><img
|
||||
alt='soc-logo' src='https://sittingonclouds.net/img/assets/clouds.png'
|
||||
style='display: block; height: auto; border: 0; width: 175px; max-width: 100%;'
|
||||
title='soc-logo' width='175' /></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border='0' cellpadding='15' cellspacing='0'
|
||||
class='button_block' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt;'
|
||||
width='100%'>
|
||||
<tr>
|
||||
<td>
|
||||
<div align='center'>
|
||||
<!--[if mso]><v:roundrect xmlns:v='urn:schemas-microsoft-com:vml' xmlns:w='urn:schemas-microsoft-com:office:word' href='{{verify_link}}' style='height:58px;width:272px;v-text-anchor:middle;' arcsize='35%' strokeweight='0.75pt' strokecolor='#FFC727' fillcolor='#e38e36'><w:anchorlock/><v:textbox inset='0px,0px,0px,0px'><center style='color:#393d47; font-family:Tahoma, Verdana, sans-serif; font-size:18px'><![endif]--><a
|
||||
href='{{verify_link}}'
|
||||
style='text-decoration:none;display:inline-block;color:#393d47;background-color:#ff7b24;border-radius:20px;width:auto;padding-top:10px;padding-bottom:10px;font-family:Tahoma, Verdana, Segoe, sans-serif;text-align:center;mso-border-alt:none;word-break:keep-all;'
|
||||
target='_blank'><span
|
||||
style='padding-left:50px;padding-right:50px;font-size:18px;display:inline-block;letter-spacing:normal;'><span
|
||||
style='font-size: 16px; line-height: 2; word-break: break-word; mso-line-height-alt: 32px;'><span
|
||||
data-mce-style='font-size: 18px; line-height: 36px;'
|
||||
style='font-size: 18px; line-height: 36px;'><strong>Verify your email address</strong></span></span></span></a>
|
||||
<!--[if mso]></center></v:textbox></v:roundrect><![endif]-->
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table align='center' border='0' cellpadding='0' cellspacing='0' class='row row-5'
|
||||
role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #f5f5f5;' width='100%'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<table align='center' border='0' cellpadding='0' cellspacing='0'
|
||||
class='row-content stack' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #000000;'
|
||||
width='500'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class='column'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; font-weight: 400; text-align: left; vertical-align: top; padding-top: 5px; padding-bottom: 5px; border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px;'
|
||||
width='100%'>
|
||||
<table border='0' cellpadding='15' cellspacing='0'
|
||||
class='text_block' role='presentation'
|
||||
style='mso-table-lspace: 0pt; mso-table-rspace: 0pt; word-break: break-word;'
|
||||
width='100%'>
|
||||
<tr>
|
||||
<td>
|
||||
<div style='font-family: Tahoma, Verdana, sans-serif'>
|
||||
<div
|
||||
style='font-size: 12px; font-family: Tahoma, Verdana, Segoe, sans-serif; mso-line-height-alt: 14.399999999999999px; color: #393d47; line-height: 1.2;'>
|
||||
<p
|
||||
style='margin: 0; font-size: 14px; text-align: center;'>
|
||||
<span style='font-size:10px;'>This link will
|
||||
expire in 24 hours</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table><!-- End -->
|
||||
</body>
|
||||
|
||||
</html>`
|
||||
|
||||
export default verifyTemplate
|
||||
Loading…
Add table
Add a link
Reference in a new issue