Skip to content

enredacoop/flexible-form

Repository files navigation

📖 Formulario dinámico de diagnóstico

Este proyecto implementa un formulario dinámico de encuestas/diagnóstico basado en Vue/Nuxt 3, que permite:

  • Navegar entre pantallas o slices (bienvenida, preguntas, feedback, resultados).
  • Guardar las respuestas del usuario y su progreso en localStorage.
  • Calcular resultados por bloque y un resultado final con recomendaciones.
  • Adaptar el flujo de navegación de forma lineal o condicional según la configuración.

⚙️ Estructura general

El formulario se compone de:

  1. Un archivo principal (index.vue) → Controla el flujo de navegación, almacenamiento de respuestas y cálculo de resultados.
  2. Un objeto de configuración (surveyData) → Define todas las pantallas (slices) de la encuesta, las reglas de evaluación y las recomendaciones finales. Proviene de un archivo .js
  3. Componentes de presentación → (SliceWelcome, SliceQuestion, SliceFeedback, SliceEnd), que renderizan cada tipo de pantalla.

🔄 Flujo de uso

  1. El usuario ve la pantalla de bienvenida (welcome).
  2. Responde preguntas de un bloque (question).
  3. Recibe un feedback parcial (feedback) con recomendaciones.
  4. Repite el proceso en los siguientes bloques.
  5. Llega a la pantalla final (end) con un diagnóstico completo y recomendaciones globales.

🧩 Lógica del index.vue

El archivo index.vue cumple el rol de motor del formulario.

1. Estado principal

data() {
  return {
    surveyData,         // Definición de la encuesta
    currentSliceId: surveyData.slices[0].id, // Controla qué pantalla se está mostrando
    answers: [],        // Respuestas del usuario
    score: null,        // Puntuación final
    results: null       // Resultados por bloque
  }
}

2. Cálculo del slice actual

El formulario muestra un slice a la vez, definido en surveyData.slices y según el type, el sistema selecciona qué componente visual debe renderizarse.

computed: {
  currentSlice() {
    return surveyData.slices.find(s => s.id === this.currentSliceId)
  },

  currentSliceComponent() {
    switch (this.currentSlice.type) {
      case "welcome": return "SliceWelcome"
      case "question": return "SliceQuestion"
      case "feedback": return "SliceFeedback"
      case "end": return "SliceEnd"
      default: return "SliceQuestion"
    }
  }
}

3. Navegación

La navegación entre slices se define en la propiedad next de cada slice.

  • Lineal: lleva directamente al siguiente slice.
"next": "B0-02"
  • Condicional: el siguiente slice depende de la respuesta del usuario.
"next": { "yes": "Q2", "no": "Q3" }

Los métodos principales son:

  • goToNext(event) Guarda el historial de slices visitados en localStorage (previous-slices).
  • goToPrevious() Permite volver atrás eliminando la última respuesta y restaurando el slice previo.

4. Guardado de respuestas

Cada vez que el usuario responde una pregunta, se construye un objeto de respuesta:

{
  sectionId,               // ID del bloque (ej. B0)
  sectionTitle,            // Título del bloque
  sliceId,                 // ID de la pregunta
  value,                   // Valor elegido
  score,                   // Puntuación obtenida
  questionTotalPoints      // Puntos posibles en la pregunta
}

Estas respuestas se guardan en memoria (answers) y en localStorage.

5. Resultados por bloque

Cuando el usuario llega a un slice de tipo feedback, se calcula la puntuación del bloque calculateBlockResult()

  • Filtra las respuestas de la sección actual (sectionId).
  • Suma los puntajes obtenidos.
  • Calcula los puntos máximos posibles del bloque.
  • Evalúa el resultado aplicando la regla definida en surveyData.rules.
  • Guarda los resultados parciales en localStorage.

Ejemplo de resultado guardado:

{
  "sectionId": "B0",
  "sectionTitle": "Estrategia y gobernanza",
  "sectionPossibleTotalPoints": 15,
  "score": 10,
  "result": "Revisar y actualizar la política de sostenibilidad..."
}

6. Resultado final

En el último slice (end), se ejecuta calculateFinalScore()

  • Suma todos los resultados parciales.
  • Calcula el total de puntos posibles.
  • Aplica la regla de surveyData.finalRecommendations.total(score).
  • Guarda el resultado en localStorage.

Ejemplo de resultado final:

{
  "totalPossiblePoints": 75,
  "score": 42,
  "recommendations": "B Corp, ISO 14001, ISO 45001"
}

📂 Estructura del surveyData

El archivo surveyData.js define la encuesta completa.

1. Metadatos principales

export const surveyData = {
  title: "Formulario Demo",
  slices: [ ... ],   // Definición de pantallas
  rules: { ... },    // Reglas de evaluación por bloque
  finalRecommendations: { ... } // Reglas de evaluación global
}

2. Tipos de slices

Cada slice tiene un tipo (type), que determina el componente a renderizar.

  • welcome → pantalla de bienvenida.
  • question → una pregunta con opciones de respuesta.
  • feedback → resultados de un bloque de preguntas.
  • end → pantalla final con diagnóstico.

3. Ejemplo de pregunta

{
  id: "B0-01",
  type: "question",
  section: { id: "B0", title: "1. Estrategia y gobernanza" },
  question: {
    title: "¿Cuenta con una memoria de sostenibilidad?",
    description: "1 es la puntuación más baja y 5 la más alta."
  },
  input: {
    type: "range",
    options: [
      { value: "1", label: "1", score: 1 },
      { value: "2", label: "2", score: 2 },
      ...
    ]
  },
  questionTotalPoints: 5,
  next: "B0-02"
}

4. Reglas por bloque

Cada bloque (B0, B1, …) tiene una función que evalúa el puntaje:

rules: {
  B0: (score) => score <= 2
    ? "Recomendaciones básicas..."
    : "Recomendaciones avanzadas...",
  ...
}

5. Reglas finales

En finalRecommendations, se evalúa el puntaje global:

finalRecommendations: {
  total: (score) => {
    if (score <= 25) return "Certificado regional..."
    if (score <= 40) return "B Corp, ISO 14001..."
    return "GRI verificado..."
  }
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors