Skip to main content

Overview

The Vehicle Form component is dynamically generated for each vehicle based on the number specified in the Client Form. Each form captures motorization type, ITV status, and observations for individual vehicles.

HTML Structure

Vehicle forms are dynamically injected into the #formularios container:
index.html:62
<div class="formulario" id="formularios"></div>
Dynamic structure generated by JavaScript (script.js:58-102):
<div class="bloque" data-vehiculo="{N}">
    <h3>🚙 Vehículo Nº {N}</h3>

    <p>🔧 Motorización:</p>
    <label>
        <input type="radio" id="radio1{N}" name="motorizacion{N}" value="Diesel" required>
        🛢️ Diesel
    </label>
    <label>
        <input type="radio" id="radio2{N}" name="motorizacion{N}" value="Gasolina">
        ⛽ Gasolina
    </label>
    <label>
        <input type="radio" id="radio3{N}" name="motorizacion{N}" value="Hibrido">
        🔋 Híbrido
    </label>
    <label>
        <input type="radio" id="radio4{N}" name="motorizacion{N}" value="Electrico">
        ⚡ Eléctrico
    </label>
    <div class="aprobados">
        <p>📋 Estado de la ITV:</p>
        <label>
            <input type="radio" id="radio5{N}" value="Aprobo" name="aprobados{N}">
            ✅ Aprobado
        </label>
        <label>
            <input type="radio" id="radio6{N}" value="NoAprobo" name="aprobados{N}">
            ❌ No Aprobado
        </label>
    </div>
    <label for="observaciones{N}">📝 Observaciones del vehículo:</label>
    <textarea
        id="observaciones{N}"
        name="observaciones{N}"
        class="caja-texto"
        placeholder="Ingrese observaciones sobre el estado del vehículo..."
        maxlength="250"
        rows="4">
    </textarea>
</div>

Form Fields

Motorization Radio Buttons

Four mutually exclusive options for vehicle engine type:
  • Diesel (value="Diesel") - ID: radio1{N}
  • Gasolina (value="Gasolina") - ID: radio2{N}
  • Hibrido (value="Hibrido") - ID: radio3{N}
  • Electrico (value="Electrico") - ID: radio4{N}
All share the same name attribute: motorizacion{N} where {N} is the vehicle number. Validation: Required field (script.js:169-174)

ITV Status Radio Buttons

Two mutually exclusive options for inspection status:
  • Aprobado (value="Aprobo") - ID: radio5{N}
  • No Aprobado (value="NoAprobo") - ID: radio6{N}
Both share the same name attribute: aprobados{N} where {N} is the vehicle number. Validation: Required field (script.js:177-181)

Observations Textarea

  • ID: observaciones{N} where {N} is the vehicle number
  • Max length: 250 characters
  • Rows: 4
  • Required: No
  • Purpose: Free-form text for vehicle condition notes

crearFormularioVehiculo(numeroVehiculo)

Generates the HTML structure for a single vehicle form.
script.js:58-102
function crearFormularioVehiculo(numeroVehiculo) {
    return `
        <div class="bloque" data-vehiculo="${numeroVehiculo}">
            <h3>🚙 Vehículo Nº ${numeroVehiculo}</h3>

            <p>🔧 Motorización:</p>
            <label>
                <input type="radio" id="radio1${numeroVehiculo}" name="motorizacion${numeroVehiculo}" value="Diesel" required>
                🛢️ Diesel
            </label>
            <label>
                <input type="radio" id="radio2${numeroVehiculo}" name="motorizacion${numeroVehiculo}" value="Gasolina">
                ⛽ Gasolina
            </label>
            <label>
                <input type="radio" id="radio3${numeroVehiculo}" name="motorizacion${numeroVehiculo}" value="Hibrido">
                🔋 Híbrido
            </label>
            <label>
                <input type="radio" id="radio4${numeroVehiculo}" name="motorizacion${numeroVehiculo}" value="Electrico">
                ⚡ Eléctrico
            </label>
            <div class="aprobados">
                <p>📋 Estado de la ITV:</p>
                <label>
                    <input type="radio" id="radio5${numeroVehiculo}" value="Aprobo" name="aprobados${numeroVehiculo}">
                    ✅ Aprobado
                </label>
                <label>
                    <input type="radio" id="radio6${numeroVehiculo}" value="NoAprobo" name="aprobados${numeroVehiculo}">
                    ❌ No Aprobado
                </label>
            </div>
            <label for="observaciones${numeroVehiculo}">📝 Observaciones del vehículo:</label>
            <textarea
                id="observaciones${numeroVehiculo}"
                name="observaciones${numeroVehiculo}"
                class="caja-texto"
                placeholder="Ingrese observaciones sobre el estado del vehículo..."
                maxlength="250"
                rows="4">
            </textarea>
        </div>
    `;
}
Parameters:
  • numeroVehiculo (number): The vehicle number (1-indexed)
