Auth Actions
// /actions/auth.ts
'use server'
import { cookies } from 'next/headers'
import { signin, signup } from '@/utils/authTools'
import { z } from 'zod'
import { redirect } from 'next/navigation'
import { COOKIE_NAME } from '@/utils/constants'
const authSchema = z.object({
email: z.string().email(),
password: z.string(),
})
export const registerUser = async (prevState: any, formData: FormData) => {
const data = authSchema.parse({
email: formData.get('email'),
password: formData.get('password'),
})
try {
const { token } = await signup(data)
cookies().set(COOKIE_NAME, token)
} catch (e) {
console.error(e)
return { message: 'Failed to sign you up' }
}
redirect('/dashboard')
}
export const signinUser = async (prevState: any, formData: FormData) => {
const data = authSchema.parse({
email: formData.get('email'),
password: formData.get('password'),
})
try {
const { token } = await signin(data)
cookies().set(COOKIE_NAME, token)
} catch (e) {
console.error(e)
return { message: 'Failed to sign you in' }
}
redirect('/dashboard')
}
Submit Button
// /components/Submit.tsx
'use client'
import { Button } from '@nextui-org/react'
import { useFormStatus } from 'react-dom'
const Submit = ({ label, ...btnProps }) => {
const { pending } = useFormStatus()
return (
<Button {...btnProps} type="submit" isLoading={pending}>
{label}
</Button>
)
}
export default Submit
Signup Form
// /components/SignupForm.tsx
'use client'
import { useFormState } from 'react-dom'
import { Input, Button } from '@nextui-org/react'
import { registerUser } from '@/actions/auth'
import Link from 'next/link'
import Submit from './Submit'
const initState = { message: null }
const SignupForm = () => {
const [formState, action] = useFormState<{ message: string | null }>(
registerUser,
initState
)
return (
<form
action={action}
className="bg-content1 border border-default-100 shadow-lg rounded-md p-3 flex flex-col gap-2 "
>
<h3 className="my-4">Sign up</h3>
<Input fullWidth size="lg" placeholder="Email" name="email" required />
<Input
name="password"
fullWidth
size="lg"
type="password"
placeholder="Password"
required
/>
<Submit label={'signup'} />
<div>
<Link href="/signin">{`Already have an account?`}</Link>
</div>
{formState?.message && <p>{formState.message}</p>}
</form>
)
}
export default SignupForm
Signin Form
// /components/SigninForm.tsx
'use client'
import { useFormState } from 'react-dom'
import { Input, Button } from '@nextui-org/react'
import { signinUser } from '@/actions/auth'
import Link from 'next/link'
import Submit from './Submit'
const initState = { message: null }
const SigninForm = () => {
const [formState, action] = useFormState<{ message: string | null }>(
signinUser,
initState
)
return (
<form
action={action}
className="bg-content1 border border-default-100 shadow-lg rounded-md p-3 flex flex-col gap-2 "
>
<h3 className="my-4">Sign in</h3>
<Input
fullWidth
required
size="lg"
placeholder="Email"
name="email"
type="email"
/>
<Input
name="password"
fullWidth
required
size="lg"
type="password"
placeholder="Password"
/>
<Submit label={'signin'} />
<div>
<Link href="/signup">{`Don't have an account?`}</Link>
</div>
{formState?.message && <p>{formState.message}</p>}
</form>
)
}
export default SigninForm