terminado

This commit is contained in:
Jaime Jiménez
2025-09-11 12:15:56 +02:00
parent 6a9c197a02
commit 67b5f9457e
15 changed files with 311 additions and 91 deletions

View File

@ -1,37 +1,54 @@
(function () {
"use strict";
"use strict";
const default_lang = "es";
const language = localStorage.getItem("language");
const DEFAULT_LANG = "es";
function initLanguage() {
const saved = localStorage.getItem("language") || default_lang;
setLanguage(saved, false); // solo actualiza bandera y lang
document.querySelectorAll('.language').forEach(a => {
a.addEventListener('click', () => setLanguage(a.dataset.lang, true));
});
}
function getCurrentLang() {
// Viene del servidor (Thymeleaf): <html th:lang="${#locale.language}">
return document.documentElement.lang || DEFAULT_LANG;
}
function setLanguage(lang, redirect = true) {
const already = document.documentElement.lang === lang;
function setFlag(lang) {
const img = document.getElementById("header-lang-img");
if (!img) return;
img.src = (lang === "en")
? "/assets/images/flags/gb.svg"
: "/assets/images/flags/spain.svg";
}
// Actualiza <html lang> y bandera
document.documentElement.lang = lang;
document.getElementById("header-lang-img").src =
lang === "en" ? "/assets/images/flags/gb.svg"
: "/assets/images/flags/spain.svg";
localStorage.setItem("language", lang);
function onLanguageClick(e) {
e.preventDefault();
const lang = this.dataset.lang;
if (!lang || lang === getCurrentLang()) return;
// Redirige si cambia el idioma
if (!already && redirect) {
const url = new URL(location.href);
url.searchParams.set("lang", lang);
location.href = url.toString();
}
}
// Guarda la preferencia (opcional)
try { localStorage.setItem("language", lang); } catch {}
// Llama al inicializador de idioma en cuanto el DOM esté listo
document.addEventListener("DOMContentLoaded", function () {
initLanguage();
});
// Redirige con ?lang=... para que Spring cambie el Locale y renderice en ese idioma
const url = new URL(location.href);
url.searchParams.set("lang", lang);
location.assign(url);
}
function initLanguage() {
// Usa el idioma actual que viene del servidor
const current = getCurrentLang();
setFlag(current);
// Enlaces/ botones de idioma: .language[data-lang="en|es"]
document.querySelectorAll(".language").forEach(a => {
a.addEventListener("click", onLanguageClick);
});
// (Opcional) si guardaste algo en localStorage y quieres forzar
// la alineación al entrar por 1ª vez:
const saved = localStorage.getItem("language");
if (saved && saved !== current) {
const url = new URL(location.href);
url.searchParams.set("lang", saved);
location.replace(url); // alinea y no deja historial extra
}
}
document.addEventListener("DOMContentLoaded", initLanguage);
})();

View File

@ -129,6 +129,7 @@ class PresupuestoCliente {
this.summaryTableCubierta = $('#summary-cubierta');
this.summaryTableSobrecubierta = $('#summary-sobrecubierta');
this.summaryTableFaja = $('#summary-faja');
this.summaryTableExtras = $('#summary-servicios-extras');
}
init() {
@ -1280,6 +1281,7 @@ class PresupuestoCliente {
type: 'POST',
data: data,
success: (data) => {
this.divExtras.data('language-calcular', data.language.calcular);
this.#loadExtrasData(data.servicios_extra);
this.#changeTab('pills-extras');
},
@ -1350,15 +1352,22 @@ class PresupuestoCliente {
if (id === 'btn-prev-extras') {
this.#changeTab('pills-seleccion-tirada');
this.summaryTableExtras.addClass('d-none');
} else {
//this.#changeTab('pills-finalizar');
}
});
// Eventos para el resumen
$(document).on('change', '.service-checkbox', (e) => {
Summary.updateExtras();
});
}
#loadExtrasData(servicios) {
this.divExtras.empty();
this.summaryTableExtras.removeClass('d-none');
this.divExtras.removeClass('animate-fadeInUpBounce');
this.divExtras.addClass('animate-fadeInUpBounce');
@ -1366,6 +1375,8 @@ class PresupuestoCliente {
const item = new ServiceOptionCard(extra);
this.divExtras.append(item.render());
}
Summary.updateExtras();
}

View File