Returns: string - HTML string for the vehicle form

generarFormulariosVehiculos()

Generates all vehicle forms based on the global numeroAutos variable.
script.js:44-51
function generarFormulariosVehiculos() {
    const contenedor = document.getElementById("formularios");

    for (let i = 1; i <= numeroAutos; i++) {
        const vehiculoHTML = crearFormularioVehiculo(i);
        contenedor.innerHTML += vehiculoHTML;
    }
}
Parameters: None (uses global numeroAutos) Returns: void Behavior: Iterates from 1 to numeroAutos and appends each vehicle form to the container

validarFormulariosVehiculos()

Validates that all vehicle forms have required fields completed.
script.js:167-184
function validarFormulariosVehiculos() {
    for (let i = 1; i <= numeroAutos; i++) {
        // Verificar motorización
        const motorizacionSeleccionada = document.querySelector(`input[name="motorizacion${i}"]:checked`);
        if (!motorizacionSeleccionada) {
            mostrarError(`Por favor, seleccione la motorización para el vehículo ${i}.`);
            return false;
        }

        // Verificar estado ITV
        const itvSeleccionado = document.querySelector(`input[name="aprobados${i}"]:checked`);
        if (!itvSeleccionado) {
            mostrarError(`Por favor, seleccione el estado ITV para el vehículo ${i}.`);
            return false;
        }
    }
    return true;
}
Parameters: None Returns: boolean - true if all forms are valid, false otherwise Behavior:
  • Checks each vehicle form has a motorization selected
  • Checks each vehicle form has an ITV status selected
  • Shows error message for first missing field found
  • Returns false immediately on first validation failure

procesarDatosVehiculos()

Extracts and stores data from all vehicle forms into the global vehiculosData array.
script.js:189-204
function procesarDatosVehiculos() {
    vehiculosData = [];

    for (let i = 1; i <= numeroAutos; i++) {
        const motorizacion = document.querySelector(`input[name="motorizacion${i}"]:checked`).value;
        const estadoITV = document.querySelector(`input[name="aprobados${i}"]:checked`).value;
        const observaciones = document.getElementById(`observaciones${i}`).value.trim();

        vehiculosData.push({
            numero: i,
            motorizacion: motorizacion,
            estadoITV: estadoITV,
            observaciones: observaciones
        });
    }
}
Parameters: None Returns: void Side Effects: Populates global vehiculosData array with vehicle data objects Data Structure:
{
    numero: number,        // Vehicle number (1-indexed)
    motorizacion: string,  // "Diesel", "Gasolina", "Hibrido", or "Electrico"
    estadoITV: string,     // "Aprobo" or "NoAprobo"
    observaciones: string  // Free-form text (may be empty)
}

agregarBotonCalcular()

