Skip to main content

Overview

The Results Display component shows the final summary after processing all vehicle forms. It presents client information, total costs with breakdown, ITV status for each vehicle, and consolidated observations.

HTML Structure

The results section is initially hidden and displayed after form processing:
index.html:68-105
<section id="muestra" class="results-section">
    <!-- Tarjeta con información del cliente -->
    <div class="info-card">
        <div class="informacion" id="informacion">
            <h3>👤 Información del Cliente</h3>
        </div>
    </div>

    <!-- Tarjeta con el total a pagar -->
    <div class="info-card">
        <div class="total">
            <h3>💰 Total a Pagar</h3>
            <div class="total-amount">
                <span id="total">€0</span>
            </div>
        </div>
    </div>

    <!-- Tarjeta con el estado de la ITV -->
    <div class="info-card">
        <div id="resultados" class="resultados">
            <h3>✅ Estado ITV</h3>
            <div class="status-content">
                <span id="raprobado"></span>
            </div>
        </div>
    </div>

    <!-- Tarjeta con observaciones (ancho completo) -->
    <div class="info-card full-width">
        <div class="observacion">
            <h3>📝 Observaciones</h3>
            <div class="observations-content">
                <span id="robservaciones"></span>
            </div>
        </div>
    </div>
</section>

Sections

Client Information Card

Displays customer details from the client form. Container ID: #informacion Populated by: mostrarInformacionCliente(datos) (script.js:210-218) Content Structure:
<h3>👤 Información del Cliente</h3>
<div>Nombre: <span>{nombre}</span></div>
<div>Apellidos: <span>{apellidos}</span></div>
<div>Razón Social: <span>{razonSocial}</span></div>
<div>Nº de Vehículos: <span>{nAutos}</span></div>

Total Amount Card

Shows cost breakdown by motorization type and grand total. Container ID: #total Populated by: calcularYMostrarTotal() (script.js:268-319) Content Structure:
<div class="total-desglose">
    <div class="desglose-item">
        {emoji} {count} {type}: {cost}€
    </div>
    <!-- Repeated for each motorization type with vehicles -->
    <div class="total-final">
        💰 Total: {totalGeneral}€
    </div>
</div>

ITV Status Card

Displays approval status for each vehicle. Container ID: #raprobado Populated by: mostrarEstadosITV() (script.js:223-239) Content Structure:
<div class="estado-vehiculo {clase}">
    {emoji} Vehículo Nº {numero}: {estado}
</div>
<!-- Repeated for each vehicle -->

Observations Card

Consolidates all vehicle observations. Container ID: #robservaciones Populated by: mostrarObservaciones() (script.js:244-263) Content Structure:
<div class="observacion-vehiculo">
    <strong>🚗 Vehículo Nº {numero}:</strong><br>
    <div class="caja-texto">{observaciones}</div>
</div>
<!-- Repeated for each vehicle with observations -->
<!-- If no observations: -->
<em>Sin observaciones registradas</em>

mostrarInformacionCliente(datos)

Populates the client information card with customer data.
script.js:210-218
function mostrarInformacionCliente(datos) {
    document.getElementById("informacion").innerHTML = `
        <h3>👤 Información del Cliente</h3>
        <div>Nombre: <span>${datos.nombre}</span></div>
        <div>Apellidos: <span>${datos.apellidos}</span></div>
        <div>Razón Social: <span>${datos.razonSocial}</span></div>
        <div>Nº de Vehículos: <span>${datos.nAutos}</span></div>
    `;
}
Parameters:
  • datos (Object):
    • nombre (string): Customer first name
    • apellidos (string): Customer last name(s)
    • razonSocial (string): Business name
    • nAutos (number): Number of vehicles
Returns: void

mostrarEstadosITV()

