Implement register form

This commit is contained in:
Jorge Vargas 2024-11-15 14:41:21 -06:00
parent adeb3fd3bf
commit cdcd71cf2a
17 changed files with 526 additions and 99 deletions

View file

@ -7,8 +7,8 @@ export default function Button(props: PropsWithChildren<{ className?: string; lo
return (
<button
className={clsx(
loading ? 'bg-blue-400 cursor-progress' : 'bg-blue-600 hover:bg-blue-700',
'py-2 px-3.5 rounded-lg',
{ 'cursor-progress': loading },
'py-2 px-3.5 rounded-lg bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400',
className
)}
{...restProps}

33
src/components/Modal.tsx Normal file
View file

@ -0,0 +1,33 @@
import { useEffect, type KeyboardEvent, type PropsWithChildren } from 'react'
import type { SetState } from 'types'
export default function Modal(props: PropsWithChildren<{ setOpen: SetState<boolean> }>) {
const { children, setOpen } = props
useEffect(() => {
const handleEsc = (ev: KeyboardEvent) => {
if (ev.code === 'Escape') setOpen(false)
}
window.addEventListener('keydown', handleEsc)
return () => {
window.removeEventListener('keydown', handleEsc)
}
}, [])
return (
<div
className='fixed size-full flex bg-black bg-opacity-50 left-0 top-0 z-50 justify-center items-center'
onClick={() => setOpen(false)}
>
<div
className='bg-white rounded-lg overflow-hidden shadow-xl transform transition-all m-8'
role='dialog'
aria-modal='true'
onClick={(ev) => ev.stopPropagation()}
>
{children}
</div>
</div>
)
}

View file

@ -0,0 +1,86 @@
import type { Session } from '@auth/core/types'
import { useState } from 'react'
import { gql } from '@/graphql/__generated__/client'
import { useMutation } from '@apollo/client/react/hooks'
import Button from 'components/Button'
import * as m from 'paraglide/messages.js'
import Modal from 'components/Modal'
import apolloClient from '@/graphql/apolloClient'
import toast from 'react-hot-toast'
const registerMutation = gql(`
mutation Register($username: String!, $email: String!, $pfp: File) {
registerUser(username: $username, email: $email, pfp: $pfp)
}
`)
export default function RegisterBtn(props: { session: Session }) {
const { session } = props
const [modalOpen, setModalOpen] = useState(false)
const [mutate, { loading }] = useMutation(registerMutation, { client: apolloClient, ignoreResults: true })
if (session) return null
const handleSubmit = (ev) => {
ev.preventDefault()
const formData = new FormData(ev.target)
const variables = Object.fromEntries(formData)
mutate({ variables })
.then(() => {
toast.success(m.emailSuccess())
setModalOpen(false)
})
.catch((err) => {
toast.error(err.message)
})
}
return (
<>
<Button className='rounded-t-none' onClick={() => setModalOpen(true)}>
{m.register()}
</Button>
{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='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>
</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/*'
/>
</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}
</>
)
}