Desenvolvedores
src_
components_
VerdadeiroOuFalsoComponent.jsx

Explicação do Código 📜

Importação de Dependências 🛠️

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Form, FormControl, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Card, CardContent } from '@/components/ui/card';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import RichTextContent from '@/components/RichTextContent';
  • zodResolver: Importa o resolver para integrar o Zod com o React Hook Form, utilizado para validação de dados.
  • useForm: Hook do react-hook-form para gerenciar e validar o estado do formulário.
  • Controller: Componente que integra o React Hook Form com componentes personalizados, como Select.
  • z: Biblioteca de validação usada para definir e validar o esquema do formulário.
  • Button, Form, Card: Componentes UI personalizados importados para o layout e funcionalidade do formulário.

Definição do Esquema de Validação com Zod 🔐

const FormSchema = z.object({
  respostas: z.array(
    z.object({
      alternativaId: z.string(),
      resposta: z.string().nonempty('Selecione uma opção (V ou F).'),
    }),
  ),
});
  • FormSchema: Define o esquema de validação usando Zod. O campo respostas é um array de objetos, onde cada objeto tem:
    • alternativaId: Identificador da alternativa.
    • resposta: Valor da resposta, que não pode ser vazio, validado com a mensagem "Selecione uma opção (V ou F)".

Componente VerdadeiroOuFalsoComponent 🎮

const VerdadeiroOuFalsoComponent = ({ data, cursoId, exercicioId }) => {
  const form = useForm({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      respostas: data.alternativas.map((alternativa) => ({
        alternativaId: alternativa.id,
        resposta: '',
      })),
    },
  });
  • VerdadeiroOuFalsoComponent: Componente principal do quiz, que recebe os dados do exercício (data), o cursoId e o exercicioId.
  • useForm: Inicializa o formulário com o resolver do Zod para validação e define os valores padrão das respostas.

Função verificarResposta 🔍

const verificarResposta = async (formData) => {
  try {
    const formattedRespostas = formData.respostas.map((resposta) => ({
      alternativaId: resposta.alternativaId,
      resposta: resposta.resposta === 'V' ? 'true' : 'false',
    }));
 
    const response = await fetch('/api/verificar-resposta', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        cursoId,
        exercicioId,
        respostas: formattedRespostas,
        blockType: 'verdadeiroOuFalso',
      }),
    });
 
    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 (!dataResponse.isCorrect && data.explicacao) {
      form.setValue('explicacao', data.explicacao);
    } else {
      form.setValue('explicacao', null);
    }
  } catch (error) {
    console.error('Erro ao verificar a resposta:', error);
    alert('Ocorreu um erro ao verificar a resposta.');
  }
};
  • verificarResposta: Função assíncrona que é chamada ao submeter o formulário. Ela:
    • Formata as respostas para enviá-las ao backend.
    • Realiza uma requisição POST para o endpoint /api/verificar-resposta, passando os dados do exercício e as respostas.
    • Se a resposta for válida, atualiza o resultado como "Correto!" ou "Incorreto." e exibe uma explicação, se fornecida.
    • Em caso de erro, exibe um alerta.

Renderização do Formulário 💻

return (
  <Card className="mb-4">
    <CardContent>
      <RichTextContent content={data.pergunta} />
      <Form {...form}>
        <form onSubmit={form.handleSubmit(verificarResposta)} className="space-y-6">
          {data.alternativas.map((alternativa, index) => (
            <FormItem key={alternativa.id} className="flex items-center space-x-3">
              <FormControl className="w-2">
                <Controller
                  name={`respostas.${index}.resposta`}
                  control={form.control}
                  render={({ field }) => (
                    <Select onValueChange={field.onChange} value={field.value} className="">
                      <SelectTrigger className="w-19 !w-19">
                        <SelectValue placeholder="V ou F" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="V">V</SelectItem>
                        <SelectItem value="F">F</SelectItem>
                      </SelectContent>
                    </Select>
                  )}
                />
              </FormControl>
              <FormLabel className="flex-1 ">{alternativa.texto}</FormLabel>
              <input
                type="hidden"
                {...form.register(`respostas.${index}.alternativaId`)}
                value={alternativa.id}
              />
              <FormMessage>
                {form.formState.errors.respostas &&
                  form.formState.errors.respostas[index]?.resposta?.message}
              </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('resultado') === 'Incorreto.' && form.getValues('explicacao') && (
        <div className="mt-2 text-gray-600">{form.getValues('explicacao')}</div>
      )}
    </CardContent>
  </Card>
);
  • Renderização:
    • Exibe a pergunta utilizando RichTextContent.
    • Mapeia as alternativas e renderiza um Select para o usuário escolher "V" ou "F".
    • Exibe o botão para submeter as respostas e mostrar o resultado.
    • Dependendo do resultado, a cor do feedback será verde (para "Correto!") ou vermelha (para "Incorreto").
    • Se a resposta for incorreta, exibe a explicação, caso haja.

Código Completo 💻

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Form, FormControl, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Card, CardContent } from '@/components/ui/card';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import RichTextContent from '@/components/RichTextContent';
 
const FormSchema = z.object({
  respostas: z.array(
    z.object({
      alternativaId: z.string(),
      resposta: z.string().nonempty('Selecione uma opção (V ou F).'),
    }),
  ),
});
 
const VerdadeiroOuFalsoComponent = ({ data, cursoId, exercicioId }) => {
  const form = useForm({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      respostas: data.alternativas.map((alternativa) => ({
        alternativaId: alternativa.id,
        resposta: '',
      })),
    },
  });
 
  const verificarResposta = async (formData) => {
    try {
      const formattedRespostas = formData.respostas.map((resposta) => ({
        alternativaId: resposta.alternativaId,
        resposta: resposta.resposta === 'V' ? 'true' : 'false',
      }));
 
      const response = await fetch('/api/verificar-resposta', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          cursoId,
          exercicioId,
          respostas: formattedRespostas,
          blockType: 'verdadeiroOuFalso',
        }),
      });
 
      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 (!dataResponse.isCorrect && data.explicacao) {
        form.setValue('explicacao', data.explicacao);
      } else {
        form.setValue('explicacao', null);
      }
    } catch (error) {
      console.error('Erro ao verificar a resposta:', error);
      alert('Ocor
 
reu 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">
            {data.alternativas.map((alternativa, index) => (
              <FormItem key={alternativa.id} className="flex items-center space-x-3">
                <FormControl className="w-2">
                  <Controller
                    name={`respostas.${index}.resposta`}
                    control={form.control}
                    render={({ field }) => (
                      <Select onValueChange={field.onChange} value={field.value} className="">
                        <SelectTrigger className="w-19 !w-19">
                          <SelectValue placeholder="V ou F" />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="V">V</SelectItem>
                          <SelectItem value="F">F</SelectItem>
                        </SelectContent>
                      </Select>
                    )}
                  />
                </FormControl>
                <FormLabel className="flex-1 ">{alternativa.texto}</FormLabel>
                <input
                  type="hidden"
                  {...form.register(`respostas.${index}.alternativaId`)}
                  value={alternativa.id}
                />
                <FormMessage>
                  {form.formState.errors.respostas &&
                    form.formState.errors.respostas[index]?.resposta?.message}
                </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('resultado') === 'Incorreto.' && form.getValues('explicacao') && (
          <div className="mt-2 text-gray-600">{form.getValues('explicacao')}</div>
        )}
      </CardContent>
    </Card>
  );
};