feat: add previous configuration handling for user selections in quotes
- Implemented session storage management for the last configuration choices made by the user. - Added functionality to prompt users when changing models to retain their previous selections. - Introduced methods to apply previous choices to the newly loaded model, including finishes, handles, glass types, and options. - Enhanced user experience by ensuring selections are automatically applied where applicable.
This commit is contained in:
@@ -41,16 +41,21 @@ Entry point is `src/js/starter.js`, loaded from `src/index.html`. Flow on load (
|
||||
*Note: that doc describes a more modular refactor (`Application.js`, `communication/UrlParamsParser.js`,
|
||||
`communication/IframeBridge.js`) that does not exist yet in `src/js` — the current implementation is the
|
||||
flatter `starter.js`/`params_parser.js` described here.*
|
||||
2. Product/catalog data is fetched as JSON from `src/assets/data/sistemi/<sistema>/modelli.json` and
|
||||
`src/assets/data/modelli/<sistema>/<cartella>/{form,modello,maniglia,avvolgibile,vetro,listino}.json`
|
||||
(which JSON files are fetched depends on the `moduli` array in the matched `modelli.json` entry).
|
||||
2. Catalog data comes from the Laravel backoffice (`backoffice/`, API base in `src/js/api_base.js`):
|
||||
`GET /api/sistemi` (systems + active models that have a price list; models without one are hidden and flagged in the admin list) and
|
||||
`GET /api/sistemi/<sistema>/modelli/<modello>/configurazione`, which returns the menu wiring (`form`: radios,
|
||||
selects, finish menus — the old `form.json` shape), finishes, handles, glass types and the price-grid sizes,
|
||||
with image URLs served by `GET /api/media/...` (CORS-enabled, needed for WebGL textures). Only
|
||||
`avvolgibile.json` and `sistemi/<sistema>/altezza_maniglia_<categoria>.json` are still read from `src/assets/data`.
|
||||
3. **`MenuBuilder.build()`** (`src/js/menu_builder.js`) injects an HTML template (`assets/_menu.html`, or
|
||||
`assets/_menu-cassonetto.html` when `type=cassonetto`) into `#left-container`, builds the model-picker
|
||||
list, handles the mobile-portrait/landscape layout reflow, and initializes `PriceCalculator`. It returns
|
||||
the price calculator instance used by the rest of the app.
|
||||
4. **`Configurator.init()` / `.enable()`** (`src/js/configurator.js`) wires a single delegated `input` handler
|
||||
on the size fields, selects and radios. On every change it recomputes price via `PriceCalculator`, builds
|
||||
`window.configurazione` (the object that gets posted to the parent on "add to cart"), and updates the DOM.
|
||||
on the size fields, selects and radios. On every change (debounced) it sends the selected codes to
|
||||
`POST /api/sistemi/<sistema>/modelli/<modello>/prezzo`, stores the result in `window.configurazione` and
|
||||
updates the DOM. "Add to cart" sends the same codes (`scelte`): the backend recomputes the price and ignores
|
||||
any price coming from the client.
|
||||
5. **`APP.Player`** (`src/js/app.js`) wraps a Three.js renderer/scene/camera (scene graph loaded from
|
||||
`src/assets/app.json`, a three.js-editor-style export) plus the actual product GLB
|
||||
(`src/assets/models/<sistema>/<modello.modello>`). Two players are created: `player` (visible canvas) and
|
||||
@@ -59,22 +64,30 @@ Entry point is `src/js/starter.js`, loaded from `src/index.html`. Flow on load (
|
||||
per `userData.categoria` mesh tag — categories like `interno`, `esterno`, `maniglia`, `vetro`, `cerniere`),
|
||||
`flipView` (180° GSAP-animated turn between front/back view), `addMarker` (in-scene hotspot with a video
|
||||
popup).
|
||||
6. **`PriceCalculator`** (`src/js/price_calculator.js`) is a stateless-ish module (single module-level
|
||||
`listini` cache set via `init`) that looks up a base price from a width/height grid in **mm** (served by
|
||||
the backoffice API, using the first grid size ≥ the requested one) and layers on percentage/flat supplements for finish, glass, hinges, handle
|
||||
height, and actuator type, then adds 22% VAT.
|
||||
6. **Pricing is server-side only**: `backoffice/app/Support/Configuratore/CalcolatorePrezzo.php`.
|
||||
`prezzo = base × (1 + supplementi % / 100) + supplementi fissi + variazione vetro` (VAT excluded). Base is
|
||||
the first grid size ≥ the requested one (mm). Supplements come from `opzioni` rows (finish type
|
||||
bianco/uniforme/bicolore, hinges, profili extra, ...): percentage, fixed, or per linear metre
|
||||
(ml from L/H multipliers + extra mm). Groups with `ui = multipla` (profili extra) accept several codes,
|
||||
with same-`alternativa` options mutually exclusive. Sistema-level rows can be overridden per model by group.
|
||||
Option groups themselves live in `gruppi_opzioni` (title, control radio/select/multipla, menu section, and
|
||||
the model `moduli` key that enables them): a group without fixed markup in `_menu.html` is rendered by
|
||||
`MenuBuilder` into `.opzioni-sistema` / `.opzioni-accessori`. Select options can call a `window[func]`
|
||||
(e.g. `nascondiCategoria` with `categoria: maniglia` for the motor) via their `parametri`. The glass
|
||||
variation is Σ max(pane area, minimo_mq) × maggiorazione_mq, with panes from the model's `regole_vetro`
|
||||
(spec: "Specifica tecnica vetri"). All of it is edited in Filament under "Configuratore".
|
||||
`src/js/price_calculator.js` only wraps the API call and the grid sizes.
|
||||
|
||||
### Data conventions
|
||||
|
||||
- Every 3D-visible part is tagged with `userData.categoria` in the GLB/scene so JS can show/hide/retexture it
|
||||
without knowing mesh names (`interno`, `esterno`, `maniglia`, `cerniere`, `vetro`, ...).
|
||||
- Each model folder under `src/assets/data/modelli/<sistema>/<cartella>/` follows the same file set:
|
||||
`form.json` (UI radios/selects/finiture wiring — declares which named `<select>`/radio groups exist and
|
||||
which categories/texture folders they map to), `modello.json` (finish options), `maniglia.json` (handle
|
||||
options), `avvolgibile.json` (shutter, cassonetto-only), `vetro.json` (glass options), `listino.json`
|
||||
(price grid).
|
||||
- Texture images live under `src/assets/data/immagini/<sistema>/<folder>/<texture_folder>/<id>/...` and are
|
||||
loaded lazily per selection (`APP.Player.changeTexture`); a monotonically-checked `isStale()` guard discards
|
||||
- Which menu sections a model shows (and which items enter the price) is driven by its `moduli` in the
|
||||
backoffice (`Modello::MODULI`, e.g. `finitura_esterna`, `apertura`, `telaio`, `vetro`). The per-model JSON
|
||||
files under `src/assets/data/modelli/` are legacy and no longer read (except `avvolgibile.json`).
|
||||
- Texture and icon images live in the backoffice (`storage/app/public/configuratore/...`, seeded once by
|
||||
`ConfiguratoreSeeder` from `backoffice/database/seeders/data/configuratore/`) and are loaded lazily per
|
||||
selection (`APP.Player.changeTexture`) from absolute URLs; a monotonically-checked `isStale()` guard discards
|
||||
a texture load if the user changed the selection again before it finished.
|
||||
- `window.*` globals (`window.configurazione`, `window.cambiaTexture`, `window.caricaModello`,
|
||||
`window.rotate`, `window.sistema`, etc.) are the integration surface between the jQuery-driven menu markup
|
||||
|
||||
Reference in New Issue
Block a user