Displays ITV approval status for all vehicles using data from vehiculosData array.
script.js:223-239
function mostrarEstadosITV() {
    let estadosHTML = "";

    vehiculosData.forEach(vehiculo => {
        const emoji = vehiculo.estadoITV === "Aprobo" ? "✅" : "❌";
        const estado = vehiculo.estadoITV === "Aprobo" ? "Aprobado" : "No Aprobado";
        const clase = vehiculo.estadoITV === "Aprobo" ? "aprobado" : "no-aprobado";

        estadosHTML += `
            <div class="estado-vehiculo ${clase}">
                ${emoji} Vehículo Nº ${vehiculo.numero}: ${estado}
            </div>
        `;
    });

    document.getElementById("raprobado").innerHTML = estadosHTML;
}
Parameters: None (uses global vehiculosData) Returns: void Styling:
  • .estado-vehiculo.aprobado: Green theme (styles.css:646-650)
  • .estado-vehiculo.no-aprobado: Red theme (styles.css:651-655)

mostrarObservaciones()

Consolidates and displays observations from all vehicles.
script.js:244-263
function mostrarObservaciones() {
    let observacionesHTML = "";

    vehiculosData.forEach(vehiculo => {
        if (vehiculo.observaciones) {
            observacionesHTML += `
                <div class="observacion-vehiculo">
                    <strong>🚗 Vehículo Nº ${vehiculo.numero}:</strong><br>
                    <div class="caja-texto">${vehiculo.observaciones}</div>
                </div>
            `;
        }
    });

    if (observacionesHTML === "") {
        observacionesHTML = "<em>Sin observaciones registradas</em>";
    }

    document.getElementById("robservaciones").innerHTML = observacionesHTML;
}
Parameters: None (uses global vehiculosData) Returns: void Behavior: Only displays vehicles with non-empty observations. Shows fallback message if none exist.

calcularYMostrarTotal()

Calculates total cost based on motorization types and displays detailed breakdown.
script.js:268-319
function calcularYMostrarTotal() {
    const tarifas = {
        "Diesel": 50,
        "Gasolina": 45,
        "Hibrido": 35,
        "Electrico": 30
    };

    let contadores = {
        "Diesel": 0,
        "Gasolina": 0,
        "Hibrido": 0,
        "Electrico": 0
    };

    // Contar vehículos por tipo de motorización
    vehiculosData.forEach(vehiculo => {
        contadores[vehiculo.motorizacion]++;
    });

    // Calcular costos por tipo
    const costos = {
        diesel: tarifas.Diesel * contadores.Diesel,
        gasolina: tarifas.Gasolina * contadores.Gasolina,
        hibrido: tarifas.Hibrido * contadores.Hibrido,
        electrico: tarifas.Electrico * contadores.Electrico
    };

    const totalGeneral = costos.diesel + costos.gasolina + costos.hibrido + costos.electrico;

    // Crear desglose detallado
    let desglose = "";
    Object.keys(contadores).forEach(tipo => {
        if (contadores[tipo] > 0) {
            const costo = tarifas[tipo] * contadores[tipo];
            desglose += `
                <div class="desglose-item">
                    ${obtenerEmojiMotorizacion(tipo)} ${contadores[tipo]} ${tipo}: ${costo}
                </div>
            `;
        }
    });

    document.getElementById("total").innerHTML = `
        <div class="total-desglose">
            ${desglose}
            <div class="total-final">
                💰 Total: ${totalGeneral}
            </div>
        </div>
    `;
}
Parameters: None (uses global vehiculosData) Returns: void Pricing:
  • Diesel: €50
  • Gasolina: €45
  • Hibrido: €35
  • Electrico: €30

ocultarCaja()