@ -1,9 +1,19 @@
$(document).on('click', '#maquetacion', function (e) {
import * as Summary from "./summary.js";
$(document).on('change', '#maquetacion', function (e) {
e.preventDefault();
$.get("/presupuesto/public/maquetacion/form", function (data) {
$("#maquetacionModalBody").html(data);
$("#maquetacionModal").modal("show");
});
if ($('#maquetacion').is(':checked')) {
$.get("/presupuesto/public/maquetacion/form", function (data) {
$("#maquetacionModalBody").html(data);
$("#maquetacionModal").modal("show");
});
} else {
const calcularStr = $('#div-extras').data('language-calcular');
$('#maquetacion').data('price', calcularStr);
$('label[for="maquetacion"] .service-price')
.text(calcularStr);
$('#maquetacion').prop('checked', false);
}
});
$(document).on("submit", "#maquetacionForm", function (e) {
@ -15,15 +25,91 @@ $(document).on("submit", "#maquetacionForm", function (e) {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize(),
success: function (data) {
// obtener el json devuelto
const json = JSON.parse(data);
dataType: "json",
success: function (json) {
const modalEl = document.getElementById("maquetacionModal");
const modal = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
modal.hide();
const resumenHtml = `
<div class="text-start">
<p>Páginas calculadas: ${json.numPaginasEstimadas ?? "-"}</p>
<p>Precio por página estimado: ${formateaMoneda(json.precioPaginaEstimado) || "-"}</p>
<hr class="my-2">
${json.precio ?
`<h3 class="mb-0"><strong>Precio:</strong> ${formateaMoneda(json.precio)}</h3>` : ""}
</div>
`;
Swal.fire({
title: json.language.presupuesto_maquetacion || 'Presupuesto Maquetación',
html: resumenHtml,
icon: 'info',
showCancelButton: true,
confirmButtonText: json.language.add_to_presupuesto || 'Añadir al presupuesto',
cancelButtonText: json.language.cancel || 'Cancelar',
customClass: {
confirmButton: 'btn btn-secondary me-2', // clases para el botón confirmar
cancelButton: 'btn btn-light' // clases para cancelar
},
buttonsStyling: false,
reverseButtons: false,
allowOutsideClick: false
}).then((result) => {
if (result.isConfirmed) {
$('#maquetacion').prop('checked', true);
$('#maquetacion').data('price', json.precio);
$('label[for="maquetacion"] .service-price')
.text(formateaMoneda(json.precio));
Summary.updateExtras();
}
else {
const calcularStr = $('#div-extras').data('language-calcular');
$('#maquetacion').prop('checked', false);
$('#maquetacion').data('price', calcularStr);
$('label[for="maquetacion"] .service-price').text(calcularStr);
}
});
},
error: function (xhr, status, error) {
$("#maquetacionModalBody").html(
"<div class='alert alert-danger'>" + xhr.responseText + "</div>"
);
try {
const errs = JSON.parse(xhr.responseText); // { numCaracteres: "…" , … }
// limpia errores previos
$form.find(".is-invalid").removeClass("is-invalid");
$form.find(".invalid-feedback").text("");
// recorre los errores y los muestra
Object.entries(errs).forEach(([field, msg]) => {
const $input = $form.find(`[name="${field}"]`);
if ($input.length) {
$input.addClass("is-invalid");
$input.siblings(".invalid-feedback").text(msg);
}
});
} catch {
$("#maquetacionModalBody").html(
"<div class='alert alert-danger'>" + xhr.responseText + "</div>"
);
}
}
});
});
});
$(document).on('hidden.bs.modal', '#maquetacionModal', function () {
const calcularStr = $('#div-extras').data('language-calcular');
$('#maquetacion').prop('checked', false);
$('#maquetacion').data('price', calcularStr);
$('label[for="maquetacion"] .service-price').text(calcularStr);
});
function formateaMoneda(valor) {
try {
return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(valor);
} catch {
return valor;
}
}

View File

@ -138,4 +138,27 @@ export function updateFaja() {
$('#summary-faja-tamanio-solapa').text($('#tamanio-solapas-faja').val() + ' mm');
$('#summary-faja-acabado').text($('#faja-acabado option:selected').text());
}
}
export function updateExtras() {
const $table = $('#summary-servicios-extras');
const $tbody = $table.find('tbody');
$tbody.empty();
// Agregar las filas de servicios extras
$('.service-checkbox:checked').each(function() {
const $servicio = $(this);
const resumen = $(`label[for="${$servicio.attr('id')}"] .service-title`).text().trim() || $servicio.attr('id');
const price = $(`label[for="${$servicio.attr('id')}"] .service-price`).text().trim() || $servicio.attr('price');
const $row = $('<tr>').append(
$('<td>').append($('<span>').text(resumen)),
$('<td class="text-end">').text(price)
);
$tbody.append($row);
});
if ($tbody.children().length > 0) {
$table.removeClass('d-none');
} else {
$table.addClass('d-none');
}
}