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:
+142
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\ModelloResource\RelationManagers;
|
||||
|
||||
use App\Models\Finitura;
|
||||
use Filament\Forms;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Finiture del profilo del sistema e, per ciascuna, la scelta del modello: come il
|
||||
* sistema (nessuna riga in finiture_modelli) oppure lato proprio o disattivata.
|
||||
*/
|
||||
class FinitureRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'finitureDelSistema';
|
||||
|
||||
protected static ?string $title = 'Finiture';
|
||||
|
||||
protected static ?string $modelLabel = 'finitura';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'finiture';
|
||||
|
||||
/** Scelte del modello per finitura_id, lette una volta per richiesta. */
|
||||
protected ?\Illuminate\Support\Collection $scelte = null;
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->description('Per ogni finitura del profilo scegli se nel modello vale l\'impostazione del sistema (lato e attivazione in "Finiture e maniglie") o una propria: un lato diverso, oppure disattivata. La scelta del modello può anche attivare una finitura disattiva nel sistema.')
|
||||
->defaultSort('ordine')
|
||||
->defaultPaginationPageOption(50)
|
||||
->columns([
|
||||
Tables\Columns\ImageColumn::make('anteprima')->label('Anteprima')->disk('public')->height(36),
|
||||
Tables\Columns\TextColumn::make('descrizione')
|
||||
->label('Finitura')
|
||||
->description(fn (Finitura $record) => $record->codice)
|
||||
->searchable(['descrizione', 'codice']),
|
||||
Tables\Columns\TextColumn::make('sistema')
|
||||
->label('Nel sistema')
|
||||
->state(fn (Finitura $record) => $record->attivo ? Finitura::LATI[$record->lato] : 'Disattiva')
|
||||
->color('gray'),
|
||||
Tables\Columns\SelectColumn::make('scelta_modello')
|
||||
->label('In questo modello')
|
||||
->options(Finitura::LATI_MODELLO)
|
||||
->placeholder('Come il sistema')
|
||||
->getStateUsing(fn (Finitura $record) => $this->scelte()->get($record->id))
|
||||
->updateStateUsing(function (Finitura $record, ?string $state) {
|
||||
$this->salvaScelta([$record->id], $state);
|
||||
|
||||
return $state;
|
||||
}),
|
||||
Tables\Columns\TextColumn::make('effettiva')
|
||||
->label('Risultato')
|
||||
->state(function (Finitura $record) {
|
||||
$lato = $this->scelte()->get($record->id) ?? ($record->attivo ? $record->lato : 'nessuno');
|
||||
|
||||
return $lato === 'nessuno' ? 'Non disponibile' : Finitura::LATI[$lato];
|
||||
})
|
||||
->badge()
|
||||
->color(fn (string $state) => $state === 'Non disponibile' ? 'danger' : 'success'),
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\TernaryFilter::make('personalizzata')
|
||||
->label('Scelta del modello')
|
||||
->placeholder('Tutte')
|
||||
->trueLabel('Personalizzate')
|
||||
->falseLabel('Come il sistema')
|
||||
->queries(
|
||||
true: fn ($query) => $query->whereIn('id', $this->scelte()->keys()),
|
||||
false: fn ($query) => $query->whereNotIn('id', $this->scelte()->keys()),
|
||||
),
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\Action::make('ripristina')
|
||||
->label('Tutte come il sistema')
|
||||
->icon('heroicon-o-arrow-uturn-left')
|
||||
->color('gray')
|
||||
->requiresConfirmation()
|
||||
->modalDescription('Elimina le scelte del modello: per tutte le finiture torna a valere l\'impostazione del sistema.')
|
||||
->visible(fn () => $this->scelte()->isNotEmpty())
|
||||
->action(function () {
|
||||
DB::table('finiture_modelli')->where('modello_id', $this->getOwnerRecord()->getKey())->delete();
|
||||
$this->scelte = null;
|
||||
|
||||
Notification::make()->title('Finiture ripristinate come nel sistema')->success()->send();
|
||||
}),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkAction::make('imposta')
|
||||
->label('Imposta nel modello')
|
||||
->icon('heroicon-o-adjustments-horizontal')
|
||||
->form([
|
||||
Forms\Components\Select::make('lato')
|
||||
->label('In questo modello')
|
||||
->options(['sistema' => 'Come il sistema'] + Finitura::LATI_MODELLO)
|
||||
->required(),
|
||||
])
|
||||
->action(fn (Collection $records, array $data) => $this->salvaScelta(
|
||||
$records->modelKeys(),
|
||||
$data['lato'] === 'sistema' ? null : $data['lato'],
|
||||
))
|
||||
->deselectRecordsAfterCompletion(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function isReadOnly(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function scelte(): \Illuminate\Support\Collection
|
||||
{
|
||||
return $this->scelte ??= DB::table('finiture_modelli')
|
||||
->where('modello_id', $this->getOwnerRecord()->getKey())
|
||||
->pluck('lato', 'finitura_id');
|
||||
}
|
||||
|
||||
/** null = come il sistema (rimuove la scelta del modello). */
|
||||
private function salvaScelta(array $finiture, ?string $lato): void
|
||||
{
|
||||
$modello = $this->getOwnerRecord()->getKey();
|
||||
$righe = DB::table('finiture_modelli')->where('modello_id', $modello)->whereIn('finitura_id', $finiture);
|
||||
|
||||
if ($lato === null || $lato === '') {
|
||||
$righe->delete();
|
||||
} else {
|
||||
abort_unless(array_key_exists($lato, Finitura::LATI_MODELLO), 422);
|
||||
DB::table('finiture_modelli')->upsert(
|
||||
array_map(fn ($id) => ['modello_id' => $modello, 'finitura_id' => $id, 'lato' => $lato, 'created_at' => now(), 'updated_at' => now()], $finiture),
|
||||
['modello_id', 'finitura_id'],
|
||||
['lato', 'updated_at'],
|
||||
);
|
||||
}
|
||||
|
||||
$this->scelte = null;
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\ModelloResource\RelationManagers;
|
||||
|
||||
use App\Filament\Resources\OpzioneResource;
|
||||
use App\Models\GruppoOpzioni;
|
||||
use App\Models\Opzione;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Opzioni personalizzate del modello: se il modello ha almeno una riga in un gruppo,
|
||||
* per quel modello il gruppo del sistema è sostituito per intero.
|
||||
*/
|
||||
class OpzioniRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'opzioni';
|
||||
|
||||
protected static ?string $title = 'Opzioni personalizzate';
|
||||
|
||||
protected static ?string $modelLabel = 'opzione';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'opzioni';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form->schema(OpzioneResource::campi(conSistema: false, modello: fn () => $this->getOwnerRecord()));
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return OpzioneResource::tabella($table)
|
||||
->description('I gruppi presenti qui sostituiscono, per questo modello, quelli definiti in "Opzioni e supplementi" del sistema (es. icone di apertura proprie o un supplemento diverso). Eliminando tutte le righe di un gruppo torna a valere quello del sistema.')
|
||||
->headerActions([
|
||||
Tables\Actions\Action::make('personalizza')
|
||||
->label('Personalizza gruppo')
|
||||
->icon('heroicon-o-document-duplicate')
|
||||
->color('gray')
|
||||
->modalDescription('Copia nel modello le opzioni del gruppo definite sul sistema, da modificare qui.')
|
||||
->form([
|
||||
Forms\Components\Select::make('gruppo')
|
||||
->label('Gruppo')
|
||||
->options(fn () => $this->gruppiPersonalizzabili())
|
||||
->required(),
|
||||
])
|
||||
->action(function (array $data) {
|
||||
$copiate = $this->copiaGruppo($data['gruppo']);
|
||||
|
||||
Notification::make()->title("Copiate {$copiate} opzioni dal sistema")->success()->send();
|
||||
}),
|
||||
Tables\Actions\CreateAction::make()
|
||||
->mutateFormDataUsing(fn (array $data) => $this->conIconaDelSistema($data) + ['sistema_id' => $this->getOwnerRecord()->sistema_id]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function isReadOnly(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Gruppi del sistema non ancora personalizzati per il modello. */
|
||||
private function gruppiPersonalizzabili(): array
|
||||
{
|
||||
$modello = $this->getOwnerRecord();
|
||||
$personalizzati = $modello->opzioni()->distinct()->pluck('gruppo')->all();
|
||||
|
||||
return Opzione::query()
|
||||
->where('sistema_id', $modello->sistema_id)
|
||||
->whereNull('modello_id')
|
||||
->whereNotIn('gruppo', $personalizzati)
|
||||
->distinct()
|
||||
->pluck('gruppo')
|
||||
->mapWithKeys(fn (string $g) => [$g => GruppoOpzioni::where('codice', $g)->value('etichetta') ?? $g])
|
||||
->all();
|
||||
}
|
||||
|
||||
private function copiaGruppo(string $gruppo): int
|
||||
{
|
||||
$modello = $this->getOwnerRecord();
|
||||
|
||||
$righe = Opzione::query()
|
||||
->where('sistema_id', $modello->sistema_id)
|
||||
->whereNull('modello_id')
|
||||
->where('gruppo', $gruppo)
|
||||
->get();
|
||||
|
||||
DB::transaction(function () use ($righe, $modello) {
|
||||
foreach ($righe as $riga) {
|
||||
$copia = $riga->replicate(['icona']);
|
||||
$copia->modello_id = $modello->getKey();
|
||||
$copia->icona = $this->copiaIcona($riga);
|
||||
$copia->save();
|
||||
}
|
||||
});
|
||||
|
||||
return $righe->count();
|
||||
}
|
||||
|
||||
/** Nuova opzione con un valore del sistema e senza icona: prende una copia di quella del sistema. */
|
||||
private function conIconaDelSistema(array $data): array
|
||||
{
|
||||
if (blank($data['icona'] ?? null)) {
|
||||
$origine = OpzioneResource::catalogo($this->getOwnerRecord(), $data['gruppo'] ?? null)->firstWhere('valore', $data['valore'] ?? null);
|
||||
$data['icona'] = $origine ? $this->copiaIcona($origine) : null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** Icona duplicata: ogni record ha i suoi file (vedi HaImmaginiCatalogo). */
|
||||
private function copiaIcona(Opzione $origine): ?string
|
||||
{
|
||||
$disco = Storage::disk('public');
|
||||
if (! $origine->icona || ! $disco->exists($origine->icona)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$percorso = 'configuratore/opzioni/'.Str::random(20).'.'.pathinfo($origine->icona, PATHINFO_EXTENSION);
|
||||
$disco->copy($origine->icona, $percorso);
|
||||
|
||||
return $percorso;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user