Hides the client and vehicle forms with animation before showing results.
script.js:339-355
function ocultarCaja() {
    const formularios = document.getElementById("formularios");
    const formSection = document.querySelector(".form-section");
    const resultados = document.getElementById("muestra");

    // Animación de salida para formularios dinámicos y sección principal
    formularios.style.opacity = "0";
    formularios.style.transform = "translateY(-20px)";
    formSection.style.opacity = "0";
    formSection.style.transform = "translateY(-20px)";

    setTimeout(() => {
        formularios.style.display = "none";
        formSection.style.display = "none";
        mostrarResultados();
    }, 300);
}
Parameters: None Returns: void Behavior: Fades out forms over 300ms, then calls mostrarResultados()

mostrarResultados()

Reveals the results section with smooth animation.
script.js:360-375
function mostrarResultados() {
    const resultados = document.getElementById("muestra");
    resultados.classList.add("show");

    // Animación de entrada
    setTimeout(() => {
        resultados.style.opacity = "1";
        resultados.style.transform = "translateY(0)";
    }, 100);

    // Scroll suave hacia los resultados
    resultados.scrollIntoView({
        behavior: "smooth",
        block: "start"
    });
}
Parameters: None Returns: void Behavior:
  1. Adds .show class to enable grid display
  2. Fades in with transform animation
  3. Smoothly scrolls results into view

calcularYMostrar()

Orchestrates the entire calculation and display workflow.
script.js:693-704
function calcularYMostrar() {
    // Validar que todos los vehículos tengan datos completos
    if (!validarFormulariosVehiculos()) {
        return; // Detener la ejecución si hay errores
    }
    // Si la validación es exitosa, calcular y mostrar resultados
    calcular();
    ocultarCaja();
    setTimeout(() => {
        agregarBotonesAccion();
    }, 500);
}
Parameters: None Returns: void Workflow:
  1. Validates all vehicle forms
  2. Calls calcular() to process data
  3. Calls ocultarCaja() to hide forms
  4. After 500ms, adds action buttons (print, export, reset)

calcular()

Core calculation function that populates all result sections.
script.js:119-148
function calcular() {
    try {
        // Obtener datos del cliente
        const datosCliente = obtenerDatosCliente();

        // Validar que todos los vehículos tengan datos completos
        if (!validarFormulariosVehiculos()) {
            return;
        }

        // Procesar datos de vehículos
        procesarDatosVehiculos();

        // Mostrar información del cliente
        mostrarInformacionCliente(datosCliente);

        // Mostrar estados de ITV
        mostrarEstadosITV();

        // Mostrar observaciones
        mostrarObservaciones();

        // Calcular y mostrar total
        calcularYMostrarTotal();

    } catch (error) {
        console.error("Error en el cálculo:", error);
        mostrarError("Ha ocurrido un error al procesar los datos. Por favor, verifique la información ingresada.");
    }
}
Parameters: None Returns: void Error Handling: Catches exceptions and displays error message

CSS Classes

.results-section

Main container for all result cards. Hidden by default.
styles.css:291-304
.results-section {
    display: none;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
    padding: 2rem;
    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
    border-radius: 0.75rem;
    border: 1px solid #e5e7eb;
}

.results-section.show {
    display: grid;
}
Behavior: Becomes visible grid when .show class is added

.info-card

Individual card wrapper for each result section.
styles.css:306-322
.info-card {
    background: #ffffff;
    border-radius: 0.75rem;
    box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
    border: 1px solid #e5e7eb;
    overflow: hidden;
    transition: all 0.3s ease;
}

.info-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}

.info-card.full-width {
    grid-column: 1 / -1;
}
Variants:
  • .full-width: Spans all grid columns (used for observations)

.total-amount

Highlighted container for total cost display.
styles.css:361-374
.total-amount {
    text-align: center;
    padding: 1.5rem;
    background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
    border-radius: 0.5rem;
    border: 2px solid #10b981;
}

