O código a seguir implementa um formulário de registro com validação de dados e integração com a API para criar um novo aluno. Vamos passar por cada parte do código com uma explicação detalhada e incluir emojis para tornar a leitura mais envolvente 😄.
Importações 📦
O código começa com as importações necessárias:
'use client'
import React from 'react'
import { useRouter } from 'next/navigation'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import InputCpf from '@/components/InputCpf'
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import BackgroundVideo from '@/components/BackgroundVideo'
import { toast } from 'sonner'useFormezodResolversão usados para gerenciar a validação do formulário de forma eficiente.zé utilizado para definir o esquema de validação dos dados.- Componentes como
Button,InputeCardsão usados para construir a interface de usuário.
Definição do Esquema de Validação 📋
Aqui, usamos o zod para definir o esquema de validação dos dados do formulário:
const formSchema = z.object({
fullName: z.string().min(3, { message: 'Nome completo deve ter pelo menos 3 caracteres.' }),
email: z.string().email({ message: 'Email inválido' }),
cpf: z.string().min(11, { message: 'CPF inválido.' }),
password: z.string().min(6, { message: 'Senha deve ter pelo menos 6 caracteres.' }),
})fullNamedeve ter pelo menos 3 caracteres.emailprecisa ser um email válido.cpfdeve ter no mínimo 11 caracteres.passwordprecisa ter pelo menos 6 caracteres.
Inicialização do Formulário 📝
A seguir, inicializamos o formulário com o useForm e passamos o esquema de validação para ele:
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
fullName: '',
email: '',
cpf: '',
password: '',
},
})Aqui estamos configurando o formulário com valores iniciais vazios para todos os campos.
Função de Submissão 🔄
Quando o formulário é enviado, o onSubmit é chamado para enviar os dados para a API:
const onSubmit = async (values) => {
try {
const apiUrl = process.env.NEXT_PUBLIC_SERVER_URL
const response = await fetch(`${apiUrl}/api/alunos`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nomeCompleto: values.fullName,
email: values.email,
cpf: values.cpf,
password: values.password,
}),
})
if (!response.ok) {
throw new Error('Erro ao registrar o aluno')
}
const data = await response.json()
toast('Conta criada com sucesso!', {
description: <span style={{ color: '#d1d5db' }}>Faça seu login agora</span>,
style: {
backgroundColor: '#15803d',
color: 'white',
},
})
router.push('/login')
} catch (error) {
console.error('Erro:', error)
}
}Aqui, o código faz uma requisição POST para o backend com os dados do aluno e, se a requisição for bem-sucedida, exibe uma mensagem de sucesso.
Estrutura do Formulário 💻
A interface de usuário é construída com componentes reutilizáveis para criar os campos do formulário:
return (
<div className="relative w-full h-screen overflow-y-auto bg-background">
<BackgroundVideo />
<div className="relative z-10 min-h-screen py-8 flex flex-col items-center justify-center">
<Card className="p-8 rounded-lg shadow-lg max-w-md w-full mx-4">
<CardHeader>
<CardTitle>Registrar</CardTitle>
<CardDescription>Bem-vindo, crie sua conta de aluno abaixo</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="fullName"
render={({ field }) => (
<FormItem>
<FormLabel>
Nome Completo <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input placeholder="Digite seu nome" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>
Email <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input type="email" placeholder="email@exemplo.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="cpf"
render={({ field }) => (
<FormItem>
<FormLabel>
CPF <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<InputCpf control={form.control} name="cpf" />
</FormControl>
<FormDescription>
É fundamental seu nome completo e CPF estarem corretos para gerarmos seus
certificados
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
Senha <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input type="password" placeholder="Digite sua senha" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-center">
<Button type="submit">Registrar</Button>
</div>
</form>
</Form>
</CardContent>
</Card>
<div className="text-balance text-center mt-4 text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-primary ">
Ao clicar em continuar, você concorda com nossos <br></br>
<a href="#">Termos de Serviço</a> e <a href="#"> Política de Privacidade</a>.
</div>
</div>
</div>
)Aqui é onde a UI é renderizada, incluindo o fundo com o BackgroundVideo, o card de formulário, e o botão de submissão.
Código Completo 📝
'use client'
import React from 'react'
import { useRouter } from 'next/navigation'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import InputCpf from '@/components/InputCpf'
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import BackgroundVideo from '@/components/BackgroundVideo'
import { toast } from 'sonner'
const formSchema = z.object({
fullName: z.string().min(3, { message: 'Nome completo deve ter pelo menos 3 caracteres.' }),
email: z.string().email({ message: 'Email inválido' }),
cpf: z.string().min(11, { message: 'CPF inválido.' }),
password: z.string().min(6, { message: 'Senha deve ter pelo menos 6 caracteres.' }),
})
const RegisterForm = () => {
const router = useRouter()
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
fullName: '',
email: '',
cpf: '',
password: '',
},
})
const onSubmit = async (values) => {
try {
const apiUrl = process.env.NEXT_PUBLIC_SERVER_URL
const response = await fetch(`${apiUrl}/api/alunos`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nomeCompleto: values.fullName,
email: values.email,
cpf: values.cpf,
password: values.password,
}),
})
if (!response.ok) {
throw new Error('Erro ao registrar o aluno')
}
const data = await response.json()
toast('Conta criada com sucesso!', {
description: <span style={{ color: '#d1d5db' }}>Faça seu login agora</span>,
style: {
backgroundColor: '#15803d',
color: 'white',
},
})
router.push('/login')
} catch (error) {
console.error('Erro:', error)
}
}
return (
<div className="relative w-full h-screen overflow-y-auto bg-background">
<BackgroundVideo />
<div className="relative z-10 min-h-screen py-8 flex flex-col items-center justify-center">
<Card className="p-8 rounded-lg shadow-lg max-w-md w-full mx-4">
<CardHeader>
<CardTitle>Registrar</CardTitle>
<CardDescription>Bem-vindo, crie sua conta de aluno abaixo</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="fullName"
render={({ field }) => (
<FormItem>
<FormLabel>
Nome Completo <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input placeholder="Digite seu nome" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>
Email <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input type="email" placeholder="email@exemplo.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="cpf"
render={({ field }) => (
<FormItem>
<FormLabel>
CPF <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<InputCpf control={form.control} name="cpf" />
</FormControl>
<FormDescription>
É fundamental seu nome completo e CPF estarem corretos para gerarmos seus
certificados
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
Senha <span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input type="password" placeholder="Digite sua senha" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-center">
<Button type="submit">Registrar</Button>
</div>
</form>
</Form>
</CardContent>
</Card>
<div className="text-balance text-center mt-4 text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-primary ">
Ao clicar em continuar, você concorda com nossos <br></br>
<a href="#">Termos de Serviço</a> e <a href="#"> Política de Privacidade</a>.
</div>
</div>
</div>
)
}
export default RegisterForm