Explicação do Componente 📚
O PerguntaObjetivaComponent é um formulário interativo onde o usuário seleciona uma alternativa e o sistema verifica se a resposta está correta, retornando feedback visual e explicação, se disponível.
Definição do Schema com Zod 🛠️
O primeiro passo no componente é definir o esquema de validação utilizando Zod, que valida que a alternativa selecionada não está vazia.
Código de definição do esquema com Zod:
const FormSchema = z.object({
alternativaId: z.string().nonempty('Selecione uma alternativa.'),
})
- FormSchema: Utiliza Zod para garantir que o campo alternativaId seja uma string não vazia. Caso contrário, a mensagem "Selecione uma alternativa." será exibida.
Configuração do Formulário com useForm
📋
Em seguida, o hook useForm do react-hook-form é utilizado para gerenciar o estado e a validação do formulário.
Código de configuração do formulário:
const form = useForm({
resolver: zodResolver(FormSchema),
defaultValues: {
alternativaId: '',
},
})
- useForm: Gerencia o estado do formulário e validação utilizando o resolver zodResolver.
- defaultValues: Define o valor inicial do campo alternativaId como vazio.
Função para Verificar a Resposta 🔍
A função verificarResposta é responsável por enviar os dados para a API, verificar se a resposta está correta e retornar feedback ao usuário.
Código da função para verificar a resposta:
const verificarResposta = async (formData) => {
try {
const response = await fetch('/api/verificar-resposta', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
cursoId,
exercicioId,
alternativaId: formData.alternativaId,
blockType: 'perguntaObjetiva',
}),
})
if (!response.ok) {
const errorData = await response.json()
throw new Error(errorData.error || 'Erro ao verificar a resposta.')
}
const dataResponse = await response.json()
form.setValue('resultado', dataResponse.isCorrect ? 'Correto!' : 'Incorreto.')
if (data.explicacao) {
form.setValue('explicacao', data.explicacao)
}
} catch (error) {
console.error('Erro ao verificar a resposta:', error)
alert('Ocorreu um erro ao verificar a resposta.')
}
}
- fetch: Envia uma requisição POST para a API
/api/verificar-resposta
com os dados do exercício. - setValue: Atualiza o estado do formulário com o resultado da resposta (correto ou incorreto) e com uma explicação, se disponível.
- alert: Em caso de erro, exibe um alerta com a mensagem de erro.
Renderização do Formulário e Resposta 💡
O formulário é renderizado com as alternativas como RadioButtons. O feedback visual é mostrado com base no resultado da resposta.
Código de renderização do formulário e feedback:
return (
<Card className="mb-4">
<CardContent>
<RichTextContent content={data.pergunta} />
<Form {...form}>
<form onSubmit={form.handleSubmit(verificarResposta)} className="space-y-6">
<FormField
control={form.control}
name="alternativaId"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel>Selecione uma alternativa</FormLabel>
<FormControl>
<RadioGroup
onValueChange={field.onChange}
value={field.value}
className="space-y-2"
>
{data.alternativas.map((alternativa) => (
<FormItem key={alternativa.id} className="flex items-center space-x-3">
<FormControl>
<RadioGroupItem value={alternativa.id} />
</FormControl>
<FormLabel>{alternativa.texto}</FormLabel>
</FormItem>
))}
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Verificar Resposta</Button>
</form>
</Form>
{form.getValues('resultado') && (
<div
className={`mt-2 ${
form.getValues('resultado') === 'Correto!' ? 'text-green-600' : 'text-red-600'
}`}
>
{form.getValues('resultado')}
</div>
)}
{form.getValues('explicacao') && (
<div className="mt-2 text-gray-600">{form.getValues('explicacao')}</div>
)}
</CardContent>
</Card>
)
- RadioGroup: Exibe as alternativas de resposta como botões de rádio. Quando o usuário seleciona uma, o estado do formulário é atualizado.
- Button: Envia o formulário para verificar a resposta.
- feedback visual: O texto de "Correto!" ou "Incorreto." é exibido abaixo do formulário com cores apropriadas (verde ou vermelho).
Código Completo 🖥️
'use client'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form'
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
import { Card, CardContent } from '@/components/ui/card'
import RichTextContent from '@/components/RichTextContent'
const FormSchema = z.object({
alternativaId: z.string().nonempty('Selecione uma alternativa.'),
})
const PerguntaObjetivaComponent = ({ data, cursoId, exercicioId }) => {
const form = useForm({
resolver: zodResolver(FormSchema),
defaultValues: {
alternativaId: '',
},
})
const verificarResposta = async (formData) => {
try {
const response = await fetch('/api/verificar-resposta', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
cursoId,
exercicioId,
alternativaId: formData.alternativaId,
blockType: 'perguntaObjetiva',
}),
})
if (!response.ok) {
const errorData = await response.json()
throw new Error(errorData.error || 'Erro ao verificar a resposta.')
}
const dataResponse = await response.json()
form.setValue('resultado', dataResponse.isCorrect ? 'Correto!' : 'Incorreto.')
if (data.explicacao) {
form.setValue('explicacao', data.explicacao)
}
} catch (error) {
console.error('Erro ao verificar a resposta:', error)
alert('Ocorreu um erro ao verificar a resposta.')
}
}
return (
<Card className="mb-4">
<CardContent>
<RichTextContent content={data.pergunta} />
<Form {...form}>
<form onSubmit={form.handleSubmit(verificarResposta)} className="space-y-6">
<FormField
control={form.control}
name="alternativaId"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel>Selecione uma alternativa</FormLabel>
<FormControl>
<RadioGroup
onValueChange={field.onChange}
value={field.value}
className="space-y-2"
>
{data.alternativas.map((alternativa) => (
<FormItem key={alternativa.id} className="flex items-center space-x-3">
<FormControl>
<RadioGroupItem value={alternativa.id} />
</FormControl>
<FormLabel>{alternativa.texto}</FormLabel>
</FormItem>
))}
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Verificar Resposta</Button>
</form>
</Form>
{form.getValues('resultado') && (
<div
className={`mt-2 ${
form.getValues('resultado') === 'Correto!' ? 'text-green-600' : 'text-red-600'
}`}
>
{form.getValues('resultado')}
</div>
)}
{form.getValues('explicacao') && (
<div className="mt-2 text-gray-600">{form.getValues('explicacao')}</div>
)}
</CardContent>
</Card>
)
}
export default PerguntaObjetivaComponent