.total-amount span {
    font-size: 2rem;
    font-weight: 800;
    color: #10b981;
    text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

Dynamic Status Classes

Classes for ITV status indicators:
styles.css:638-655
.estado-vehiculo {
    padding: 0.75rem;
    margin: 0.5rem 0;
    border-radius: 0.5rem;
    font-weight: 600;
    background: rgba(37, 99, 235, 0.05);
    border-left: 4px solid #2563eb;
}
.estado-vehiculo.aprobado {
    background: rgba(16, 185, 129, 0.1);
    border-left-color: #10b981;
    color: #10b981;
}
.estado-vehiculo.no-aprobado {
    background: rgba(239, 68, 68, 0.1);
    border-left-color: #ef4444;
    color: #ef4444;
}

Cost Breakdown Classes

styles.css:663-684
.total-desglose {
    text-align: left;
}
.desglose-item {
    padding: 0.5rem;
    margin: 0.25rem 0;
    background: rgba(16, 185, 129, 0.1);
    border-radius: 0.375rem;
    font-size: 0.95rem;
    font-weight: 600;
}
.total-final {
    margin-top: 1rem;
    padding: 1rem;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: 0.5rem;
    text-align: center;
    font-size: 1.25rem;
    font-weight: 800;
    text-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

Usage Example

// After validating and processing vehicle forms
function displayResults() {
    // 1. Get client data
    const clientData = obtenerDatosCliente();
    
    // 2. Process vehicle data
    procesarDatosVehiculos();
    
    // 3. Populate result sections
    mostrarInformacionCliente(clientData);
    mostrarEstadosITV();
    mostrarObservaciones();
    calcularYMostrarTotal();
    
    // 4. Hide forms and show results
    ocultarCaja();
}

// Complete workflow
function calcularYMostrar() {
    if (validarFormulariosVehiculos()) {
        calcular();
        ocultarCaja();
        setTimeout(() => {
            agregarBotonesAccion();
        }, 500);
    }
}

Action Buttons

After results are displayed, additional action buttons are added:
script.js:578-604
function agregarBotonesAccion() {
    const muestra = document.getElementById("muestra");

    if (!document.getElementById("botones-accion")) {
        const botonesHTML = `
            <div id="botones-accion" class="info-card full-width">
                <div style="padding: 1.5rem; text-align: center;">
                    <h3> Acciones Disponibles</h3>
                    <div style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; margin-top: 1rem;">
                        <button onclick="imprimirResultados()" class="btn-secondary">
                            🖨️ Imprimir
                        </button>
                        <button onclick="exportarResultados()" class="btn-secondary">
                            📥 Exportar JSON
                        </button>
                        <button onclick="reiniciarFormulario()" class="btn-secondary">
                            🔄 Nuevo Formulario
                        </button>
                    </div>
                </div>
            </div>
        `;
        muestra.innerHTML += botonesHTML;
        agregarEstilosBotonSecundario();
    }
}
Available Actions:
  • Imprimir: Prints results via imprimirResultados() (script.js:551-573)
  • Exportar JSON: Downloads data as JSON via exportarResultados() (script.js:529-548)
  • Nuevo Formulario: Resets application via reiniciarFormulario() (script.js:522-526)

Responsive Behavior

  • Desktop (>768px): Auto-fit grid with multiple columns
  • Tablet (768px): Single column layout (styles.css:448-452)
  • Mobile (<480px): Reduced padding (styles.css:472-478)

Accessibility Features

  • Semantic HTML with proper heading hierarchy
  • High contrast text on colored backgrounds
  • Keyboard-accessible action buttons
  • Smooth scroll to results when displayed
  • Clear visual distinction between approved/rejected status

Data Flow

Client Form → enviar()

Vehicle Forms → validarFormulariosVehiculos()

Data Extraction → procesarDatosVehiculos()

Calculation → calcular()

Results Display → mostrarInformacionCliente()
                  → mostrarEstadosITV()
                  → mostrarObservaciones()
                  → calcularYMostrarTotal()

Visual Transition → ocultarCaja() → mostrarResultados()

Action Buttons → agregarBotonesAccion()

Build docs developers (and LLMs) love