backoffice first commit

This commit is contained in:
2026-07-17 11:34:15 +02:00
parent 761db06329
commit 1c40ef6601
159 changed files with 25830 additions and 7875 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+34
View File
@@ -215,6 +215,32 @@ body {
width: 50px;
}
#vai-al-preventivo {
z-index: 98;
position: absolute;
bottom: 100px;
left: 50%;
transform: translateX(-50%);
display: block;
max-width: 90%;
background-color: #24a5cc;
color: #fff;
font-weight: bold;
font-size: 14px;
text-align: center;
text-decoration: none;
white-space: nowrap;
padding: 10px 20px;
border-radius: 24px;
box-shadow: 0 4px 14px rgba(0, 0, 0, .25);
transition: background-color 0.3s;
}
#vai-al-preventivo:hover {
background-color: #1c86a6;
color: #fff;
}
.main-menu hr {
border: 0;
height: 1px;
@@ -561,6 +587,14 @@ body {
bottom: 30px;
}
#vai-al-preventivo {
bottom: 88px;
max-width: 96%;
font-size: 13px;
padding: 9px 16px;
white-space: normal;
}
#left-container {
overflow: auto;
overflow-x: hidden;
+1
View File
@@ -175,6 +175,7 @@
</div>
<div id="markerContainer"></div>
<div class="titolo"></div>
<a id="vai-al-preventivo" class="d-none" href="#"></a>
<div id="cart-container" class="cart-container">
<div class="prezzo"></div>
<div class="quantity-control">
+101 -10
View File
@@ -19,24 +19,115 @@ window.THREE = THREE; // Used by APP Scripts.
window.OrbitControls = OrbitControls; // Used by APP Scripts.
window.GLTFLoader = GLTFLoader; // Used by APP Scripts.
// --- Integrazione backend preventivi ---
// Base URL dell'API Laravel: impostata in build (import.meta.env.VITE_PREVENTIVI_API_BASE, da
// .env/.env.production — vedi root del repo), sovrascrivibile a runtime con window.PREVENTIVI_API_BASE
// senza dover rebuildare (es. per un hotfix). Nessuna delle due impostata → fallback dev locale.
const PREVENTIVI_API_BASE =
(typeof window.PREVENTIVI_API_BASE === 'string' && window.PREVENTIVI_API_BASE) ||
import.meta.env.VITE_PREVENTIVI_API_BASE ||
'http://localhost:8000/api';
const CART_TOKEN_KEY = 'kreios_cart_token';
// URL dell'app cliente (checkout): richiesto all'API invece di essere indovinato, perché la
// porta Vite dell'app cliente può cambiare (es. se 5199 è già occupata). Fallback locale se
// il backend non è raggiungibile.
let appClienteUrl =
(typeof window.APP_CLIENTE_URL === 'string' && window.APP_CLIENTE_URL) ||
'http://localhost:5199';
const configReady = (async () => {
try {
const res = await fetch(`${PREVENTIVI_API_BASE}/config`, {
headers: { Accept: 'application/json' },
});
if (!res.ok) return;
const data = await res.json();
if (data.frontend_cliente_url) appClienteUrl = data.frontend_cliente_url;
} catch (e) {
// Backend non raggiungibile: resta il fallback locale.
}
})();
let invioPreventivoInCorso = false;
// Mostra/aggiorna il link "Vai al preventivo" (markup fisso in index.html, sopra la cart-container).
window.mostraLinkPreventivo = (token, count) => {
const link = document.getElementById('vai-al-preventivo');
if (!link) return;
// L'app cliente non conosce a priori l'URL del configuratore (può girare su domini/porte
// diverse in dev/prod): lo passiamo qui come parametro, così il link "torna al configuratore"
// nella pagina di conferma può essere generato dinamicamente invece di essere hardcoded.
const ritorno = encodeURIComponent(window.location.href);
link.href = `${appClienteUrl}/?token=${encodeURIComponent(token)}&ritorno=${ritorno}`;
link.textContent = count > 0 ? `Vai al preventivo (${count})` : 'Vai al preventivo';
link.classList.remove('d-none');
};
// Ripristina il link se esiste già un preventivo in corso da una sessione precedente.
const ripristinaLinkPreventivo = async () => {
const token = localStorage.getItem(CART_TOKEN_KEY);
if (!token) return;
try {
await configReady;
const res = await fetch(`${PREVENTIVI_API_BASE}/carrello/${encodeURIComponent(token)}`, {
headers: { Accept: 'application/json' },
});
if (!res.ok) return;
const data = await res.json();
if (data.carrello?.items?.length) {
window.mostraLinkPreventivo(token, data.carrello.items.length);
}
} catch (e) {
// Backend non raggiungibile: non blocca il configuratore.
}
};
ripristinaLinkPreventivo();
$(() => {
$('.cart-button').on('click', async () => {
if($('.cart-button').hasClass('disabled'))
if ($('.cart-button').hasClass('disabled') || invioPreventivoInCorso)
return;
const img = await window.generaImagine();
const data = {
payload: window.configurazione,
img: img,
qty: parseInt($('.quantity-input').val()),
fn: 'aggiungi_prodotto'
};
invioPreventivoInCorso = true;
try {
const params = ParamsParser.getQueryParams();
const img = await window.generaImagine();
const conf = window.configurazione || {};
const inner = conf.configurazione || {};
window.parent.postMessage(data, "https://www.infissionline.it");
window.parent.postMessage(data, "https://infissionline.test");
const body = {
token: localStorage.getItem(CART_TOKEN_KEY) || undefined,
sistema: params.sistema,
type: params.type,
nome: inner.nome,
larghezza: parseInt(inner.width) || null,
altezza: parseInt(inner.height) || null,
qty: parseInt($('.quantity-input').val()) || 1,
prezzo: conf.prezzo,
payload: inner,
img: img,
};
await configReady;
const res = await fetch(`${PREVENTIVI_API_BASE}/carrello/aggiungi`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error('Errore nel salvataggio del preventivo');
const data = await res.json();
localStorage.setItem(CART_TOKEN_KEY, data.token);
window.mostraLinkPreventivo(data.token, data.carrello.items.length);
} catch (e) {
console.error(e);
alert('Si è verificato un errore nell\'aggiunta al preventivo. Riprova.');
} finally {
invioPreventivoInCorso = false;
}
});
});