Desenvolvedores
src_
components_
PerguntaObjetivaComponent.jsx

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