📝 Bloco de Pergunta Objetiva no PayloadCMS
O PerguntaObjetiva é um bloco criado para armazenar perguntas de múltipla escolha dentro do PayloadCMS. Ele permite a criação de alternativas, a definição de uma resposta correta e a inclusão de uma explicação opcional.
🚀 Estrutura do Bloco
Esse bloco é composto pelos seguintes elementos:
slug
→ Define um identificador único do bloco.labels
→ Define os nomes no singular e plural para exibição no painel.fields
→ Define os campos da pergunta, alternativas e explicação.
import { Block } from 'payload'
import {
lexicalEditor,
FixedToolbarFeature,
InlineToolbarFeature,
} from '@payloadcms/richtext-lexical'
import { isAdminOrCreatedByField } from '@/access/isAdminOrCreatedBy'
🔹 Aqui importamos os módulos necessários:
Block
: Representa a estrutura de um bloco no PayloadCMS.lexicalEditor
: Editor de texto baseado no Lexical.FixedToolbarFeature
: Adiciona uma barra de ferramentas fixa ao editor.InlineToolbarFeature
: Adiciona uma barra de ferramentas flutuante para edição inline.isAdminOrCreatedByField
: Função de controle de acesso para restringir visualização no frontend.
🏗️ Definição do Bloco
const PerguntaObjetiva: Block = {
slug: 'perguntaObjetiva', // 🏷️ Identificador do bloco
labels: {
singular: 'Pergunta objetiva',
plural: 'Perguntas objetivas',
},
🔹 O slug
define o identificador do bloco, que será usado internamente pelo PayloadCMS.
🔹 Os rótulos (labels
) especificam os nomes para exibição no painel.
📌 Campo da Pergunta
fields: [
{
name: 'pergunta',
label: 'Enunciado da Pergunta Objetiva', // 📝 Texto da pergunta
type: 'richText',
required: true,
editor: lexicalEditor({
features: ({ defaultFeatures }) => {
return [...defaultFeatures, FixedToolbarFeature(), InlineToolbarFeature()]
},
}),
},
🔹 name: 'pergunta'
→ Define o identificador do campo.
🔹 label: 'Enunciado da Pergunta Objetiva'
→ Nome que aparecerá no painel administrativo.
🔹 type: 'richText'
→ Permite o uso do editor de texto avançado.
🔹 required: true
→ Torna o campo obrigatório.
🔢 Campo das Alternativas
{
name: 'alternativas',
label: 'Alternativas',
type: 'array',
required: true,
minRows: 2, // 🔢 Exige pelo menos duas opções
fields: [
{
type: 'row',
fields: [
{
name: 'isCorrect',
label: 'Resposta Correta ✅',
type: 'checkbox',
required: true,
defaultValue: false,
access: {
read: isAdminOrCreatedByField, // 🔒 Restrição de acesso
},
admin: {
width: '9%',
},
},
{
name: 'texto',
label: 'Texto da Alternativa 📝',
type: 'textarea',
required: true,
admin: {
width: '79%',
},
},
],
},
],
🔹 Alternativas são armazenadas como um array, garantindo que a pergunta tenha mais de uma opção.
🔹 isCorrect
→ Checkbox que define se a alternativa está correta (acesso restrito para evitar trapaças).
🔹 texto
→ Campo de texto para o conteúdo da alternativa.
🔍 Validação da Resposta
validate: (value) => {
const correctAnswers = value.filter((option: { isCorrect: any }) => option.isCorrect)
if (correctAnswers.length !== 1) {
return 'Você deve marcar exatamente uma alternativa como correta.'
}
return true
},
},
🔹 Essa função valida que apenas uma alternativa seja marcada como correta. Caso contrário, retorna um erro.
📝 Campo de Explicação (Opcional)
{
name: 'explicacao',
label: 'Explicação (opcional) 🤔',
type: 'textarea',
required: false,
},
],
}
🔹 Esse campo permite adicionar uma explicação para justificar a resposta correta.
📜 Código Completo
import { Block } from 'payload'
import {
lexicalEditor,
FixedToolbarFeature,
InlineToolbarFeature,
} from '@payloadcms/richtext-lexical'
import { isAdminOrCreatedByField } from '@/access/isAdminOrCreatedBy'
const PerguntaObjetiva: Block = {
slug: 'perguntaObjetiva',
labels: {
singular: 'Pergunta objetiva',
plural: 'Perguntas objetivas',
},
fields: [
{
name: 'pergunta',
label: 'Enunciado da Pergunta Objetiva',
type: 'richText',
required: true,
editor: lexicalEditor({
features: ({ defaultFeatures }) => {
return [...defaultFeatures, FixedToolbarFeature(), InlineToolbarFeature()]
},
}),
},
{
name: 'alternativas',
label: 'Alternativas',
type: 'array',
required: true,
minRows: 2,
fields: [
{
type: 'row',
fields: [
{
name: 'isCorrect',
label: 'Resposta Correta ✅',
type: 'checkbox',
required: true,
defaultValue: false,
access: {
read: isAdminOrCreatedByField,
},
admin: {
width: '9%',
},
},
{
name: 'texto',
label: 'Texto da Alternativa 📝',
type: 'textarea',
required: true,
admin: {
width: '79%',
},
},
],
},
],
validate: (value) => {
const correctAnswers = value.filter((option: { isCorrect: any }) => option.isCorrect)
if (correctAnswers.length !== 1) {
return 'Você deve marcar exatamente uma alternativa como correta.'
}
return true
},
},
{
name: 'explicacao',
label: 'Explicação (opcional) 🤔',
type: 'textarea',
required: false,
},
],
}
export default PerguntaObjetiva