++ Primo Caricamento
This commit is contained in:
189
resources/views/customers/_form.blade.php
Normal file
189
resources/views/customers/_form.blade.php
Normal file
@@ -0,0 +1,189 @@
|
||||
{{--
|
||||
resources/views/customers/_form.blade.php — Partial del form cliente
|
||||
|
||||
Il prefisso underscore (_form) è una convenzione per indicare "partial view":
|
||||
frammenti di HTML riutilizzati in più pagine tramite @include().
|
||||
|
||||
Questa tecnica evita di duplicare il form identico in create.blade.php e edit.blade.php.
|
||||
|
||||
La variabile $customer viene passata da edit.blade.php. In create.blade.php
|
||||
non esiste, quindi usiamo old() come fallback per ripopolare dopo errore.
|
||||
--}}
|
||||
|
||||
{{-- ─── Sezione 1: Informazioni principali ──────────────────────────────────── --}}
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-12">
|
||||
<h6 class="text-muted fw-semibold text-uppercase small letter-spacing-1 mb-3">
|
||||
<i class="bi bi-person me-1"></i>Informazioni principali
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">
|
||||
Nome / Ragione Sociale <span class="text-danger">*</span>
|
||||
</label>
|
||||
{{--
|
||||
is-invalid: classe Bootstrap che mostra il bordo rosso se c'è un errore.
|
||||
$errors->has('name'): controlla se il campo ha errori di validazione.
|
||||
old('name', $customer->name ?? ''): usa il valore OLD se c'è (dopo errore),
|
||||
altrimenti il valore del Model (modifica), altrimenti stringa vuota (crea).
|
||||
--}}
|
||||
<input type="text" name="name"
|
||||
class="form-control {{ $errors->has('name') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('name', $customer->name ?? '') }}"
|
||||
placeholder="Es. Mario Rossi / Rossi S.r.l."
|
||||
required>
|
||||
{{-- Messaggio di errore specifico del campo --}}
|
||||
@error('name')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">
|
||||
Email <span class="text-danger">*</span>
|
||||
</label>
|
||||
<input type="email" name="email"
|
||||
class="form-control {{ $errors->has('email') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('email', $customer->email ?? '') }}"
|
||||
placeholder="mario@esempio.it"
|
||||
required>
|
||||
@error('email')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">Telefono</label>
|
||||
<input type="tel" name="phone"
|
||||
class="form-control {{ $errors->has('phone') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('phone', $customer->phone ?? '') }}"
|
||||
placeholder="+39 02 1234567">
|
||||
@error('phone')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">
|
||||
Tipo <span class="text-danger">*</span>
|
||||
</label>
|
||||
<select name="type" class="form-select {{ $errors->has('type') ? 'is-invalid' : '' }}" required>
|
||||
<option value="">— Seleziona —</option>
|
||||
<option value="privato" {{ old('type', $customer->type ?? '') === 'privato' ? 'selected' : '' }}>
|
||||
Privato
|
||||
</option>
|
||||
<option value="azienda" {{ old('type', $customer->type ?? '') === 'azienda' ? 'selected' : '' }}>
|
||||
Azienda
|
||||
</option>
|
||||
</select>
|
||||
@error('type')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">
|
||||
Stato <span class="text-danger">*</span>
|
||||
</label>
|
||||
<select name="status" class="form-select {{ $errors->has('status') ? 'is-invalid' : '' }}" required>
|
||||
<option value="">— Seleziona —</option>
|
||||
<option value="prospect" {{ old('status', $customer->status ?? 'prospect') === 'prospect' ? 'selected' : '' }}>
|
||||
Prospect
|
||||
</option>
|
||||
<option value="attivo" {{ old('status', $customer->status ?? '') === 'attivo' ? 'selected' : '' }}>
|
||||
Attivo
|
||||
</option>
|
||||
<option value="inattivo" {{ old('status', $customer->status ?? '') === 'inattivo' ? 'selected' : '' }}>
|
||||
Inattivo
|
||||
</option>
|
||||
</select>
|
||||
@error('status')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ─── Sezione 2: Sede e dati fiscali ──────────────────────────────────────── --}}
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-12">
|
||||
<h6 class="text-muted fw-semibold text-uppercase small mb-3">
|
||||
<i class="bi bi-building me-1"></i>Sede e dati fiscali
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">Città</label>
|
||||
<input type="text" name="city"
|
||||
class="form-control {{ $errors->has('city') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('city', $customer->city ?? '') }}"
|
||||
placeholder="Milano">
|
||||
@error('city')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<label class="form-label fw-medium">Indirizzo</label>
|
||||
<input type="text" name="address"
|
||||
class="form-control {{ $errors->has('address') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('address', $customer->address ?? '') }}"
|
||||
placeholder="Via Roma, 1 - 20100 Milano MI">
|
||||
@error('address')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">Partita IVA</label>
|
||||
<input type="text" name="vat_number"
|
||||
class="form-control {{ $errors->has('vat_number') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('vat_number', $customer->vat_number ?? '') }}"
|
||||
placeholder="IT12345678901">
|
||||
@error('vat_number')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">Codice Fiscale</label>
|
||||
<input type="text" name="fiscal_code"
|
||||
class="form-control {{ $errors->has('fiscal_code') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('fiscal_code', $customer->fiscal_code ?? '') }}"
|
||||
placeholder="RSSMRA80A01H501Z">
|
||||
@error('fiscal_code')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">Valore Contratto ({{ $appSettings['currency_symbol'] }})</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">{{ $appSettings['currency_symbol'] }}</span>
|
||||
<input type="number" name="contract_value" step="0.01" min="0"
|
||||
class="form-control {{ $errors->has('contract_value') ? 'is-invalid' : '' }}"
|
||||
value="{{ old('contract_value', $customer->contract_value ?? '0') }}"
|
||||
placeholder="0.00">
|
||||
</div>
|
||||
@error('contract_value')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ─── Sezione 3: Note ─────────────────────────────────────────────────────── --}}
|
||||
@if($appSettings['allow_notes'] ?? true)
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<h6 class="text-muted fw-semibold text-uppercase small mb-3">
|
||||
<i class="bi bi-sticky me-1"></i>Note
|
||||
</h6>
|
||||
<textarea name="notes" rows="4"
|
||||
class="form-control {{ $errors->has('notes') ? 'is-invalid' : '' }}"
|
||||
placeholder="Note interne, informazioni aggiuntive...">{{ old('notes', $customer->notes ?? '') }}</textarea>
|
||||
@error('notes')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
49
resources/views/customers/create.blade.php
Normal file
49
resources/views/customers/create.blade.php
Normal file
@@ -0,0 +1,49 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Nuovo Cliente')
|
||||
@section('page-title', 'Nuovo Cliente')
|
||||
|
||||
@section('page-actions')
|
||||
<a href="{{ route('customers.index') }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Torna alla lista
|
||||
</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white border-0 pt-4 pb-0 px-4">
|
||||
<h5 class="fw-semibold">
|
||||
<i class="bi bi-person-plus me-2 text-primary"></i>Dati cliente
|
||||
</h5>
|
||||
<p class="text-muted small">I campi contrassegnati con * sono obbligatori.</p>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-4">
|
||||
{{--
|
||||
@csrf: genera un token nascosto per proteggere da attacchi CSRF
|
||||
(Cross-Site Request Forgery). Laravel lo verifica automaticamente.
|
||||
OBBLIGATORIO in tutti i form POST/PUT/DELETE!
|
||||
--}}
|
||||
<form method="POST" action="{{ route('customers.store') }}">
|
||||
@csrf
|
||||
|
||||
@include('customers._form')
|
||||
|
||||
<div class="d-flex justify-content-end gap-2 mt-4 pt-3 border-top">
|
||||
<a href="{{ route('customers.index') }}" class="btn btn-outline-secondary">
|
||||
Annulla
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg me-1"></i>Salva Cliente
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
49
resources/views/customers/edit.blade.php
Normal file
49
resources/views/customers/edit.blade.php
Normal file
@@ -0,0 +1,49 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Modifica ' . $customer->name)
|
||||
@section('page-title', 'Modifica Cliente')
|
||||
|
||||
@section('page-actions')
|
||||
<a href="{{ route('customers.show', $customer) }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Torna al dettaglio
|
||||
</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white border-0 pt-4 pb-0 px-4">
|
||||
<h5 class="fw-semibold">
|
||||
<i class="bi bi-pencil me-2 text-warning"></i>{{ $customer->name }}
|
||||
</h5>
|
||||
<p class="text-muted small">I campi contrassegnati con * sono obbligatori.</p>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-4">
|
||||
{{--
|
||||
@method('PUT'): poiché i browser inviano solo GET/POST,
|
||||
Laravel "finge" il metodo PUT tramite un campo nascosto _method.
|
||||
--}}
|
||||
<form method="POST" action="{{ route('customers.update', $customer) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
@include('customers._form', ['customer' => $customer])
|
||||
|
||||
<div class="d-flex justify-content-end gap-2 mt-4 pt-3 border-top">
|
||||
<a href="{{ route('customers.show', $customer) }}" class="btn btn-outline-secondary">
|
||||
Annulla
|
||||
</a>
|
||||
<button type="submit" class="btn btn-warning">
|
||||
<i class="bi bi-check-lg me-1"></i>Salva Modifiche
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
158
resources/views/customers/index.blade.php
Normal file
158
resources/views/customers/index.blade.php
Normal file
@@ -0,0 +1,158 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Clienti')
|
||||
@section('page-title', 'Gestione Clienti')
|
||||
|
||||
@section('page-actions')
|
||||
<a href="{{ route('customers.create') }}" class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-1"></i>Nuovo Cliente
|
||||
</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ═══ Barra filtri ════════════════════════════════════════════════════ --}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body py-3">
|
||||
{{-- method="GET": i filtri vengono messi nell'URL (?search=...&type=...) --}}
|
||||
<form method="GET" action="{{ route('customers.index') }}" class="row g-2 align-items-end">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-semibold text-muted">Cerca</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
||||
<input type="text" name="search"
|
||||
class="form-control"
|
||||
placeholder="Nome, email, città, P.IVA..."
|
||||
{{-- old(): ripopola il campo con il valore precedente dopo ricarica pagina --}}
|
||||
value="{{ request('search') }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-semibold text-muted">Tipo</label>
|
||||
<select name="type" class="form-select">
|
||||
<option value="">Tutti</option>
|
||||
<option value="privato" {{ request('type') === 'privato' ? 'selected' : '' }}>Privato</option>
|
||||
<option value="azienda" {{ request('type') === 'azienda' ? 'selected' : '' }}>Azienda</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-semibold text-muted">Stato</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="">Tutti</option>
|
||||
<option value="attivo" {{ request('status') === 'attivo' ? 'selected' : '' }}>Attivo</option>
|
||||
<option value="prospect" {{ request('status') === 'prospect' ? 'selected' : '' }}>Prospect</option>
|
||||
<option value="inattivo" {{ request('status') === 'inattivo' ? 'selected' : '' }}>Inattivo</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-funnel me-1"></i>Filtra
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<a href="{{ route('customers.index') }}" class="btn btn-outline-secondary w-100">
|
||||
<i class="bi bi-x me-1"></i>Reset
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ═══ Tabella clienti ════════════════════════════════════════════════ --}}
|
||||
<div class="card">
|
||||
<div class="card-header bg-white border-0 pt-3">
|
||||
<span class="text-muted small">
|
||||
{{ $customers->total() }} {{ Str::plural('cliente', $customers->total()) }} trovati
|
||||
</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-4">Cliente</th>
|
||||
<th>Contatto</th>
|
||||
<th>Città</th>
|
||||
<th>Tipo</th>
|
||||
<th>Stato</th>
|
||||
<th>Contratto</th>
|
||||
<th class="text-end pe-4">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($customers as $customer)
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<div class="fw-semibold">{{ $customer->name }}</div>
|
||||
@if ($customer->vat_number)
|
||||
<div class="text-muted small">P.IVA: {{ $customer->vat_number }}</div>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ $customer->email }}</div>
|
||||
@if ($customer->phone)
|
||||
<div class="text-muted small">{{ $customer->phone }}</div>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-muted">{{ $customer->city ?? '—' }}</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark border">{{ $customer->type_label }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-{{ $customer->badge_color }}">
|
||||
{{ ucfirst($customer->status) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="fw-semibold">
|
||||
{{ $appSettings['currency_symbol'] }}{{ number_format($customer->contract_value, 0, ',', '.') }}
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="{{ route('customers.show', $customer) }}"
|
||||
class="btn btn-outline-primary" title="Dettaglio">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="{{ route('customers.edit', $customer) }}"
|
||||
class="btn btn-outline-secondary" title="Modifica">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
{{-- Form DELETE: i browser non supportano DELETE nativo,
|
||||
Laravel usa il campo _method come workaround --}}
|
||||
<form method="POST" action="{{ route('customers.destroy', $customer) }}"
|
||||
onsubmit="return confirm('Eliminare {{ addslashes($customer->name) }}?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-outline-danger" title="Elimina">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted py-5">
|
||||
<i class="bi bi-people display-6 d-block mb-2 opacity-25"></i>
|
||||
Nessun cliente trovato.<br>
|
||||
<a href="{{ route('customers.create') }}" class="btn btn-primary mt-3">
|
||||
<i class="bi bi-person-plus me-1"></i>Aggiungi il primo cliente
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{-- Paginazione: generata automaticamente da Laravel --}}
|
||||
@if ($customers->hasPages())
|
||||
<div class="card-footer bg-white d-flex justify-content-between align-items-center">
|
||||
<div class="text-muted small">
|
||||
Pagina {{ $customers->currentPage() }} di {{ $customers->lastPage() }}
|
||||
</div>
|
||||
{{-- links() genera i bottoni prev/next con Bootstrap styling --}}
|
||||
{{ $customers->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
153
resources/views/customers/show.blade.php
Normal file
153
resources/views/customers/show.blade.php
Normal file
@@ -0,0 +1,153 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', $customer->name)
|
||||
@section('page-title', $customer->name)
|
||||
|
||||
@section('page-actions')
|
||||
<div class="btn-group">
|
||||
<a href="{{ route('customers.index') }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Lista
|
||||
</a>
|
||||
<a href="{{ route('customers.edit', $customer) }}" class="btn btn-warning">
|
||||
<i class="bi bi-pencil me-1"></i>Modifica
|
||||
</a>
|
||||
<form method="POST" action="{{ route('customers.destroy', $customer) }}"
|
||||
onsubmit="return confirm('Sei sicuro di voler eliminare questo cliente?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger">
|
||||
<i class="bi bi-trash me-1"></i>Elimina
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row g-4">
|
||||
|
||||
{{-- ─── Scheda principale ────────────────────────────────────────────── --}}
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white border-0 pt-4 px-4 pb-0">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
{{-- Avatar generato con iniziali --}}
|
||||
<div class="rounded-circle bg-primary d-flex align-items-center justify-content-center text-white fw-bold fs-4"
|
||||
style="width: 56px; height: 56px; flex-shrink: 0;">
|
||||
{{ strtoupper(substr($customer->name, 0, 1)) }}
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="mb-1">{{ $customer->name }}</h4>
|
||||
<div class="d-flex gap-2">
|
||||
<span class="badge bg-{{ $customer->badge_color }}">{{ ucfirst($customer->status) }}</span>
|
||||
<span class="badge bg-light text-dark border">{{ $customer->type_label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-4">
|
||||
|
||||
<div class="row g-4">
|
||||
{{-- Contatti --}}
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted text-uppercase small fw-semibold mb-3">Contatto</h6>
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-4 text-muted fw-normal small">Email</dt>
|
||||
<dd class="col-8">
|
||||
<a href="mailto:{{ $customer->email }}">{{ $customer->email }}</a>
|
||||
</dd>
|
||||
|
||||
@if($customer->phone)
|
||||
<dt class="col-4 text-muted fw-normal small">Telefono</dt>
|
||||
<dd class="col-8">
|
||||
<a href="tel:{{ $customer->phone }}">{{ $customer->phone }}</a>
|
||||
</dd>
|
||||
@endif
|
||||
|
||||
@if($customer->city)
|
||||
<dt class="col-4 text-muted fw-normal small">Città</dt>
|
||||
<dd class="col-8">{{ $customer->city }}</dd>
|
||||
@endif
|
||||
|
||||
@if($customer->address)
|
||||
<dt class="col-4 text-muted fw-normal small">Indirizzo</dt>
|
||||
<dd class="col-8">{{ $customer->address }}</dd>
|
||||
@endif
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
{{-- Dati fiscali --}}
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted text-uppercase small fw-semibold mb-3">Dati fiscali</h6>
|
||||
<dl class="row mb-0">
|
||||
@if($customer->vat_number)
|
||||
<dt class="col-5 text-muted fw-normal small">P. IVA</dt>
|
||||
<dd class="col-7 font-monospace">{{ $customer->vat_number }}</dd>
|
||||
@endif
|
||||
|
||||
@if($customer->fiscal_code)
|
||||
<dt class="col-5 text-muted fw-normal small">Cod. Fiscale</dt>
|
||||
<dd class="col-7 font-monospace">{{ $customer->fiscal_code }}</dd>
|
||||
@endif
|
||||
|
||||
<dt class="col-5 text-muted fw-normal small">Contratto</dt>
|
||||
<dd class="col-7 fw-bold text-success fs-5">
|
||||
{{ $appSettings['currency_symbol'] }}{{ number_format($customer->contract_value, 2, ',', '.') }}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Note --}}
|
||||
@if ($customer->notes)
|
||||
<hr>
|
||||
<h6 class="text-muted text-uppercase small fw-semibold mb-2">Note</h6>
|
||||
<p class="mb-0 text-secondary">{{ $customer->notes }}</p>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ─── Sidebar informazioni ─────────────────────────────────────────── --}}
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h6 class="text-muted text-uppercase small fw-semibold mb-3">Timeline</h6>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="text-muted small">Creato il</span>
|
||||
{{-- format() usa il formato da configurazione dinamica --}}
|
||||
<span class="small">{{ $customer->created_at->format($appSettings['date_format'] ?? 'd/m/Y') }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="text-muted small">Aggiornato il</span>
|
||||
<span class="small">{{ $customer->updated_at->format($appSettings['date_format'] ?? 'd/m/Y') }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="text-muted small">ID sistema</span>
|
||||
<span class="small font-monospace">#{{ $customer->id }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<p class="text-muted small mb-3">Azioni rapide</p>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="{{ route('customers.edit', $customer) }}" class="btn btn-warning btn-sm">
|
||||
<i class="bi bi-pencil me-1"></i>Modifica dati
|
||||
</a>
|
||||
<a href="mailto:{{ $customer->email }}" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-envelope me-1"></i>Invia email
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
195
resources/views/dashboard.blade.php
Normal file
195
resources/views/dashboard.blade.php
Normal file
@@ -0,0 +1,195 @@
|
||||
{{--
|
||||
resources/views/dashboard.blade.php — Dashboard principale
|
||||
|
||||
@extends indica da quale layout "ereditare" la struttura HTML.
|
||||
@section riempie le sezioni definite con @yield nel layout.
|
||||
--}}
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Dashboard')
|
||||
@section('page-title', 'Dashboard')
|
||||
|
||||
@section('page-actions')
|
||||
<a href="{{ route('customers.create') }}" class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-1"></i>Nuovo Cliente
|
||||
</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- Messaggio di benvenuto --}}
|
||||
@if ($welcomeMessage)
|
||||
<div class="alert alert-info border-0 shadow-sm mb-4">
|
||||
<i class="bi bi-info-circle me-2"></i>{{ $welcomeMessage }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ═══ Statistiche ═══════════════════════════════════════════════════ --}}
|
||||
<div class="row g-4 mb-4">
|
||||
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card stat-card h-100">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
<div class="rounded-3 p-3 bg-primary bg-opacity-10 me-3">
|
||||
<i class="bi bi-people fs-3 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold">{{ $stats['total'] }}</div>
|
||||
<div class="text-muted small">Clienti totali</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card stat-card h-100">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
<div class="rounded-3 p-3 bg-success bg-opacity-10 me-3">
|
||||
<i class="bi bi-person-check fs-3 text-success"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold text-success">{{ $stats['active'] }}</div>
|
||||
<div class="text-muted small">Clienti attivi</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card stat-card h-100">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
<div class="rounded-3 p-3 bg-warning bg-opacity-10 me-3">
|
||||
<i class="bi bi-person-exclamation fs-3 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold text-warning">{{ $stats['prospect'] }}</div>
|
||||
<div class="text-muted small">Prospect</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card stat-card h-100">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
<div class="rounded-3 p-3 bg-info bg-opacity-10 me-3">
|
||||
<i class="bi bi-currency-euro fs-3 text-info"></i>
|
||||
</div>
|
||||
<div>
|
||||
{{-- number_format: formatta il numero con separatori --}}
|
||||
<div class="fs-2 fw-bold text-info">
|
||||
{{ $appSettings['currency_symbol'] }}{{ number_format($stats['total_contract_value'], 0, ',', '.') }}
|
||||
</div>
|
||||
<div class="text-muted small">Valore contratti</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- ═══ Clienti recenti + Distribuzione per città ══════════════════════ --}}
|
||||
<div class="row g-4">
|
||||
|
||||
{{-- Ultimi clienti aggiunti --}}
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white border-0 pt-3 pb-0">
|
||||
<h5 class="fw-semibold mb-0">
|
||||
<i class="bi bi-clock-history me-2 text-muted"></i>Clienti recenti
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-3">Cliente</th>
|
||||
<th>Tipo</th>
|
||||
<th>Stato</th>
|
||||
<th>Aggiunto</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{-- @forelse: come @foreach ma gestisce il caso lista vuota --}}
|
||||
@forelse ($recentCustomers as $customer)
|
||||
<tr>
|
||||
<td class="ps-3">
|
||||
<div class="fw-semibold">{{ $customer->name }}</div>
|
||||
<div class="text-muted small">{{ $customer->email }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark border">
|
||||
{{ $customer->type_label }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{-- badge_color è l'accessor definito nel Model --}}
|
||||
<span class="badge bg-{{ $customer->badge_color }}">
|
||||
{{ ucfirst($customer->status) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-muted small">
|
||||
{{-- diffForHumans(): "2 giorni fa", "stamattina", ecc. --}}
|
||||
{{ $customer->created_at->diffForHumans() }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('customers.show', $customer) }}"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted py-4">
|
||||
Nessun cliente ancora. <a href="{{ route('customers.create') }}">Aggiungine uno!</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-end border-0">
|
||||
<a href="{{ route('customers.index') }}" class="btn btn-link btn-sm text-decoration-none">
|
||||
Vedi tutti <i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Clienti per città --}}
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-white border-0 pt-3 pb-0">
|
||||
<h5 class="fw-semibold mb-0">
|
||||
<i class="bi bi-geo-alt me-2 text-muted"></i>Top città
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@forelse ($byCity as $city => $count)
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="fw-medium">{{ $city ?: 'N/D' }}</span>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="progress flex-grow-1" style="width: 80px; height: 6px;">
|
||||
@php
|
||||
$maxCount = max(array_values($byCity));
|
||||
$pct = $maxCount > 0 ? ($count / $maxCount) * 100 : 0;
|
||||
@endphp
|
||||
<div class="progress-bar" style="width: {{ $pct }}%"></div>
|
||||
</div>
|
||||
<span class="badge bg-primary rounded-pill">{{ $count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-muted text-center my-4">Nessun dato disponibile</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
15
resources/views/errors/404.blade.php
Normal file
15
resources/views/errors/404.blade.php
Normal file
@@ -0,0 +1,15 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Pagina non trovata')
|
||||
@section('page-title', 'Pagina non trovata')
|
||||
|
||||
@section('content')
|
||||
<div class="text-center py-5">
|
||||
<div class="display-1 fw-bold text-muted opacity-25">404</div>
|
||||
<h2 class="mt-3">Questa pagina non esiste</h2>
|
||||
<p class="text-muted">La risorsa che cerchi non è disponibile o è stata spostata.</p>
|
||||
<a href="{{ route('dashboard') }}" class="btn btn-primary mt-2">
|
||||
<i class="bi bi-house me-1"></i>Torna alla dashboard
|
||||
</a>
|
||||
</div>
|
||||
@endsection
|
||||
188
resources/views/layouts/app.blade.php
Normal file
188
resources/views/layouts/app.blade.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<!DOCTYPE html>
|
||||
{{--
|
||||
resources/views/layouts/app.blade.php — Layout principale dell'applicazione
|
||||
|
||||
Blade è il motore di template di Laravel. Permette di:
|
||||
- Includere PHP in HTML con sintassi pulita: {{ $variabile }}
|
||||
- Definire sezioni riutilizzabili: @yield, @section/@endsection
|
||||
- Usare direttive: @if, @foreach, @include, ecc.
|
||||
|
||||
Questo layout è il "guscio" HTML condiviso da tutte le pagine.
|
||||
Ogni pagina "estende" questo layout con @extends('layouts.app')
|
||||
e riempie le sezioni con @section('content') ... @endsection
|
||||
--}}
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{{-- @yield('title') viene rimpiazzato dalla sezione 'title' di ogni view --}}
|
||||
<title>@yield('title', 'Dashboard') — {{ $appSettings['company_name'] ?? config('app.name') }}</title>
|
||||
|
||||
{{-- Bootstrap 5 via CDN: nessun build step necessario --}}
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
{{-- Bootstrap Icons --}}
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
{{-- Colore tema dinamico dalle impostazioni --}}
|
||||
--bs-primary: {{ $appSettings['theme_color'] ?? '#0d6efd' }};
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
||||
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
color: rgba(255,255,255,0.75);
|
||||
border-radius: 8px;
|
||||
margin: 2px 0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover,
|
||||
.sidebar .nav-link.active {
|
||||
color: #fff;
|
||||
background-color: rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
.sidebar .nav-link i {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.sidebar-brand {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
|
||||
{{-- ═══════════════════════════════════════════════════════════
|
||||
SIDEBAR — navigazione laterale
|
||||
═══════════════════════════════════════════════════════════ --}}
|
||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar py-3 px-3">
|
||||
|
||||
{{-- Logo/Brand --}}
|
||||
<div class="d-flex align-items-center mb-4 ps-2">
|
||||
<i class="bi bi-people-fill text-primary fs-4 me-2"></i>
|
||||
<span class="sidebar-brand">{{ $appSettings['company_name'] ?? 'Portale Clienti' }}</span>
|
||||
</div>
|
||||
|
||||
<ul class="nav flex-column">
|
||||
{{-- route('dashboard') genera l'URL della route con nome 'dashboard' --}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs('dashboard') ? 'active' : '' }}"
|
||||
href="{{ route('dashboard') }}">
|
||||
<i class="bi bi-speedometer2 me-2"></i>Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs('customers.*') ? 'active' : '' }}"
|
||||
href="{{ route('customers.index') }}">
|
||||
<i class="bi bi-people me-2"></i>Clienti
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs('settings.*') ? 'active' : '' }}"
|
||||
href="{{ route('settings.index') }}">
|
||||
<i class="bi bi-gear me-2"></i>Impostazioni
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{-- Footer sidebar --}}
|
||||
<div class="mt-auto pt-4 ps-2">
|
||||
<small class="text-white-50">
|
||||
<i class="bi bi-envelope me-1"></i>
|
||||
{{ $appSettings['support_email'] ?? '' }}
|
||||
</small>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{{-- ═══════════════════════════════════════════════════════════
|
||||
CONTENUTO PRINCIPALE
|
||||
═══════════════════════════════════════════════════════════ --}}
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-4 py-4 main-content">
|
||||
|
||||
{{-- Header pagina --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h4 mb-0 fw-bold text-dark">@yield('page-title')</h1>
|
||||
@yield('page-actions')
|
||||
</div>
|
||||
|
||||
{{-- ─── Messaggi flash ───────────────────────────────────────────
|
||||
I messaggi flash sono impostati nel Controller con:
|
||||
redirect()->with('success', 'Messaggio...')
|
||||
e visualizzati automaticamente qui.
|
||||
─────────────────────────────────────────────────────────────── --}}
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success alert-dismissible fade show shadow-sm" role="alert">
|
||||
<i class="bi bi-check-circle me-2"></i>{{ session('success') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (session('error'))
|
||||
<div class="alert alert-danger alert-dismissible fade show shadow-sm" role="alert">
|
||||
<i class="bi bi-exclamation-circle me-2"></i>{{ session('error') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Errori di validazione globali (non associati a un campo specifico) --}}
|
||||
@if ($errors->any() && !$errors->hasBag('default'))
|
||||
<div class="alert alert-danger shadow-sm">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Correggi i seguenti errori:</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ─── Sezione contenuto: riempita da ogni view ──────────────── --}}
|
||||
@yield('content')
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Bootstrap JS --}}
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
129
resources/views/settings/index.blade.php
Normal file
129
resources/views/settings/index.blade.php
Normal file
@@ -0,0 +1,129 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Impostazioni')
|
||||
@section('page-title', 'Impostazioni Applicazione')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{--
|
||||
Nota: queste impostazioni sono DINAMICHE — modificabili senza toccare il codice.
|
||||
Sono diverse dalle variabili nel .env (che richiedono un restart del container).
|
||||
|
||||
SettingService salva i valori nel database e li mette in cache Redis.
|
||||
Ogni modifica qui si riflette immediatamente nell'applicazione.
|
||||
--}}
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
|
||||
<div class="alert alert-info border-0 shadow-sm mb-4">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Queste impostazioni si applicano immediatamente. La cache viene aggiornata ad ogni salvataggio.
|
||||
Per la configurazione dell'infrastruttura (database, SMTP, ecc.) modifica il file <code>.env</code>.
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('settings.update') }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
{{-- ═══ Visualizza per gruppo ══════════════════════════════════════ --}}
|
||||
@foreach ($config['groups'] as $groupName => $keys)
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-white border-0 pt-4 pb-0 px-4">
|
||||
<h5 class="fw-semibold mb-1">
|
||||
@switch($groupName)
|
||||
@case('Azienda') <i class="bi bi-building me-2 text-primary"></i>@break
|
||||
@case('Visualizzazione')<i class="bi bi-palette me-2 text-warning"></i>@break
|
||||
@case('Funzionalità') <i class="bi bi-toggles me-2 text-success"></i>@break
|
||||
@default <i class="bi bi-gear me-2 text-muted"></i>
|
||||
@endswitch
|
||||
{{ $groupName }}
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<div class="card-body px-4 pb-4">
|
||||
<div class="row g-3">
|
||||
@foreach ($keys as $key)
|
||||
@php
|
||||
$type = $config['types'][$key] ?? 'string';
|
||||
$desc = $config['descriptions'][$key] ?? $key;
|
||||
$default = $config['defaults'][$key] ?? '';
|
||||
$value = $current[$key] ?? $default;
|
||||
@endphp
|
||||
|
||||
<div class="{{ $type === 'text' ? 'col-12' : 'col-md-6' }}">
|
||||
<label class="form-label fw-medium" for="setting_{{ $key }}">
|
||||
{{ $desc }}
|
||||
</label>
|
||||
|
||||
@if ($type === 'boolean')
|
||||
{{--
|
||||
Checkbox: invia "1" se selezionato.
|
||||
Il controller aggiunge "false" per quelli non spuntati.
|
||||
--}}
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
id="setting_{{ $key }}" name="{{ $key }}"
|
||||
value="1"
|
||||
{{ $value ? 'checked' : '' }}>
|
||||
<label class="form-check-label text-muted small" for="setting_{{ $key }}">
|
||||
{{ $value ? 'Abilitato' : 'Disabilitato' }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@elseif ($type === 'text')
|
||||
<textarea id="setting_{{ $key }}" name="{{ $key }}"
|
||||
rows="3" class="form-control {{ $errors->has($key) ? 'is-invalid' : '' }}">{{ old($key, $value) }}</textarea>
|
||||
@error($key)<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
|
||||
@elseif ($type === 'integer')
|
||||
<input type="number" id="setting_{{ $key }}" name="{{ $key }}"
|
||||
class="form-control {{ $errors->has($key) ? 'is-invalid' : '' }}"
|
||||
value="{{ old($key, $value) }}" min="1">
|
||||
@error($key)<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
|
||||
@elseif ($key === 'theme_color')
|
||||
<div class="input-group">
|
||||
<input type="color" class="form-control form-control-color"
|
||||
style="max-width: 60px;"
|
||||
id="color_preview_{{ $key }}"
|
||||
value="{{ $value }}"
|
||||
oninput="document.getElementById('setting_{{ $key }}').value = this.value">
|
||||
<input type="text" id="setting_{{ $key }}" name="{{ $key }}"
|
||||
class="form-control font-monospace {{ $errors->has($key) ? 'is-invalid' : '' }}"
|
||||
value="{{ old($key, $value) }}"
|
||||
placeholder="#0d6efd"
|
||||
oninput="document.getElementById('color_preview_{{ $key }}').value = this.value">
|
||||
</div>
|
||||
@error($key)<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
|
||||
@else
|
||||
<input type="text" id="setting_{{ $key }}" name="{{ $key }}"
|
||||
class="form-control {{ $errors->has($key) ? 'is-invalid' : '' }}"
|
||||
value="{{ old($key, $value) }}">
|
||||
@error($key)<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
@endif
|
||||
|
||||
{{-- Mostra il valore default come suggerimento --}}
|
||||
<div class="form-text text-muted">
|
||||
Default: <code>{{ is_bool($default) ? ($default ? 'true' : 'false') : $default }}</code>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
<div class="d-flex justify-content-end gap-2">
|
||||
<a href="{{ route('dashboard') }}" class="btn btn-outline-secondary">Annulla</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-floppy me-1"></i>Salva Impostazioni
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
Reference in New Issue
Block a user