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:
2026-10-19 19:49:44 +02:00
parent 863e6ca920
commit 06617a985a
197 changed files with 4892 additions and 400 deletions
@@ -0,0 +1,120 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Catalogo del configuratore per sistema (finiture, vetri, regole vetro, opzioni con
* supplementi): sostituisce i JSON e le immagini sotto src/assets/data.
*/
return new class extends Migration
{
public function up(): void
{
// Finiture del profilo e colori maniglia/cerniere: stesse proprietà 3D.
Schema::create('finiture', function (Blueprint $table) {
$table->id();
$table->foreignId('sistema_id')->constrained('sistemi')->cascadeOnDelete();
$table->string('tipo', 20); // profilo | maniglia
// Valore inviato dal configuratore (es. "2", "M1").
$table->string('codice', 50);
$table->string('descrizione');
$table->string('codice_mazzetta', 50)->nullable();
$table->string('colore', 20)->nullable();
$table->string('colore_corpo_base', 20)->nullable();
$table->decimal('roughness', 4, 2)->nullable();
$table->decimal('metalness', 4, 2)->nullable();
$table->string('anteprima')->nullable();
$table->string('texture')->nullable();
$table->string('texture_bump')->nullable();
$table->decimal('bump_scala', 6, 2)->nullable();
$table->boolean('predefinita')->default(false);
$table->unsignedInteger('ordine')->default(0);
$table->boolean('attivo')->default(true);
$table->timestamps();
$table->unique(['sistema_id', 'tipo', 'codice']);
});
// Riempimenti (vetri e pannelli): prezzo a m² sulle lastre calcolate dalla regola del modello.
Schema::create('vetri', function (Blueprint $table) {
$table->id();
$table->foreignId('sistema_id')->constrained('sistemi')->cascadeOnDelete();
$table->string('codice', 50);
$table->string('descrizione');
$table->decimal('maggiorazione_mq', 10, 2)->default(0);
$table->decimal('minimo_mq', 8, 3)->default(0);
$table->string('colore', 20)->nullable();
$table->decimal('roughness', 4, 2)->nullable();
$table->decimal('metalness', 4, 2)->nullable();
$table->decimal('opacita', 4, 2)->nullable();
$table->string('anteprima')->nullable();
$table->string('popup')->nullable();
$table->string('texture')->nullable();
$table->string('texture_bump')->nullable();
$table->decimal('bump_scala', 6, 2)->nullable();
$table->boolean('predefinito')->default(false);
$table->unsignedInteger('ordine')->default(0);
$table->boolean('attivo')->default(true);
$table->timestamps();
$table->unique(['sistema_id', 'codice']);
});
// Geometria delle lastre per tipologia (es. F2: 2 lastre (L - 312) / 2 x (H - 189)).
Schema::create('regole_vetro', function (Blueprint $table) {
$table->id();
$table->foreignId('sistema_id')->constrained('sistemi')->cascadeOnDelete();
$table->string('codice', 50);
$table->string('descrizione');
// [{descrizione, quantita, divisore, detrazione_larghezza, detrazione_altezza}]
$table->json('lastre');
$table->text('note')->nullable();
$table->timestamps();
$table->unique(['sistema_id', 'codice']);
});
// Opzioni del configuratore (radio/select) e supplementi di prezzo. Con modello_id
// valorizzato sostituiscono, per quel modello, l'intero gruppo definito sul sistema.
Schema::create('opzioni', function (Blueprint $table) {
$table->id();
$table->foreignId('sistema_id')->constrained('sistemi')->cascadeOnDelete();
$table->foreignId('modello_id')->nullable()->constrained('modelli')->cascadeOnDelete();
$table->string('gruppo', 50);
$table->string('valore', 100);
$table->string('etichetta');
$table->string('icona')->nullable();
$table->string('supplemento_tipo', 20)->nullable(); // percentuale | fisso
$table->decimal('supplemento', 10, 2)->default(0);
$table->json('parametri')->nullable();
$table->unsignedInteger('ordine')->default(0);
$table->boolean('attivo')->default(true);
$table->timestamps();
$table->index(['sistema_id', 'gruppo']);
$table->index(['modello_id', 'gruppo']);
});
Schema::table('modelli', function (Blueprint $table) {
// Titolo esteso mostrato nel configuratore e nel preventivo.
$table->string('titolo')->nullable()->after('descrizione');
$table->foreignId('regola_vetro_id')->nullable()->after('moduli')
->constrained('regole_vetro')->nullOnDelete();
});
}
public function down(): void
{
Schema::table('modelli', function (Blueprint $table) {
$table->dropConstrainedForeignId('regola_vetro_id');
$table->dropColumn('titolo');
});
Schema::dropIfExists('opzioni');
Schema::dropIfExists('regole_vetro');
Schema::dropIfExists('vetri');
Schema::dropIfExists('finiture');
}
};
@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Lato delle finiture del profilo (interno, esterno o entrambi) sul sistema, con
* personalizzazione per modello: una riga in finiture_modelli sostituisce, per quel
* modello, attivazione e lato del sistema.
*/
return new class extends Migration
{
public function up(): void
{
Schema::table('finiture', function (Blueprint $table) {
$table->string('lato', 20)->default('entrambi')->after('tipo'); // entrambi | interno | esterno
});
Schema::create('finiture_modelli', function (Blueprint $table) {
$table->id();
$table->foreignId('modello_id')->constrained('modelli')->cascadeOnDelete();
$table->foreignId('finitura_id')->constrained('finiture')->cascadeOnDelete();
$table->string('lato', 20); // entrambi | interno | esterno | nessuno
$table->timestamps();
$table->unique(['modello_id', 'finitura_id']);
});
}
public function down(): void
{
Schema::dropIfExists('finiture_modelli');
Schema::table('finiture', function (Blueprint $table) {
$table->dropColumn('lato');
});
}
};
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Supplementi al metro lineare (es. profili extra): metri = (L x ml_per_larghezza +
* H x ml_per_altezza + ml_aggiunta_mm) / 1000. Le opzioni con la stessa `alternativa`
* si escludono a vicenda nei gruppi a scelta multipla.
*/
return new class extends Migration
{
public function up(): void
{
Schema::table('opzioni', function (Blueprint $table) {
$table->string('alternativa', 50)->nullable()->after('icona');
$table->decimal('ml_per_larghezza', 8, 3)->default(0)->after('supplemento');
$table->decimal('ml_per_altezza', 8, 3)->default(0)->after('ml_per_larghezza');
$table->decimal('ml_aggiunta_mm', 10, 2)->default(0)->after('ml_per_altezza');
});
}
public function down(): void
{
Schema::table('opzioni', function (Blueprint $table) {
$table->dropColumn(['alternativa', 'ml_per_larghezza', 'ml_per_altezza', 'ml_aggiunta_mm']);
});
}
};
@@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
/**
* Gruppi di opzioni del configuratore gestiti dal backoffice (prima erano fissi nel codice):
* controllo del menu, sezione in cui compare e modulo del modello che lo rende visibile.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('gruppi_opzioni', function (Blueprint $table) {
$table->id();
// Chiave usata da opzioni.gruppo e dal configuratore.
$table->string('codice', 50)->unique();
$table->string('etichetta');
$table->string('ui', 20); // nessuna | radio | select | multipla
$table->string('sezione', 20)->default('accessori'); // sistema | accessori
// Modulo del modello che rende visibile il gruppo (Modello::moduli).
$table->string('modulo', 50);
$table->unsignedInteger('ordine')->default(0);
$table->timestamps();
});
$adesso = now();
DB::table('gruppi_opzioni')->insert(array_map(fn (array $g) => $g + ['created_at' => $adesso, 'updated_at' => $adesso], [
['codice' => 'tipo_finitura', 'etichetta' => 'Tipo finitura', 'ui' => 'nessuna', 'sezione' => 'sistema', 'modulo' => 'modello', 'ordine' => 1],
['codice' => 'telaio', 'etichetta' => 'Seleziona il telaio del serramento', 'ui' => 'radio', 'sezione' => 'sistema', 'modulo' => 'telaio', 'ordine' => 2],
['codice' => 'apertura', 'etichetta' => 'Seleziona il verso di apertura del serramento', 'ui' => 'radio', 'sezione' => 'sistema', 'modulo' => 'apertura', 'ordine' => 3],
['codice' => 'profili_extra', 'etichetta' => 'Profili extra', 'ui' => 'multipla', 'sezione' => 'sistema', 'modulo' => 'profili_extra', 'ordine' => 4],
['codice' => 'cerniere_a_scomparsa', 'etichetta' => 'Cerniere a scomparsa', 'ui' => 'select', 'sezione' => 'accessori', 'modulo' => 'cerniere', 'ordine' => 5],
['codice' => 'soglia_ribassata', 'etichetta' => 'Soglia ribassata', 'ui' => 'select', 'sezione' => 'accessori', 'modulo' => 'soglia_ribassata', 'ordine' => 6],
['codice' => 'motore', 'etichetta' => 'Motore', 'ui' => 'select', 'sezione' => 'accessori', 'modulo' => 'motore', 'ordine' => 7],
['codice' => 'azionamento', 'etichetta' => 'Azionamento', 'ui' => 'select', 'sezione' => 'accessori', 'modulo' => 'azionamento', 'ordine' => 8],
]));
}
public function down(): void
{
Schema::dropIfExists('gruppi_opzioni');
}
};