Adds the calculation button after all vehicle forms.
script.js:107-114
function agregarBotonCalcular() {
    const contenedor = document.getElementById("formularios");
    contenedor.innerHTML += `
        <button onclick="calcularYMostrar();" id="calcular" class="btn-primary" style="grid-column: 1 / -1; justify-self: center;">
            Calcular Resultados
        </button>
    `;
}
Parameters: None Returns: void Behavior: Appends a centered “Calcular Resultados” button spanning all grid columns

CSS Classes

.formulario

Grid container for all vehicle forms.
styles.css:173-178
.formulario {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
    gap: 2rem;
    margin-top: 2rem;
}
Behavior: Auto-fits columns with minimum 350px width

.bloque

Container for individual vehicle form.
styles.css:180-193
.bloque {
    background: #ffffff;
    padding: 1.5rem;
    border: 1px solid #e5e7eb;
    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);
    transition: all 0.3s ease;
    border-top: 3px solid #f093fb;
}

.bloque: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);
}
Features: Hover effect with elevation change and enhanced shadow

.aprobados

Special container for ITV status radio buttons with green theme.
styles.css:248-267
.aprobados {
    background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
    border: 2px solid #10b981;
    border-radius: 0.5rem;
    padding: 1rem;
    margin: 1rem 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.aprobados label {
    background: rgba(16, 185, 129, 0.1);
    border-color: rgba(16, 185, 129, 0.3);
}

.aprobados label:hover {
    background: rgba(16, 185, 129, 0.2);
    border-color: #10b981;
}

.caja-texto

Styled textarea for vehicle observations.
styles.css:270-288
.caja-texto {
    background: #ffffff;
    border: 2px solid #e5e7eb;
    border-radius: 0.5rem;
    padding: 1rem;
    width: 100% !important;
    font-size: 0.95rem;
    font-family: inherit;
    transition: all 0.2s ease;
    resize: vertical;
    min-height: 100px;
    margin: 0.5rem 0 !important;
}

.caja-texto:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}

Usage Example

// Generate forms after validating client data
function enviar() {
    const nAutosInput = document.getElementById("nAutos").value.trim();
    numeroAutos = parseInt(nAutosInput);
    
    if (numeroAutos > 0) {
        // Clear previous forms
        document.getElementById("formularios").innerHTML = "";
        vehiculosData = [];
        
        // Generate new vehicle forms
        generarFormulariosVehiculos();
        
        // Add calculate button
        agregarBotonCalcular();
    }
}

// Validate and process forms
function calcularYMostrar() {
    if (!validarFormulariosVehiculos()) {
        return; // Stop if validation fails
    }
    
    // Extract data from forms
    procesarDatosVehiculos();
    
    // vehiculosData now contains:
    // [
    //   { numero: 1, motorizacion: "Diesel", estadoITV: "Aprobo", observaciones: "..." },
    //   { numero: 2, motorizacion: "Electrico", estadoITV: "NoAprobo", observaciones: "..." }
    // ]
}

Pricing by Motorization

The vehicle forms feed into the pricing calculation:
MotorizationPrice (€)Variable
Diesel50tarifas.Diesel (script.js:270)
Gasolina45tarifas.Gasolina (script.js:271)
Hibrido35tarifas.Hibrido (script.js:272)
Electrico30tarifas.Electrico (script.js:273)

Validation Rules

FieldRuleError Message
MotorizationOne option must be selected”Por favor, seleccione la motorización para el vehículo .”
ITV StatusOne option must be selected”Por favor, seleccione el estado ITV para el vehículo .”
ObservationsOptional, max 250 charsNone

Responsive Behavior

  • Desktop (>768px): Auto-fit grid with multiple columns
  • Tablet (768px): Single column (styles.css:444-447)
  • Mobile (<480px): Reduced padding (styles.css:469-478)

Animations

Vehicle forms animate in with a fade-in effect:
styles.css:411-428
@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.bloque {
    animation: fadeIn 0.5s ease-out;
}

.bloque:nth-child(even) {
    animation-delay: 0.1s;
}
Effect: Even-numbered forms have a slight delay, creating a staggered appearance

Build docs developers (and LLMs) love