Selaa lähdekoodia

fix di attivita_id per dtatable, fix mobile firenli page-title, vista catalogo (inconclusa), migration voucher, vertia menu volontari e prnotazii tavoli

marcofalabretti 2 päivää sitten
vanhempi
commit
4dc1cc1bb4
98 muutettua tiedostoa jossa 3088 lisäystä ja 1065 poistoa
  1. 1
    1
      app/DataTables/AllergeneDataTable.php
  2. 8
    3
      app/DataTables/AttivitaDataTable.php
  3. 6
    1
      app/DataTables/CategoriacontabileDataTable.php
  4. 10
    5
      app/DataTables/CucinaDataTable.php
  5. 5
    1
      app/DataTables/FornitoreDataTable.php
  6. 7
    4
      app/DataTables/MetodoPagamentoDataTable.php
  7. 6
    1
      app/DataTables/OperatoreDataTable.php
  8. 6
    2
      app/DataTables/PagamentoDataTable.php
  9. 14
    13
      app/DataTables/PiattoDataTable.php
  10. 13
    3
      app/DataTables/PrimaNotaDataTable.php
  11. 26
    1
      app/DataTables/PuntoVenditaDataTable.php
  12. 17
    7
      app/DataTables/RigaOrdineDataTable.php
  13. 6
    1
      app/DataTables/TestiDataTable.php
  14. 17
    9
      app/DataTables/UserDataTable.php
  15. 14
    1
      app/DataTables/UserDataTableEditor.php
  16. 1
    0
      app/Http/Controllers/AttivitaController.php
  17. 102
    30
      app/Http/Controllers/CarrelloController.php
  18. 2
    0
      app/Http/Controllers/CategoriaContabileController.php
  19. 2
    0
      app/Http/Controllers/CucinaController.php
  20. 13
    0
      app/Http/Controllers/MetodoPagamentoController.php
  21. 1
    0
      app/Http/Controllers/OperatoreController.php
  22. 1
    0
      app/Http/Controllers/PagamentoController.php
  23. 4
    6
      app/Http/Controllers/PiattoController.php
  24. 2
    1
      app/Http/Controllers/PrimaNotaController.php
  25. 29
    4
      app/Http/Controllers/PuntovenditaController.php
  26. 2
    1
      app/Http/Controllers/RigaOrdineController.php
  27. 2
    0
      app/Http/Controllers/TestiController.php
  28. 56
    13
      app/Http/Controllers/TombolaController.php
  29. 5
    1
      app/Http/Controllers/UserController.php
  30. 10
    0
      app/Http/Controllers/VoucherController.php
  31. 8
    1
      app/Models/AbstractModels/AbstractAttivita.php
  32. 6
    0
      app/Models/AbstractModels/AbstractMetodoPagamento.php
  33. 2
    6
      app/Models/AbstractModels/AbstractUser.php
  34. 15
    0
      app/Models/Dispositivo.php
  35. 4
    0
      app/Models/User.php
  36. 10
    0
      app/Models/Voucher.php
  37. 24
    0
      app/Services/Paga/Contanti.php
  38. 37
    0
      app/Services/Paga/Cupon.php
  39. 24
    0
      app/Services/Paga/Pos.php
  40. 66
    0
      app/Services/Paga/RegistraPagamento.php
  41. 191
    0
      app/Services/Paga/SegrestaWallet.php
  42. 17
    0
      app/Services/Paga/Stripe.php
  43. 9
    9
      config/custom.php
  44. 1
    1
      database/migrations/2026_03_25_004544_attivita.php
  45. 1
    0
      database/migrations/2026_03_27_223801_metodo_pagamento.php
  46. 1
    0
      database/migrations/2026_05_15_230716_categoria_contabile.php
  47. 33
    0
      database/migrations/2026_06_13_170432_voucher.php
  48. 2
    1
      database/seeders/DatabaseSeeder.php
  49. 58
    0
      database/seeders/MetodoPagamentoSeed.php
  50. 8
    1
      database/seeders/PermissionSeed.php
  51. 15
    0
      resources/assets/vendor/js/template-customizer.js
  52. 2
    0
      resources/css/app.css
  53. 23
    0
      resources/css/fest-theme.css
  54. 107
    81
      resources/menu/verticalMenu.json
  55. 25
    0
      resources/views/_partials/badge.blade.php
  56. 16
    1
      resources/views/allergene/index.blade.php
  57. 6
    3
      resources/views/attivita/_partials/parziali.blade.php
  58. 14
    2
      resources/views/attivita/index.blade.php
  59. 15
    2
      resources/views/bacheca/index.blade.php
  60. 15
    2
      resources/views/bilancio/index.blade.php
  61. 15
    2
      resources/views/categoria_contabile/index.blade.php
  62. 14
    2
      resources/views/contenuto_bacheca/index.blade.php
  63. 14
    2
      resources/views/cucina/index.blade.php
  64. 3
    3
      resources/views/dashboard/index.blade.php
  65. 19
    2
      resources/views/endpoint/index.blade.php
  66. 14
    2
      resources/views/evento/index.blade.php
  67. 14
    2
      resources/views/fornitore/index.blade.php
  68. 2
    2
      resources/views/layouts/sections/menu/verticalMenu.blade.php
  69. 26
    4
      resources/views/layouts/sections/navbar/navbar-partial.blade.php
  70. 16
    2
      resources/views/metodo_pagamento/index.blade.php
  71. 3
    3
      resources/views/monitor/index.blade.php
  72. 3
    3
      resources/views/operatore/index.blade.php
  73. 16
    3
      resources/views/ordine/index.blade.php
  74. 14
    2
      resources/views/pagamento/index.blade.php
  75. 19
    5
      resources/views/piatto/index.blade.php
  76. 3
    3
      resources/views/prenotazione/index.blade.php
  77. 14
    2
      resources/views/prima_nota/index.blade.php
  78. 14
    2
      resources/views/print_job/index.blade.php
  79. 14
    2
      resources/views/punto_operatore/index.blade.php
  80. 172
    3
      resources/views/punto_vendita/cassa/_partials/carrello/pagamento/checkout.blade.php
  81. 10
    2
      resources/views/punto_vendita/cassa/_partials/scripts.blade.php
  82. 123
    6
      resources/views/punto_vendita/cassa/index.blade.php
  83. 0
    758
      resources/views/punto_vendita/cassa/vista2.blade.php
  84. 16
    0
      resources/views/punto_vendita/cassa/viste/catalogo/_partials/carrello-item.blade.php
  85. 1
    0
      resources/views/punto_vendita/cassa/viste/catalogo/_partials/scripts.blade.php
  86. 672
    0
      resources/views/punto_vendita/cassa/viste/catalogo/_partials/style.blade.php
  87. 511
    0
      resources/views/punto_vendita/cassa/viste/catalogo/index.blade.php
  88. 14
    3
      resources/views/punto_vendita/index.blade.php
  89. 103
    0
      resources/views/punto_vendita/metodo_pagamento/segresta_wallet.blade.php
  90. 5
    2
      resources/views/role/index.blade.php
  91. 3
    3
      resources/views/saltacoda/index.blade.php
  92. 18
    2
      resources/views/stampante/index.blade.php
  93. 14
    2
      resources/views/testi/index.blade.php
  94. 26
    4
      resources/views/tombola/index.blade.php
  95. 4
    4
      resources/views/tombola/tabellone.blade.php
  96. 5
    2
      resources/views/user/index.blade.php
  97. 3
    0
      resources/views/voucher/index.blade.php
  98. 8
    7
      routes/web.php

+ 1
- 1
app/DataTables/AllergeneDataTable.php Näytä tiedosto

@@ -45,7 +45,7 @@ class AllergeneDataTable extends DataTable
45 45
      */
46 46
     public function query(Allergene $model): QueryBuilder
47 47
     {
48
-        return $model->newQuery();
48
+        return $model->newQuery()->orderBy('nome', 'asc');
49 49
     }
50 50
 
51 51
     /**

+ 8
- 3
app/DataTables/AttivitaDataTable.php Näytä tiedosto

@@ -44,8 +44,12 @@ class AttivitaDataTable extends DataTable
44 44
      * @return QueryBuilder<Attivitum>
45 45
      */
46 46
     public function query(Attivita $model): QueryBuilder
47
-    {
48
-        return $model->newQuery()->where('user_id', Auth::user()->id);
47
+    {   
48
+        if($this->user_id){
49
+            return $model->newQuery()->where('user_id', $this->user_id)->orderBy('nome', 'asc');
50
+        }else{
51
+            return $model->newQuery()->where('user_id', Auth::user()->id);
52
+        }
49 53
     }
50 54
 
51 55
     /**
@@ -82,6 +86,7 @@ class AttivitaDataTable extends DataTable
82 86
                     ->editor(
83 87
                         Editor::make()
84 88
                             ->fields([
89
+                                Fields\Hidden::make('user_id')->default(Auth::user()->id),
85 90
                                 Fields\Text::make('nome')->label('Nome'),
86 91
                                 Fields\Text::make('descrizione')->label('Descrizione'),
87 92
                                 Fields\Image::make('path_logo')->label('Logo'),
@@ -105,7 +110,7 @@ class AttivitaDataTable extends DataTable
105 110
             Column::make('is_attiva_display')->title('Disponibile')->addClass('text-center')->responsivePriority(1)->width('10%'),
106 111
             Column::make('nome')->responsivePriority(1),
107 112
             Column::make('descrizione'),
108
-            Column::make('path_logo'),
113
+            // Column::make('path_logo'),
109 114
             Column::computed('seleziona_attivita'),
110 115
             // Column::make('path_icon'),
111 116
             // Column::make('path_image'),

+ 6
- 1
app/DataTables/CategoriacontabileDataTable.php Näytä tiedosto

@@ -50,7 +50,11 @@ class CategoriacontabileDataTable extends DataTable
50 50
      */
51 51
     public function query(Categoriacontabile $model): QueryBuilder
52 52
     {
53
-        return $model->newQuery()->orderBy('nome', 'asc');
53
+        if($this->attivita_id){
54
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
55
+        }else{
56
+            return $model->newQuery()->whereRaw('1 = 0');
57
+        }
54 58
     }
55 59
 
56 60
     /**
@@ -88,6 +92,7 @@ class CategoriacontabileDataTable extends DataTable
88 92
                     ->editor(
89 93
                         Editor::make()
90 94
                             ->fields([
95
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
91 96
                                 Fields\Text::make('nome')->label('Nome'),
92 97
                                 Fields\Text::make('descrizione')->label('Descrizione'),
93 98
                                 Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),

+ 10
- 5
app/DataTables/CucinaDataTable.php Näytä tiedosto

@@ -67,7 +67,11 @@ class CucinaDataTable extends DataTable
67 67
      */
68 68
     public function query(Cucina $model): QueryBuilder
69 69
     {
70
-        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'));
70
+        if($this->attivita_id){
71
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
72
+        }else{
73
+            return $model->newQuery()->whereRaw('1 = 0');
74
+        }
71 75
     }
72 76
 
73 77
     /**
@@ -100,12 +104,12 @@ class CucinaDataTable extends DataTable
100 104
                     ->editor(
101 105
                         Editor::make()
102 106
                         ->fields([
107
+                          Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
103 108
                             Fields\Text::make('colore')->label('Colore')->set('attr', ['type' => 'color']),
104 109
                             Fields\Text::make('nome')->label('Nome'),
105 110
                             Fields\Text::make('descrizione')->label('Descrizione'),
106 111
                             Fields\Image::make('immagine')->label('Immagine'),
107 112
                             Fields\Boolean::make('is_attiva')->label('Attiva')->default(true),  
108
-                            Fields\Select2::make('attivita_id')->label('Attività')->options(Attivita::where('is_attiva', true)->pluck('id', 'nome')),
109 113
                             // Fields\Select2::make('cucina_id')->label('Cucina')->options(Cucina::where('is_attiva', true)->pluck('id', 'nome')),
110 114
                             Fields\Select2::make('stampante_id')->label('Stampante')->options(Dispositivo::where('tipo', Dispositivo::STAMPANTE)->pluck('id', 'nome')),
111 115
                         ])
@@ -121,9 +125,9 @@ class CucinaDataTable extends DataTable
121 125
     {
122 126
         return [
123 127
             Column::make('id')->visible(false),
124
-            Column::make('is_attiva_display')->title('Disponibile')->addClass('text-center'),
128
+            Column::make('is_attiva_display')->title('Disponibile')->addClass('text-center')->responsivePriority(1),
125 129
             // Column::make('nome'),
126
-            Column::make('badge_colore')->title('Nome')->addClass('text-left'),
130
+            Column::make('badge_colore')->title('Nome')->addClass('text-left')->responsivePriority(1),
127 131
             Column::make('descrizione'),
128 132
             Column::computed('piatti_count')->title('Piatti')->addClass('text-center'),
129 133
             // Column::make('immagine'),
@@ -135,7 +139,8 @@ class CucinaDataTable extends DataTable
135 139
             ->exportable(false)
136 140
             ->printable(false)
137 141
             ->width(60)
138
-            ->addClass('text-center'),
142
+            ->addClass('text-center')
143
+            ->responsivePriority(1),
139 144
         ];
140 145
     }
141 146
 

+ 5
- 1
app/DataTables/FornitoreDataTable.php Näytä tiedosto

@@ -41,7 +41,11 @@ class FornitoreDataTable extends DataTable
41 41
      */
42 42
     public function query(Fornitore $model): QueryBuilder
43 43
     {
44
-        return $model->newQuery()->where('attivita_id', $this->attivita_id);
44
+        if($this->attivita_id){
45
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
46
+        }else{
47
+            return $model->newQuery()->whereRaw('1 = 0');
48
+        }
45 49
     }
46 50
 
47 51
     /**

+ 7
- 4
app/DataTables/MetodoPagamentoDataTable.php Näytä tiedosto

@@ -48,7 +48,11 @@ class MetodoPagamentoDataTable extends DataTable
48 48
      */
49 49
     public function query(MetodoPagamento $model): QueryBuilder
50 50
     {
51
-        return $model->newQuery();
51
+        if($this->attivita_id){
52
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
53
+        }else{
54
+            return $model->newQuery()->whereRaw('1 = 0');
55
+        }
52 56
     }
53 57
 
54 58
     /**
@@ -64,7 +68,6 @@ class MetodoPagamentoDataTable extends DataTable
64 68
                 ->formTitle('Crea nuovo metodo di pagamento')
65 69
                 ->text('<i class="fas fa-plus"></i> Nuovo metodo di pagamento'));
66 70
         }
67
-
68 71
         return $this->builder()
69 72
                     ->setTableId($this->dataTableVariable)
70 73
                     ->columns($this->getColumns())
@@ -78,7 +81,8 @@ class MetodoPagamentoDataTable extends DataTable
78 81
                     ->editor(
79 82
                         Editor::make()
80 83
                             ->fields([
81
-                                Fields\Select2::make('tipo')->label('Tipo')->options(MetodoPagamento::getTipiPagamento()->pluck('value' ,'label')->sortBy('label')),
84
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
85
+                                Fields\Select2::make('tipo')->label('Tipo')->options(MetodoPagamento::getTipiPagamento()->sortBy('label')->pluck('value' ,'label')),
82 86
                                 Fields\Text::make('nome')->label('Nome'),
83 87
                                 Fields\Text::make('descrizione')->label('Descrizione'),
84 88
                                 Fields\Boolean::make('is_attivo')->label('Attivo')->default(true),
@@ -87,7 +91,6 @@ class MetodoPagamentoDataTable extends DataTable
87 91
                                 Fields\Text::make('secret')->label('Secret'),
88 92
                                 Fields\Text::make('path_img')->label('Path immagine'),
89 93
                                 Fields\Text::make('info')->label('Info'),
90
-                                Fields\Select2::make('attivita_id')->label('Attività')->options(Attivita::all()->pluck('id', 'nome')),
91 94
                             ])
92 95
                     )
93 96
                     ->initComplete("function(settings, json){

+ 6
- 1
app/DataTables/OperatoreDataTable.php Näytä tiedosto

@@ -43,7 +43,11 @@ class OperatoreDataTable extends DataTable
43 43
      */
44 44
     public function query(Operatore $model): QueryBuilder
45 45
     {
46
-        return $model->newQuery()->where('attivita_id', $this->attivita_id);
46
+        if($this->attivita_id){
47
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('nome', 'asc');
48
+        }else{
49
+            return $model->newQuery()->whereRaw('1 = 0');
50
+        }
47 51
     }
48 52
 
49 53
     /**
@@ -80,6 +84,7 @@ class OperatoreDataTable extends DataTable
80 84
                     ->editor(
81 85
                         Editor::make()
82 86
                             ->fields([
87
+                                Fields\Hidden::make('attivita_id')->label('Attività')->default($this->attivita_id),
83 88
                                 Fields\Text::make('nome')->label('Nome'),
84 89
                                 Fields\Text::make('cognome')->label('Cognome'),
85 90
                                 Fields\Text::make('email')->label('Email'),

+ 6
- 2
app/DataTables/PagamentoDataTable.php Näytä tiedosto

@@ -64,7 +64,11 @@ class PagamentoDataTable extends DataTable
64 64
      */
65 65
     public function query(Pagamento $model): QueryBuilder
66 66
     {
67
-        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'));
67
+        if($this->attivita_id){
68
+            return $model->newQuery()->where('attivita_id', $this->attivita_id);
69
+        }else{
70
+            return $model->newQuery()->whereRaw('1 = 0');
71
+        }
68 72
     }
69 73
 
70 74
     /**
@@ -73,7 +77,7 @@ class PagamentoDataTable extends DataTable
73 77
     public function html(): HtmlBuilder
74 78
     {
75 79
         $buttons = [];
76
-        if(Auth::user()->can('create-pagamento')){
80
+        if(Auth::user()->hasRole('superadmin')){  //Auth::user()->can('create-pagamento')
77 81
             array_push($buttons, Button::make('create')
78 82
                 ->editor('editor')
79 83
                 ->className('btn btn-sm btn-primary mb-4')

+ 14
- 13
app/DataTables/PiattoDataTable.php Näytä tiedosto

@@ -67,18 +67,19 @@ class PiattoDataTable extends DataTable
67 67
      */
68 68
     public function query(Piatto $model): QueryBuilder
69 69
     {
70
-
70
+        if($this->attivita_id !== null){
71
+            $model = $model->newQuery()->where('attivita_id', $this->attivita_id);
72
+            
71 73
             if (isset($this->cucina_id)) {
72
-                return $model->newQuery()
73
-                    // ->where('menu_id', $this->menu_id)
74
-                    ->where('cucina_id', $this->cucina_id)
74
+                return $model->where('cucina_id', $this->cucina_id)
75 75
                     ->with('cucina', 'elencoAllergeni');
76 76
             }
77
-            return $model->newQuery()
78
-                // ->where('menu_id', $this->menu_id)
79
-                ->with('cucina', 'elencoAllergeni');
80
-        
81
-        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'))->with('cucina', 'elencoAllergeni');
77
+
78
+            return $model->with('cucina', 'elencoAllergeni');
79
+
80
+        }else{
81
+            return $model->newQuery()->whereRaw('1 = 0');
82
+        }
82 83
     }
83 84
 
84 85
     /**
@@ -155,7 +156,7 @@ class PiattoDataTable extends DataTable
155 156
     {
156 157
         $columns = [
157 158
             Column::make('id')->title('ID')->width('10%')->visible(false),
158
-            Column::make('is_attivo')->data('is_attivo_display')->title('Disponibile')->width('10%'),
159
+            Column::make('is_attivo')->data('is_attivo_display')->title('Disponibile')->width('10%')->responsivePriority(1),
159 160
             // ID grezzi per Editor Select2 (stesso schema di disponibile vs disponibile_display)
160 161
             Column::make('cucina_id')->data('cucina_id_display')->title('cucina')->addClass('text-center'),
161 162
         ];
@@ -163,14 +164,14 @@ class PiattoDataTable extends DataTable
163 164
 
164 165
         $columns = array_merge($columns, [
165 166
 
166
-            Column::make('nome')->title('Nome')->searchable(),
167
+            Column::make('nome')->title('Nome')->searchable()->responsivePriority(1),
167 168
             Column::computed('prezzo_display')->title('Prezzo')->addClass('text-center'),
168
-            Column::computed('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center'), // icona in tabella
169
+            Column::computed('cucina_id')->data('cucina_id_display')->title('Cucina')->addClass('text-center')->responsivePriority(2), // icona in tabella
169 170
             Column::computed('allergeni')->title('Allergeni')->visible(false), // valore grezzo per l'editor (array ID)
170 171
             Column::computed('allergeni_display')->title('Allergeni')->visible(true),
171 172
             Column::computed('bacheca_id_display')->title('Bacheca')->addClass('text-center'), // icona in tabella
172 173
             Column::computed('in_evidenza_display')->title('In evidenza')->addClass('text-center'), // icona in tabella
173
-            Column::computed('action')->title('')->width('10%')->addClass('text-center'),
174
+            Column::computed('action')->title('')->width('10%')->addClass('text-center')->responsivePriority(1),
174 175
 
175 176
         ]);
176 177
         // dd($columns);

+ 13
- 3
app/DataTables/PrimaNotaDataTable.php Näytä tiedosto

@@ -117,7 +117,11 @@ class PrimaNotaDataTable extends DataTable
117 117
      */
118 118
     public function query(PrimaNota $model): QueryBuilder
119 119
     {
120
-        return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('created_at', 'desc');
120
+        if($this->attivita_id){
121
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('created_at', 'desc');
122
+        }else{
123
+            return $model->newQuery()->whereRaw('1 = 0');
124
+        }
121 125
     }
122 126
 
123 127
     /**
@@ -144,7 +148,7 @@ class PrimaNotaDataTable extends DataTable
144 148
 
145 149
         if(Auth::user()->can('edit-primanota')){
146 150
             array_push($buttons, Button::raw('Report')
147
-                ->className('btn btn-sm btn-warning mb-4')
151
+                ->className('btn btn-sm btn-primary mb-4')
148 152
                 ->action('function(){
149 153
                     reportPrimaNota();
150 154
                 }')
@@ -153,10 +157,16 @@ class PrimaNotaDataTable extends DataTable
153 157
 
154 158
         if(Auth::user()->can('view-bilancio')){
155 159
             array_push($buttons, Button::raw('Consulta dati')
156
-                ->className('btn btn-sm btn-info mb-4')
160
+                ->className('btn btn-sm btn-primary mb-4')
157 161
                 ->action('window.location.href = "'.route('bilancio.index').'";')
158 162
                 ->text('<i class="fas fa-chart-line"></i> Consulta dati'));
159 163
         }
164
+        if(Auth::user()->can('view-categoria_contabile')){
165
+            array_push($buttons, Button::raw('Categorie contabili')
166
+                ->className('btn btn-sm btn-primary mb-4')
167
+                ->action('window.location.href = "'.route('categoria-contabile.index').'";')
168
+                ->text('<i class="fas fa-chart-line"></i> Categorie contabili'));
169
+        }
160 170
         
161 171
         return $this->builder()
162 172
                     ->setTableId($this->dataTableVariable)

+ 26
- 1
app/DataTables/PuntoVenditaDataTable.php Näytä tiedosto

@@ -44,9 +44,34 @@ class PuntoVenditaDataTable extends DataTable
44 44
                 return $entity->url_stampante ?? 'ND';
45 45
             })
46 46
             ->addColumn('abbinato_display', function($entity){
47
-                return $entity->binding_token ? 'Abbinato' : 'Non abbinato';
47
+                $token = $entity->binding_token;
48
+                $tu = $entity->binding_token && 
49
+                request()->cookie('binding_token') && 
50
+                \Illuminate\Support\Facades\Hash::check($entity->binding_token, request()->cookie('binding_token'));
51
+
52
+                switch(true){
53
+                
54
+                    case (isset($token) && $token != null && $tu == false):
55
+                        return view('_partials.badge', ['success' => 'Abbinato']);
56
+                        break;
57
+                    case ($tu == true):
58
+                        return view('_partials.badge', ['success' => 'Tu']);
59
+                        break;
60
+
61
+                    case ($token == null):
62
+                        return view('_partials.badge', ['error' => 'Non abbinato']);
63
+                        break;
64
+                }
65
+                // $txt = '<span class="badge bg-label-success">*</span>';
66
+                // $userToken = request()->cookie('binding_token');
67
+                // if ($entity->binding_token && $userToken && \Illuminate\Support\Facades\Hash::check($entity->binding_token, $userToken)) {
68
+                //     return str_replace('*','Tu', $txt);
69
+                // }
70
+                // return str_replace('*', $entity->binding_token ? 'Abbinato' : 'Non abbinato', $txt);
71
+                // return $entity->binding_token ? 'Abbinato' : 'Non abbinato';
48 72
             })
49 73
             // ->rawColumns(['punto_vendita_tipo_display'])
74
+            ->rawColumns(['abbinato_display'])
50 75
             ->setRowId('id');
51 76
     }
52 77
 

+ 17
- 7
app/DataTables/RigaOrdineDataTable.php Näytä tiedosto

@@ -67,6 +67,9 @@ class RigaOrdineDataTable extends DataTable
67 67
             ->addColumn('riga_ordine', function ($query) {
68 68
                 return view('punto_vendita.cassa._partials.carrello.piatto_ordinato', ['riga_ordine' => $query]);
69 69
             })
70
+            ->addColumn('vista_catalogo', function ($query) {
71
+                return view('punto_vendita.cassa.viste.catalogo._partials.carrello-item', ['riga_ordine' => $query]);
72
+            })
70 73
             ->setRowId('id')
71 74
             // ->rawColumns([
72 75
             //     'aumenta',
@@ -119,13 +122,13 @@ class RigaOrdineDataTable extends DataTable
119 122
                     ->paging(false)
120 123
                     ->selectStyleSingle()
121 124
                     ->responsive(true)
122
-                    ->editor(
123
-                        Editor::make()
124
-                            ->fields([
125
-                                Fields\Text::make('quantita')->label('Quantità'),
126
-                                Fields\Text::make('note')->label('Note'),
127
-                            ])
128
-                    )
125
+                    // ->editor(
126
+                    //     Editor::make()
127
+                    //         ->fields([
128
+                    //             Fields\Text::make('quantita')->label('Quantità'),
129
+                    //             Fields\Text::make('note')->label('Note'),
130
+                    //         ])
131
+                    // )
129 132
                     ->initComplete("function(settings, json){
130 133
                         initComplete_rigaordine();
131 134
                     }");
@@ -136,6 +139,13 @@ class RigaOrdineDataTable extends DataTable
136 139
      */
137 140
     public function getColumns(): array
138 141
     {
142
+        if($this->vista == 'catalogo'){
143
+            return [
144
+                Column::make('id')->visible(false),
145
+                Column::make('vista_catalogo')->title('')->searchable(true)->data('vista_catalogo')->addClass('text-start col-5 col-sm-5 col-md-5 col-lg-5 col-xl-5 col-xxl-5'),
146
+            ];
147
+        }
148
+
139 149
         return [
140 150
             Column::make('id')->visible(false),
141 151
             // Column::computed('riga_ordine')->title('')->searchable(true),

+ 6
- 1
app/DataTables/TestiDataTable.php Näytä tiedosto

@@ -13,6 +13,7 @@ use Yajra\DataTables\Html\Editor\Editor;
13 13
 use Yajra\DataTables\Html\Editor\Fields;
14 14
 use Yajra\DataTables\Services\DataTable;
15 15
 use Illuminate\Support\Facades\Auth;
16
+use Illuminate\Support\Facades\Session;
16 17
 
17 18
 class TestiDataTable extends DataTable
18 19
 {
@@ -40,7 +41,11 @@ class TestiDataTable extends DataTable
40 41
      */
41 42
     public function query(Testi $model): QueryBuilder
42 43
     {
43
-        return $model->newQuery()->where('attivita_id', session()->get('attivita_attuale'));
44
+        if($this->attivita_id){
45
+            return $model->newQuery()->where('attivita_id', $this->attivita_id)->orderBy('titolo', 'asc');
46
+        }else{
47
+            return $model->newQuery()->whereRaw('1 = 0');
48
+        }
44 49
     }
45 50
 
46 51
     /**

+ 17
- 9
app/DataTables/UserDataTable.php Näytä tiedosto

@@ -13,6 +13,7 @@ use Yajra\DataTables\Html\Editor\Fields;
13 13
 use Yajra\DataTables\Services\DataTable;
14 14
 use Illuminate\Support\Facades\Auth;
15 15
 use App\Models\Role;
16
+use Illuminate\Support\Str;
16 17
 
17 18
 class UserDataTable extends DataTable
18 19
 {
@@ -34,7 +35,8 @@ class UserDataTable extends DataTable
34 35
       return $entity->roles->pluck('display_name')->implode(', ');
35 36
     })
36 37
     ->addColumn('ruolo_id', function($entity){
37
-      return $entity->roles->first()->id;
38
+      $ruolo = $entity->roles->first();
39
+      return $ruolo ? $ruolo->id : 'Ruolo non assegnato';
38 40
     })
39 41
     ->addColumn('azienda_display', function($entity){
40 42
       return $entity->azienda ? $entity->azienda : '';
@@ -49,9 +51,12 @@ class UserDataTable extends DataTable
49 51
   */
50 52
   public function query(User $model): QueryBuilder
51 53
   {
52
-    return $model->newQuery()
53
-    // ->where('is_gruppo', 0)
54
-    ->with('roles');
54
+    if(Auth::user()->hasRole('superadmin')){
55
+      return $model->newQuery();
56
+    }else{
57
+      return $model->newQuery()->where('1 = 0');
58
+    }
59
+
55 60
   }
56 61
 
57 62
   /**
@@ -63,13 +68,14 @@ class UserDataTable extends DataTable
63 68
     if(Auth::user()->can('create-user')){
64 69
       array_push($buttons, Button::make('create')
65 70
       ->editor('editor')
66
-      ->formTitle('Crea nuovo utente')
71
+      ->formTitle('Crea nuova organizzazione')
67 72
       ->className('btn btn-sm btn-primary mb-4')
68
-      ->text('<i class="fas fa-plus"></i> Nuovo utente'));
73
+      ->text('<i class="fas fa-plus"></i> Nuova organizzazione'));
69 74
     }
70 75
 
71 76
     if(Auth::user()->hasRole('superadmin')){
72 77
       $roles = Role::orderBy('display_name', 'asc')->pluck('id', 'display_name');
78
+
73 79
     }else{
74 80
       $roles = Role::whereNotIn('name', ['superadmin'])->orderBy('display_name', 'asc')->pluck('id', 'display_name');
75 81
     }
@@ -77,9 +83,10 @@ class UserDataTable extends DataTable
77 83
     $fields = [
78 84
       Fields\Text::make('nome')->label('Nome'),
79 85
       Fields\Text::make('cognome')->label('Cognome'),
80
-      Fields\Text::make('email')->label('Email'),
81 86
       Fields\Text::make('telefono')->label('Telefono'),
82
-      Fields\Select::make('ruolo_id')->label('Ruolo')->options($roles)->default(Role::where('name', 'user')->first()->id),
87
+      Fields\Text::make('email')->label('Email'),
88
+      // Fields\Text::make('password')->label('Password')->default(Str::random(8)),
89
+      Fields\Select::make('ruolo_id')->label('Ruolo')->options($roles)->default(Role::where('name', 'amministratore')->first()->id),
83 90
       Fields\Text::make('azienda')->label('Azienda')
84 91
     ];
85 92
 
@@ -107,10 +114,11 @@ class UserDataTable extends DataTable
107 114
     public function getColumns(): array
108 115
     {
109 116
       $columns = [
117
+        Column::make('id')->visible(false),
110 118
         Column::make('nome')->title('Nome'),
111 119
         Column::make('cognome')->title('Cognome'),
112
-        Column::make('email')->title('Email'),
113 120
         Column::make('telefono')->title('Telefono'),
121
+        Column::make('email')->title('Email'),
114 122
         Column::make('ruolo_id')->title('Ruolo')->searchable(false)->name('ruolo_id')->data('ruolo_display'),
115 123
         Column::make('azienda')->title('Azienda')->data('azienda_display')->searchable(false),
116 124
         Column::computed('action')

+ 14
- 1
app/DataTables/UserDataTableEditor.php Näytä tiedosto

@@ -10,6 +10,7 @@ use Illuminate\Http\Request;
10 10
 use Illuminate\Validation\ValidationException;
11 11
 use Storage;
12 12
 use Illuminate\Support\Str;
13
+use Illuminate\Support\Facades\Hash;
13 14
 
14 15
 class UserDataTableEditor extends DataTablesEditor
15 16
 {
@@ -76,16 +77,28 @@ class UserDataTableEditor extends DataTablesEditor
76 77
 
77 78
   public function creating(Model $model, array $data): array
78 79
   {
79
-    $model->roles()->sync([$data['ruolo_id']]);
80
+    // $model->roles()->sync([$data['ruolo_id']]);
81
+    $this->tempRoleId = $data['ruolo_id'];
82
+    $data['password'] = Hash::make(Str::random(8));
80 83
     return $data;
81 84
   }
82 85
 
86
+  public function created(Model $model, array $data): Model
87
+  {
88
+    $model->roles()->sync([$this->tempRoleId]);
89
+    return $model;
90
+  }
91
+
83 92
   public function updating(Model $model, array $data): array
84 93
   {
85 94
     // dd($data['ruolo']);
86 95
     $model->roles()->sync([$data['ruolo_id']]);
96
+    if(isset($data['password'])){
97
+      $data['password'] = Hash::make($data['password']);
98
+    }
87 99
     return $data;
88 100
   }
101
+
89 102
   public function messages(): array
90 103
   {
91 104
     return $this->messages;

+ 1
- 0
app/Http/Controllers/AttivitaController.php Näytä tiedosto

@@ -31,6 +31,7 @@ class AttivitaController extends Controller
31 31
 
32 32
     public function index(AttivitaDataTable $dataTable)
33 33
     {
34
+        $dataTable->user_id = Auth::user()->id;
34 35
         return $dataTable->render('attivita.index');
35 36
     }
36 37
 

+ 102
- 30
app/Http/Controllers/CarrelloController.php Näytä tiedosto

@@ -272,6 +272,7 @@ class CarrelloController extends Controller
272 272
         ]);
273 273
     }
274 274
 
275
+
275 276
     public function checkout(Request $request){
276 277
         // $ordineA = Ordine::where([
277 278
         //     'stato' => Ordine::CARRELLO, 
@@ -300,6 +301,11 @@ class CarrelloController extends Controller
300 301
     }
301 302
 
302 303
     public function paga_ordine(Request $request){
304
+
305
+        if(!$request->filled('tag_id') && MetodoPagamento::find($request->metodo_pagamento_id)->tipo == MetodoPagamento::SEGRESTA_WALLET){
306
+            return back()->with('error', 'Tag ID obbligatorio per il metodo di pagamento Segresta Wallet');
307
+        }
308
+        
303 309
         $ordine = Ordine::find($request->ordine_id);
304 310
         if($ordine == null){
305 311
             return response()->json([
@@ -323,52 +329,118 @@ class CarrelloController extends Controller
323 329
         
324 330
         switch($pagamento->metodo_pagamento->tipo){
325 331
             case MetodoPagamento::CONTANTI:
326
-                $pagamento->stato = Pagamento::PAGATO;
327
-                $pagamento->save();
328
-                $ordine->update(['stato' => Ordine::PAGATO]);
329
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
332
+                // $pagamento->stato = Pagamento::PAGATO;
333
+                // $pagamento->save();
334
+                // $ordine->update(['stato' => Ordine::PAGATO]);
335
+                // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
336
+                
337
+                $pagamentoResult = app('\App\Services\Paga\Contanti')->paga($pagamento);
338
+                
339
+                if($pagamentoResult['result'] === true){
340
+                    $ordine->update(['stato' => Ordine::PAGATO]);
341
+                    return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
342
+                }else{
343
+                    $ordine->stato = Ordine::CARRELLO;
344
+                    $ordine->save();
345
+                    return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
346
+                }
347
+
330 348
                 break;
331 349
             case MetodoPagamento::BONIFICO:
332
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
333
-                $pagamento->save();
334
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con bonifico riuscito.');
350
+                // $pagamento->update(['stato' , Pagamento::PAGATO]);
351
+                // $pagamento->save();
352
+                // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con bonifico riuscito.');
353
+                
354
+                $ordine->stato = Ordine::CARRELLO;
355
+                    $ordine->save();
356
+                    return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
357
+
335 358
                 break;  
336 359
             case MetodoPagamento::PAYPAL:
337
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
338
-                $pagamento->save();
339
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con paypal riuscito.');
360
+                // $pagamento->update(['stato' , Pagamento::PAGATO]);
361
+                // $pagamento->save();
362
+                // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con paypal riuscito.');
363
+                
364
+                $ordine->stato = Ordine::CARRELLO;
365
+                    $ordine->save();
366
+                    return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
367
+
340 368
                 break;
341 369
             case MetodoPagamento::CARTA_DI_DEBITO:  
342
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
343
-                $pagamento->save();
344
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con carta di debito riuscito.');
370
+                // $pagamento->update(['stato' , Pagamento::PAGATO]);
371
+                // $pagamento->save();
372
+                // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con carta di debito riuscito.');
373
+                
374
+                $ordine->stato = Ordine::CARRELLO;
375
+                    $ordine->save();
376
+                    return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
377
+
345 378
                 break;
346 379
             case MetodoPagamento::CUPON:
347
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
348
-                $pagamento->save();
349
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con coupon riuscito.');
380
+                $pagamentoResult = app('\App\Services\Paga\Cupon')->paga($pagamento);
381
+                
382
+                if($pagamentoResult['result'] === true){
383
+                    $ordine->update(['stato' => Ordine::PAGATO]);
384
+                    return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con cupon riuscito.');
385
+                }else{
386
+                    $ordine->stato = Ordine::CARRELLO;
387
+                    $ordine->save();
388
+                    return back()->with('error', 'Pagamento con cupon non riuscito. '.$pagamentoResult['message']);
389
+                }
350 390
                 break;
351 391
             case MetodoPagamento::SEGRESTA_WALLET:
352
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
353
-                $pagamento->save();
354
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con wallet riuscito.');
392
+                $pagamentoResult = app('\App\Services\Paga\SegrestaWallet')
393
+                ->registraMovimento($pagamento, 'uscita', $ordine->prezzo, $ordine->attivita->nome.' - Pagamento ordine #'.$ordine->id, $request->tag_id);
394
+                
395
+                if($pagamentoResult['result'] === true){
396
+                    $pagamento->update(['stato' => Pagamento::PAGATO]);
397
+                    $pagamento->save();
398
+                    return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con wallet riuscito.');
399
+                }else{
400
+                    $pagamento->stato = Pagamento::ERRORE;
401
+                    $pagamento->save();
402
+                    $ordine->stato = Ordine::CARRELLO;
403
+                    $ordine->save();
404
+                    return back()->with('error', 'Pagamento con wallet non riuscito. '.$pagamentoResult['message']);
405
+                }
355 406
                 break;
356
-            case MetodoPagamento::APPLE_PAY:
357
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
358
-                $pagamento->save();
359
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con apple pay riuscito.');
407
+           
408
+                case MetodoPagamento::APPLE_PAY:
409
+                    // $pagamento->update(['stato' , Pagamento::PAGATO]);
410
+                    // $pagamento->save();
411
+                    // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con apple pay riuscito.');
412
+                    
413
+                    $ordine->stato = Ordine::CARRELLO;
414
+                    $ordine->save();
415
+                    return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
416
+
360 417
                 break;
361 418
             case MetodoPagamento::GOOGLE_PAY:
362
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
363
-                $pagamento->save();
364
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con google pay riuscito.');
419
+                // $pagamento->update(['stato' , Pagamento::PAGATO]);
420
+                // $pagamento->save();
421
+                // return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con google pay riuscito.');
422
+                
423
+                $ordine->stato = Ordine::CARRELLO;
424
+                    $ordine->save();
425
+                    return back()->with('error', 'METODO PAGAMENTO NON DISPONIBILE. ');
426
+
365 427
                 break;
366 428
             case MetodoPagamento::POS:
367
-                $pagamento->update(['stato' , Pagamento::PAGATO]);
368
-                $pagamento->save();
369
-                return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con pos riuscito.');
370
-                break;
429
+                $pagamentoResult = app('\App\Services\Paga\Pos')->paga($pagamento);
430
+                
431
+                if($pagamentoResult['result'] === true){
432
+                    $ordine->update(['stato' => Ordine::PAGATO]);
433
+                    return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('success', 'Pagamento con contanti riuscito. ->'.$pagamento->metodo_pagamento->tipo);
434
+                }else{
435
+                    $ordine->stato = Ordine::CARRELLO;
436
+                    $ordine->save();
437
+                    return back()->with('error', 'Pagamento con contanti non riuscito. '.$pagamentoResult['message']);
438
+                }
371 439
             default:
440
+                $ordine->stato = Ordine::CARRELLO;
441
+                $ordine->save();
442
+                $pagamento->stato = Pagamento::ERRORE;
443
+                $pagamento->save();
372 444
                 return redirect()->route('punto-vendita.show', ['punto_vendita_id' => $ordine->dispositivo_id])->with('error', 'Metodo di pagamento non supportato. Pagamento non riuscito.'.$request->metodo_pagamento_id?? 'ND');
373 445
                 break;
374 446
         }

+ 2
- 0
app/Http/Controllers/CategoriaContabileController.php Näytä tiedosto

@@ -7,6 +7,7 @@ use App\Models\Categoriacontabile;
7 7
 use App\DataTables\CategoriacontabileDataTable;
8 8
 use App\DataTables\CategoriacontabileDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10
+use Illuminate\Support\Facades\Session;
10 11
 
11 12
 class CategoriaContabileController extends Controller
12 13
 {
@@ -28,6 +29,7 @@ class CategoriaContabileController extends Controller
28 29
     
29 30
     public function index(CategoriacontabileDataTable $dataTable)
30 31
     {
32
+        $dataTable->attivita_id = Session::get('attivita_attuale');
31 33
         return $dataTable->render('categoria_contabile.index');
32 34
     }
33 35
     

+ 2
- 0
app/Http/Controllers/CucinaController.php Näytä tiedosto

@@ -7,6 +7,7 @@ use App\Models\Cucina;
7 7
 use App\DataTables\CucinaDataTable;
8 8
 use App\DataTables\CucinaDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10
+use Illuminate\Support\Facades\Session;
10 11
 
11 12
 
12 13
 class CucinaController extends Controller
@@ -29,6 +30,7 @@ class CucinaController extends Controller
29 30
 
30 31
     public function index(CucinaDataTable $dataTable)
31 32
     {
33
+        $dataTable->attivita_id = Session::get('attivita_attuale');
32 34
         return $dataTable->render('cucina.index');
33 35
     }
34 36
 

+ 13
- 0
app/Http/Controllers/MetodoPagamentoController.php Näytä tiedosto

@@ -7,6 +7,7 @@ use App\Models\MetodoPagamento;
7 7
 use App\DataTables\MetodoPagamentoDataTable;
8 8
 use App\DataTables\MetodoPagamentoDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10
+use Illuminate\Support\Facades\Session;
10 11
 
11 12
 class MetodoPagamentoController extends Controller
12 13
 {
@@ -28,6 +29,8 @@ class MetodoPagamentoController extends Controller
28 29
     
29 30
     public function index(MetodoPagamentoDataTable $dataTable)
30 31
     {
32
+
33
+        $dataTable->attivita_id = Session::get('attivita_attuale');
31 34
         return $dataTable->render('metodo_pagamento.index');
32 35
     }
33 36
     public function store(MetodoPagamentoDataTableEditor $editor)
@@ -50,4 +53,14 @@ class MetodoPagamentoController extends Controller
50 53
         return $editor->process($request);
51 54
     }
52 55
 
56
+    public function segresta_wallet_chiE(Request $request)
57
+    {
58
+        $request->validate([
59
+            'tag_id' => 'required|string|max:255',
60
+        ]);
61
+        $tag_id = $request->tag_id;
62
+        $response = app('\App\Services\Paga\SegrestaWallet')->chiE($tag_id);
63
+        return response()->json($response);
64
+    }
65
+
53 66
 }

+ 1
- 0
app/Http/Controllers/OperatoreController.php Näytä tiedosto

@@ -39,6 +39,7 @@ class OperatoreController extends Controller
39 39
     
40 40
     public function index(OperatoreDataTable $dataTable)
41 41
     {
42
+        $dataTable->attivita_id = Session::get('attivita_attuale');
42 43
         return $dataTable->render('operatore.index');
43 44
     }
44 45
 

+ 1
- 0
app/Http/Controllers/PagamentoController.php Näytä tiedosto

@@ -29,6 +29,7 @@ class PagamentoController extends Controller
29 29
 
30 30
     public function index(PagamentoDataTable $dataTable)
31 31
     {
32
+        $dataTable->attivita_id = session()->get('attivita_attuale');
32 33
         return $dataTable->render('pagamento.index');
33 34
     }
34 35
 

+ 4
- 6
app/Http/Controllers/PiattoController.php Näytä tiedosto

@@ -8,6 +8,7 @@ use App\Models\PiattoHasAllergene;
8 8
 use App\DataTables\PiattoDataTable;
9 9
 use App\DataTables\PiattoDataTableEditor;
10 10
 use Illuminate\Support\Facades\Auth;
11
+use Illuminate\Support\Facades\Session;
11 12
 
12 13
 class PiattoController extends Controller
13 14
 {
@@ -28,15 +29,12 @@ class PiattoController extends Controller
28 29
     }
29 30
 
30 31
     public function index(PiattoDataTable $dataTable){
31
-      // if(request()->get('menu_id')){
32
-      //   $dataTable->menu_id = request()->get('menu_id');
33
-      // }
32
+      $dataTable->attivita_id = Session::get('attivita_attuale');
33
+
34 34
       if(request()->get('cucina_id')){
35 35
         $dataTable->cucina_id = request()->get('cucina_id');
36 36
       }
37
-      // if(isset($dataTable->categoria_id) || isset($dataTable->menu_id)){
38
-      // return $dataTable->render('piatto.datatable');
39
-      // }
37
+
40 38
         return $dataTable->render('piatto.index');
41 39
     }
42 40
 

+ 2
- 1
app/Http/Controllers/PrimaNotaController.php Näytä tiedosto

@@ -29,6 +29,8 @@ class PrimaNotaController extends Controller
29 29
 
30 30
     public function index(PrimaNotaDataTable $dataTable)
31 31
     {
32
+        $dataTable->attivita_id = session()->get('attivita_attuale');
33
+        
32 34
         $statistiche['totale_operazioni'] = PrimaNota::where('attivita_id', session()->get('attivita_attuale'))
33 35
         ->where('created_at', '>=', Carbon::now()->startOfDay())
34 36
         ->count();
@@ -41,7 +43,6 @@ class PrimaNotaController extends Controller
41 43
         ->where('created_at', '>=', Carbon::now()->startOfDay())
42 44
         ->sum('importo');
43 45
         $statistiche['saldo'] = $statistiche['importo_entrate'] - $statistiche['importo_uscite'];
44
-        $dataTable->attivita_id = session()->get('attivita_attuale');
45 46
         return $dataTable->render('prima_nota.index', compact('statistiche'));
46 47
     }
47 48
 

+ 29
- 4
app/Http/Controllers/PuntovenditaController.php Näytä tiedosto

@@ -98,6 +98,11 @@ class PuntoVenditaController extends Controller
98 98
 
99 99
     public function show(Request $request, RigaOrdineDataTable $dataTable)
100 100
     {
101
+        if(!Auth::user()->can('view-punto_vendita')){
102
+            return redirect()->route('punto-vendita.index')
103
+            ->with('error', 'Non hai il permesso di accedere a questo punto di vendita');
104
+        }
105
+
101 106
         $puntoVendita = Dispositivo::find(request()->get('punto_vendita_id'));
102 107
         if(!$puntoVendita){
103 108
             return redirect()->route('punto-vendita.index')
@@ -105,6 +110,7 @@ class PuntoVenditaController extends Controller
105 110
         }
106 111
 
107 112
         if($puntoVendita->binding_token == '' || $puntoVendita->binding_token == null ){
113
+            // $puntoVendita->binding_token = Str::random(32);
108 114
             $puntoVendita->binding_token = Hash::make(Str::random(32));
109 115
             $puntoVendita->save();
110 116
         }
@@ -119,19 +125,28 @@ class PuntoVenditaController extends Controller
119 125
             Questo serve a garantire che ogni dispositivo rimanga "associato" al suo token, impedendo accessi da device diversi senza il corretto re-binding.
120 126
         */
121 127
         if(Cookie::has('binding_token')){
122
-            if(Hash::check(Cookie::get('binding_token'), $puntoVendita->binding_token)){
128
+            if(Hash::check(Cookie::get('binding_token'), Hash::make($puntoVendita->binding_token))){
123 129
                 // dd('A' , Cookie::get('binding_token') , $puntoVendita->binding_token);
124 130
                 Cookie::queue(Cookie::forget('binding_token'));
125 131
                 return redirect()->back()->with('error', 'Token di binding non valido. Si sta accedendo da un altro dispositivo.');
126 132
             }
127 133
         }else{
128 134
             Cookie::queue('binding_token', Hash::make($puntoVendita->binding_token));
135
+            // Cookie::queue('binding_token', $puntoVendita->binding_token);
129 136
         }
130 137
   
131 138
    
132 139
 
133 140
         // dd(Cookie::get('binding_token'));
134
-        $cucine = $puntoVendita->cucine()->where('is_attiva', true)->orderBy('nome')->get();
141
+        $cucine = $puntoVendita->cucine()
142
+            ->where('is_attiva', true)
143
+            ->with(['piatti' => function ($query) {
144
+                $query->where('is_attivo', true)
145
+                    ->with('allergeni')
146
+                    ->orderBy('nome');
147
+            }])
148
+            ->orderBy('nome')
149
+            ->get();
135 150
 
136 151
 
137 152
 
@@ -146,11 +161,19 @@ class PuntoVenditaController extends Controller
146 161
                 ]);
147 162
 
148 163
         $dataTable->ordine_id = $ordine->id;
164
+        
165
+        if($request->has('vista') && $request->vista == 'catalogo'){
166
+            $dataTable->vista = 'catalogo';
167
+        }
149 168
 
150 169
                 switch($puntoVendita->tipo){
151 170
                     case Dispositivo::CASSA:
152
-                        // return $dataTable->render('punto_vendita.cassa.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
153
-                        return $dataTable->render('punto_vendita.cassa.vista2', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
171
+                        if($request->has('vista') && $request->vista == 'catalogo'){
172
+                            return $dataTable->render('punto_vendita.cassa.viste.catalogo.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable , 'vista' => 'catalogo']);
173
+                        }else{
174
+                        return $dataTable->render('punto_vendita.cassa.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
175
+                        }
176
+                        // return $dataTable->render('punto_vendita.cassa.vista2', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
154 177
                     case Dispositivo::KIOSK:
155 178
                         return $dataTable->render('punto_vendita.kiosk.index', ['punto_vendita' => $puntoVendita , 'cucine' => $cucine, 'ordine' => $ordine, 'dataTable_rigaordine' => $dataTable]);
156 179
                     case Dispositivo::CAMERIERE:
@@ -165,6 +188,8 @@ class PuntoVenditaController extends Controller
165 188
             return response()->json(['success' => false, 'message' => 'Punto di vendita non trovato']);
166 189
         }
167 190
 
191
+        Cookie::queue(Cookie::forget('binding_token'));
192
+
168 193
         $puntoVendita->binding_token = null;
169 194
         $puntoVendita->save();
170 195
 

+ 2
- 1
app/Http/Controllers/RigaOrdineController.php Näytä tiedosto

@@ -149,11 +149,12 @@ Log::info('riga ordine chiamata', [
149 149
                 'ordine_id' => $riga_ordine->ordine->id,
150 150
                 'fcm_token' => $riga_ordine->ordine->fcm_token,
151 151
             ]);
152
-            app(NotificaOrdineService::class)->inviaOrdinePronto(
152
+            app(\App\Services\Notifica\NotificaOrdineService::class)->inviaOrdinePronto(
153 153
                 $riga_ordine,
154 154
                 'Ordine pronto',
155 155
                 ($riga_ordine->piatto?->nome ?? 'Piatto').' — ritira al banco'
156 156
             );
157
+       
157 158
         }
158 159
         return response()->json(['success' => true, 'message' => 'Riga ordine chiamata']);
159 160
     }

+ 2
- 0
app/Http/Controllers/TestiController.php Näytä tiedosto

@@ -7,6 +7,7 @@ use App\Models\Testi;
7 7
 use App\DataTables\TestiDataTable;
8 8
 use App\DataTables\TestiDataTableEditor;
9 9
 use Illuminate\Support\Facades\Auth;
10
+use Illuminate\Support\Facades\Session;
10 11
 
11 12
 class TestiController extends Controller
12 13
 {
@@ -29,6 +30,7 @@ class TestiController extends Controller
29 30
 
30 31
     public function index(TestiDataTable $dataTable)
31 32
     {
33
+        $dataTable->attivita_id = Session::get('attivita_attuale');
32 34
         return $dataTable->render('testi.index');
33 35
     }
34 36
 

+ 56
- 13
app/Http/Controllers/TombolaController.php Näytä tiedosto

@@ -4,6 +4,9 @@ namespace App\Http\Controllers;
4 4
 
5 5
 use Illuminate\Http\Request;
6 6
 use App\Models\Tombola;
7
+use Illuminate\Support\Facades\Session;
8
+use Illuminate\Support\Facades\Auth;
9
+use App\Models\Attivita;
7 10
 
8 11
 class TombolaController extends Controller
9 12
 {
@@ -19,17 +22,32 @@ class TombolaController extends Controller
19 22
     {
20 23
         return [
21 24
             new Middleware('permission:view-tombola', only: ['index']),
22
-            new Middleware('permission:create-tombola|edit-tombola|delete-tombola', only: ['store', 'update', 'destroy']),
25
+            new Middleware('permission:create-tombola|edit-tombola|delete-tombola', only: ['getTabellone', 'estrai', 'azzera', 'estratti']),
23 26
         ];
24 27
     }
28
+    public function getTabellone(Request $request){
29
+        if(Auth::user()->can('delete-tombola') && Attivita::find($attivita_id)->user_id == Auth::user()->id){
30
+            return redirect()->route('tombola.index')->with('error', 'Non hai permesso di azzerare la tombola.');
31
+        }
32
+       
33
+        foreach (range(1, 90) as $numero) {
34
+            $tombola = Tombola::firstOrCreate([
35
+                'attivita_id' => Session::get('attivita_attuale'),
36
+                'numero' => $numero,
37
+                'estratto' => false,
38
+                'estratto_at' => null,
39
+            ]);
40
+        }
41
+        return redirect()->route('tombola.index')->with('success', 'Tabellone generato con successo.');
42
+    }
25 43
 
26 44
     public function index(Request $request){
27
-        $estratti = Tombola::where('estratto', true)
45
+        $estratti = Tombola::where('attivita_id', Session::get('attivita_attuale'))->where('estratto', true)
28 46
             ->orderByDesc('estratto_at')
29 47
             ->get(['numero', 'estratto_at']);
30 48
 
31 49
         $estrattiCount = $estratti->count();
32
-        $totale = Tombola::count();
50
+        $totale = Tombola::where('attivita_id', Session::get('attivita_attuale'))->count();
33 51
         $totale = $totale > 0 ? $totale : 90;
34 52
         $rimanenti = max($totale - $estrattiCount, 0);
35 53
         $ultimoEstratto = $estratti->first();
@@ -43,17 +61,30 @@ class TombolaController extends Controller
43 61
             'ultimoEstratto' => $ultimoEstratto,
44 62
             'ultimiEstratti' => $ultimiEstratti,
45 63
             'percentuale' => $percentuale,
46
-            'urlEstrattiPubblica' => route('cliente.tombola.estratti'),
47
-            'urlTabellone' => route('tombola.tabellone'),
64
+            'urlEstrattiPubblica' => route('tombola.estratti', ['attivita_id' => Session::get('attivita_attuale')]),
65
+            'urlTabellone' => route('tombola.tabellone', ['attivita_id' => Session::get('attivita_attuale')]),
48 66
         ]);
49 67
     }
50 68
 
51
-    public function tabellone(Request $request){
52
-        return view('tombola.tabellone');
69
+    public function tabellone(Request $request, $attivita_id){
70
+        if(Auth::user()->can('view-tombola') && Attivita::find($attivita_id)->user_id == Auth::user()->id){
71
+            return redirect()->route('tombola.index')->with('error', 'Non hai permesso di vedere il tabellone.');
72
+        }
73
+        $attivita = Attivita::find($attivita_id);
74
+        if(!$attivita){
75
+            return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
76
+        }
77
+        return view('tombola.tabellone', [
78
+            'attivita' => $attivita,
79
+        ]);
53 80
     }
54 81
 
55 82
     public function estrai(Request $request){
56
-        $tombola = Tombola::where('estratto', false)->inRandomOrder()->first();
83
+        if(Auth::user()->can('view-tombola') && Attivita::find($attivita_id)->user_id == Auth::user()->id){
84
+            return redirect()->route('tombola.index')->with('error', 'Non hai permesso di azzerare la tombola.');
85
+        }
86
+        $tabellone = Tombola::where('attivita_id', Session::get('attivita_attuale'));
87
+        $tombola = $tabellone->where('estratto', false)->inRandomOrder()->first();
57 88
         if(!$tombola){
58 89
             if ($request->expectsJson() || $request->ajax()) {
59 90
                 return response()->json([
@@ -69,7 +100,7 @@ class TombolaController extends Controller
69 100
         $tombola->estratto_at = now();
70 101
         $tombola->save();
71 102
 
72
-        $estrattiCount = Tombola::where('estratto', true)->count();
103
+        $estrattiCount = $tabellone->count();
73 104
         $remaining = 90 - $estrattiCount;
74 105
 
75 106
         if ($request->expectsJson() || $request->ajax()) {
@@ -85,8 +116,13 @@ class TombolaController extends Controller
85 116
         return redirect()->route('tombola.tabellone')->with('success', 'Tombola estratta');
86 117
     }
87 118
 
88
-    public function estratti(Request $request){
89
-        $estratti = Tombola::where('estratto', true)->orderBy('estratto_at', 'desc')->get();
119
+    public function estratti(Request $request, $attivita_id){
120
+        $attivita = Attivita::find($attivita_id);
121
+        if(!$attivita){
122
+            return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
123
+        }
124
+        $tabellone = Tombola::where('attivita_id', $attivita_id);
125
+        $estratti = $tabellone->where('estratto', true)->orderBy('estratto_at', 'desc')->get();
90 126
 
91 127
         if ($request->expectsJson() || $request->ajax()) {
92 128
             $ultimo = $estratti->first();
@@ -111,8 +147,15 @@ class TombolaController extends Controller
111 147
         return view('tombola.cliente.estratti', ['estratti' => $estratti]);
112 148
     }
113 149
 
114
-    public function azzera(Request $request){
115
-        Tombola::query()->update([
150
+    public function azzera(Request $request, $attivita_id){
151
+        if(Auth::user()->can('delete-tombola') && Attivita::find($attivita_id)->user_id == Auth::user()->id){
152
+            return redirect()->route('tombola.index')->with('error', 'Non hai permesso di azzerare la tombola.');
153
+        }
154
+        $attivita = Attivita::find($attivita_id);
155
+        if(!$attivita){
156
+            return redirect()->route('tombola.index')->with('error', 'Attivita non trovata.');
157
+        }
158
+        Tombola::where('attivita_id', $attivita_id)->update([
116 159
             'estratto' => false,
117 160
             'estratto_at' => null,
118 161
         ]);

+ 5
- 1
app/Http/Controllers/UserController.php Näytä tiedosto

@@ -78,7 +78,11 @@ class UserController extends Controller implements HasMiddleware
78 78
               break;
79 79
             }
80 80
           }
81
-          return $editor->process($request);
81
+          if($request->action == 'remove' && (array_key_first($request->data) == Auth::user()->id) && Auth::user()->hasRole('superadmin')){
82
+            // dd('ok');
83
+            return response()->json(['error' => 'Non puoi eliminare te stesso se sei superadmin!' , 'success' => false , 'class' => 'alert-danger'], 400);
84
+          }
85
+          return $editor->process($request->data);
82 86
         }
83 87
 
84 88
 

+ 10
- 0
app/Http/Controllers/VoucherController.php Näytä tiedosto

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use Illuminate\Http\Request;
6
+
7
+class VoucherController extends Controller
8
+{
9
+    //
10
+}

+ 8
- 1
app/Models/AbstractModels/AbstractAttivita.php Näytä tiedosto

@@ -48,6 +48,7 @@ abstract class AbstractAttivita extends \Illuminate\Foundation\Auth\User
48 48
         'path_icon' => 'string',
49 49
         'path_image' => 'string',
50 50
         'slug' => 'string',
51
+        'user_id' => 'integer',
51 52
         'created_at' => 'datetime',
52 53
         'updated_at' => 'datetime'
53 54
     ];
@@ -70,7 +71,8 @@ abstract class AbstractAttivita extends \Illuminate\Foundation\Auth\User
70 71
         'path_logo',
71 72
         'path_icon',
72 73
         'path_image',
73
-        'slug',
74
+        'slug', 
75
+        'user_id',
74 76
         'created_at',
75 77
         'updated_at'
76 78
     ];
@@ -124,4 +126,9 @@ abstract class AbstractAttivita extends \Illuminate\Foundation\Auth\User
124 126
     {
125 127
         return $this->hasMany('\App\Models\Dispositivo', 'attivita_id', 'id')->where('tipo', \App\Models\Dispositivo::STAMPANTE);
126 128
     }
129
+
130
+    public function metodo_pagamento()
131
+    {
132
+        return $this->hasMany('\App\Models\MetodoPagamento', 'attivita_id', 'id');
133
+    }
127 134
 }

+ 6
- 0
app/Models/AbstractModels/AbstractMetodoPagamento.php Näytä tiedosto

@@ -36,6 +36,7 @@ abstract class AbstractMetodoPagamento extends \Illuminate\Foundation\Auth\User
36 36
      */
37 37
     protected $casts = [
38 38
         'id' => 'integer',  
39
+        'attivita_id' => 'integer',
39 40
         'nome' => 'string',
40 41
         'descrizione' => 'string',
41 42
         'is_attivo' => 'boolean',
@@ -55,6 +56,7 @@ abstract class AbstractMetodoPagamento extends \Illuminate\Foundation\Auth\User
55 56
      */
56 57
     protected $fillable = [
57 58
         'id',
59
+        'attivita_id',
58 60
         'nome',
59 61
         'descrizione',
60 62
         'is_attivo',
@@ -66,6 +68,10 @@ abstract class AbstractMetodoPagamento extends \Illuminate\Foundation\Auth\User
66 68
         'info',
67 69
     ];
68 70
     
71
+    public function attivita()
72
+    {
73
+        return $this->belongsTo('\App\Models\Attivita', 'attivita_id', 'id');
74
+    }
69 75
     public function pagamenti()
70 76
     {
71 77
         return $this->hasMany('\App\Models\Pagamento', 'metodo_pagamento_id', 'id');

+ 2
- 6
app/Models/AbstractModels/AbstractUser.php Näytä tiedosto

@@ -81,13 +81,9 @@ abstract class AbstractUser extends \Illuminate\Foundation\Auth\User
81 81
         'updated_at'
82 82
     ];
83 83
     
84
-    public function segnalazioni()
84
+    public function attivita()
85 85
     {
86
-        return $this->hasMany('\App\Models\Segnalazione', 'user_id', 'id');
86
+        return $this->hasMany('\App\Models\Attivita', 'user_id', 'id');
87 87
     }
88 88
     
89
-    public function annotazioni()
90
-    {
91
-        return $this->hasMany('\App\Models\Annotazione', 'user_id', 'id');
92
-    }
93 89
 }

+ 15
- 0
app/Models/Dispositivo.php Näytä tiedosto

@@ -3,6 +3,7 @@
3 3
 namespace App\Models;
4 4
 
5 5
 use Illuminate\Database\Eloquent\Model;
6
+use Illuminate\Support\Facades\Hash;
6 7
 
7 8
 class Dispositivo extends \App\Models\AbstractModels\AbstractDispositivo
8 9
 {
@@ -107,6 +108,20 @@ public function stampante_dispositivo(){
107 108
     return Dispositivo::find($this->url_stampante);
108 109
 }
109 110
 
111
+public static function findByBindingCookieToken(?string $cookieToken): ?self
112
+{
113
+    if (!$cookieToken) {
114
+        return null;
115
+    }
116
+
117
+    return self::query()
118
+        ->whereNotNull('binding_token')
119
+        ->get()
120
+        ->first(function (self $dispositivo) use ($cookieToken) {
121
+            return Hash::check((string) $dispositivo->binding_token, $cookieToken);
122
+        });
123
+}
124
+
110 125
 public function cucine()
111 126
 {
112 127
     return $this->belongsToMany('\App\Models\Cucina', 'dispositivo_has_cucina', 'dispositivo_id', 'cucina_id');

+ 4
- 0
app/Models/User.php Näytä tiedosto

@@ -29,4 +29,8 @@ class User extends \App\Models\AbstractModels\AbstractUser
29 29
     }
30 30
     return $this->cognome." ".$this->nome;
31 31
   }
32
+
33
+  public function fullName(){
34
+    return $this->cognome." ".$this->nome;
35
+  }
32 36
 }

+ 10
- 0
app/Models/Voucher.php Näytä tiedosto

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use Illuminate\Database\Eloquent\Model;
6
+
7
+class Voucher extends Model
8
+{
9
+    //
10
+}

+ 24
- 0
app/Services/Paga/Contanti.php Näytä tiedosto

@@ -0,0 +1,24 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use App\Models\Pagamento;
7
+use Illuminate\Support\Facades\Http;
8
+use Illuminate\Support\Facades\Log;
9
+
10
+class Contanti
11
+{
12
+    public function __construct(){
13
+
14
+    }
15
+
16
+    public function paga($pagamento){
17
+        $pagamento->stato = Pagamento::PAGATO;
18
+        $pagamento->save();
19
+        return [
20
+            'result' => true,
21
+            'message' => 'Pagamento con contanti registrato.',
22
+        ];
23
+    }
24
+}

+ 37
- 0
app/Services/Paga/Cupon.php Näytä tiedosto

@@ -0,0 +1,37 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use App\Models\Pagamento;
7
+use App\Models\Ordine;
8
+use App\Models\Voucher;
9
+use Illuminate\Support\Facades\Http;
10
+use Illuminate\Support\Facades\Log;
11
+
12
+class Cupon
13
+{
14
+    
15
+    public function __construct(){
16
+
17
+    }
18
+
19
+    public function paga($pagamento){
20
+        $voucher = Voucher::where('codice', $voucher_codice)->first();
21
+        if($voucher && $voucher->stato == Voucher::DISPONIBILE){
22
+            $voucher->stato = Voucher::USATO;
23
+            $voucher->save();
24
+            $pagamento->stato = Pagamento::PAGATO;
25
+            $pagamento->save();
26
+            return [
27
+                'result' => true,
28
+                'message' => 'Pagamento con cupon registrato.',
29
+            ];
30
+        }else{
31
+            return [
32
+                'result' => false,
33
+                'message' => 'Voucher non trovato.',
34
+            ];
35
+        }
36
+    }
37
+}

+ 24
- 0
app/Services/Paga/Pos.php Näytä tiedosto

@@ -0,0 +1,24 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use App\Models\Pagamento;
7
+use Illuminate\Support\Facades\Http;
8
+use Illuminate\Support\Facades\Log;
9
+
10
+class Pos
11
+{
12
+    public function __construct(){
13
+
14
+    }
15
+
16
+    public function paga($pagamento){
17
+        $pagamento->stato = Pagamento::PAGATO;
18
+        $pagamento->save();
19
+        return [
20
+            'result' => true,
21
+            'message' => 'Pagamento con pos registrato.',
22
+        ];
23
+    }
24
+}

+ 66
- 0
app/Services/Paga/RegistraPagamento.php Näytä tiedosto

@@ -0,0 +1,66 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use App\Models\Ordine;
7
+use App\Models\Pagamento;
8
+use RuntimeException;
9
+use Throwable;
10
+
11
+class RegistraPagamento
12
+{
13
+    /** @var array<string, callable> */
14
+    private array $handlers;
15
+
16
+    public function __construct()
17
+    {
18
+        $this->handlers = [
19
+            MetodoPagamento::CONTANTI => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
20
+                app(Contanti::class)->paga($pagamento),
21
+
22
+            MetodoPagamento::POS => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
23
+                app(Pos::class)->paga($pagamento),
24
+
25
+            MetodoPagamento::SEGRESTA_WALLET => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
26
+                app(SegrestaWallet::class)->registraMovimento(
27
+                    $pagamento,
28
+                    'uscita',
29
+                    (float) $ordine->prezzo,
30
+                    (string) ($context['causale'] ?? ('Pagamento ordine #' . $ordine->id)),
31
+                    $context['tag_id'] ?? null
32
+                ),
33
+        ];
34
+    }
35
+
36
+    public function esegui(Ordine $ordine, Pagamento $pagamento, array $context = []): array
37
+    {
38
+        $tipo = (string) $pagamento->metodo_pagamento->tipo;
39
+
40
+        if (! isset($this->handlers[$tipo])) {
41
+            return ['result' => false, 'message' => 'Metodo pagamento non supportato.'];
42
+        }
43
+
44
+        try {
45
+            $result = ($this->handlers[$tipo])($pagamento, $ordine, $context);
46
+        } catch (Throwable $e) {
47
+            $result = ['result' => false, 'message' => $e->getMessage()];
48
+        }
49
+
50
+        if (($result['result'] ?? false) === true) {
51
+            $pagamento->stato = Pagamento::PAGATO;
52
+            $ordine->stato = Ordine::PAGATO;
53
+        } else {
54
+            $pagamento->stato = Pagamento::ERRORE;
55
+            $ordine->stato = Ordine::CARRELLO;
56
+        }
57
+
58
+        $pagamento->save();
59
+        $ordine->save();
60
+
61
+        return [
62
+            'result' => (bool) ($result['result'] ?? false),
63
+            'message' => (string) ($result['message'] ?? 'Esito pagamento non disponibile.'),
64
+        ];
65
+    }
66
+}

+ 191
- 0
app/Services/Paga/SegrestaWallet.php Näytä tiedosto

@@ -0,0 +1,191 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use Illuminate\Support\Facades\Http;
7
+use Illuminate\Support\Facades\Log;
8
+
9
+class SegrestaWallet
10
+{
11
+    public function __construct(){
12
+
13
+    }
14
+
15
+    private function isUtenteAutenticato(MetodoPagamento $metodo_pagamento){
16
+
17
+        $segrestaWallet = (object) $metodo_pagamento->info;
18
+        $segrestaWallet->url = $metodo_pagamento->path_img;
19
+        $segrestaWallet->email = $metodo_pagamento->key;
20
+        $segrestaWallet->password = $metodo_pagamento->secret;
21
+        $segrestaWallet->user_isAuth = $metodo_pagamento->info['user_isAuth']??false;
22
+        $segrestaWallet->user_id = $metodo_pagamento->info['user_id']??null;
23
+        $segrestaWallet->api_token = $metodo_pagamento->info['api_token']??null;
24
+
25
+        // dd('segrestaWallet' , $segrestaWallet);
26
+
27
+        if($segrestaWallet->user_isAuth && $segrestaWallet->api_token !== null){
28
+            return [
29
+                'success' => true, 
30
+                'message' => 'Utente autenticato', 
31
+                'user_id' => $segrestaWallet->user_id, 
32
+                'api_token' => $segrestaWallet->api_token
33
+            ];
34
+
35
+        }else{
36
+            // dd('segrestaWallet' , $segrestaWallet);
37
+            $url = 'https://'.$segrestaWallet->url.'/api/v2/login';
38
+            try{
39
+            $response = Http::timeout(10)->retry(3)->withHeaders(['Content-Type' => 'application/json'])->post($url, [
40
+                'email' => $segrestaWallet->email,
41
+                'password' => $segrestaWallet->password,
42
+            ]);
43
+            }catch(\Exception $e){
44
+                return [
45
+                    'success' => false,
46
+                    'message' => $e->getMessage(),
47
+                ];
48
+            }
49
+            // dd('response' , $response->json()['result']);
50
+
51
+            if($response->json()['result']){
52
+                
53
+                $segrestaWallet->user_isAuth = true;
54
+                $segrestaWallet->user_id = $response->json()['user']['id']??null;
55
+                $segrestaWallet->api_token = $response->json()['user']['api_token']??null;
56
+
57
+                $metodo_pagamento->update(['info' => [
58
+                    'user_isAuth' => true,
59
+                    'user_id' => $segrestaWallet->user_id,
60
+                    'api_token' => $segrestaWallet->api_token
61
+                ]]);
62
+                $metodo_pagamento->save();
63
+
64
+                return [
65
+                    'success' => true, 
66
+                    'message' => 'Utente autenticato', 
67
+                    'user_id' => $segrestaWallet->user_id, 
68
+                    'api_token' => $segrestaWallet->api_token
69
+                ];
70
+            }elseif($response->json()['result'] === false){
71
+                return ['success' => false, 'message' => $response->json()['message']];
72
+            }
73
+            return ['success' => false, 'message' => 'Errore sconosciuto'];
74
+        }
75
+    }
76
+
77
+
78
+
79
+    public function registraMovimento($pagamento, $tipo_operazione, $importo, $descrizione, $tag_id = null){
80
+        
81
+        $url = 'https://'.$pagamento->metodo_pagamento->path_img.'/api/v2/operazione_bar/registraMovimento';
82
+        
83
+        $segrestaWalletAuth = $this->isUtenteAutenticato($pagamento->metodo_pagamento);
84
+        
85
+        if($segrestaWalletAuth['success'] === false){
86
+            return [
87
+                'result' => false,
88
+                'message' => $segrestaWalletAuth['message'],
89
+            ];
90
+        }
91
+
92
+        if($segrestaWalletAuth['success'] && $segrestaWalletAuth['api_token'] !== null){
93
+            try{
94
+            $response = Http::timeout(10)->retry(3)->withHeaders(['Content-Type' => 'application/json'])->withToken($segrestaWalletAuth['api_token'])->post($url, [
95
+                // 'user_id' => $segrestaWalletAuth['user_id'],
96
+                'tag_id' => $tag_id, // tag_id è il tag NFC letto dal braccialetto del cliente.
97
+                'tipo_operazione' => $tipo_operazione,
98
+                'importo' => $importo,
99
+                'descrizione' => $descrizione,
100
+            ]);
101
+            }catch(\Exception $e){
102
+                return [
103
+                    'result' => false,
104
+                    'message' => $e->getMessage(),
105
+                ];
106
+            }
107
+        
108
+        return [
109
+            'result' => $response->json()['result'],
110
+            'message' => $response->json()['message'],
111
+        ];
112
+        }else{
113
+            return [
114
+                'result' => false,
115
+                'message' => 'Utente non autenticato',
116
+            ];
117
+        }
118
+    }
119
+
120
+
121
+    public function chiE($tag_id){
122
+        if(!$tag_id){
123
+            return [
124
+                'result' => false,
125
+                'message' => 'Tag ID obbligatorio',
126
+            ];
127
+        }
128
+        if(MetodoPagamento::where('tipo', MetodoPagamento::SEGRESTA_WALLET)->where('is_attivo', true)->count() == 1){
129
+            $metodoPagamento = MetodoPagamento::where('tipo', MetodoPagamento::SEGRESTA_WALLET)->where('is_attivo', true)->first();
130
+        }else{
131
+            return [
132
+                'result' => false,
133
+                'message' => 'Metodo Pagamento non trovato',
134
+            ];
135
+        }
136
+
137
+        $url = 'https://'.$metodoPagamento->path_img.'/api/v2/user/chiE';
138
+        $segrestaWalletAuth = $this->isUtenteAutenticato($metodoPagamento);
139
+
140
+
141
+        // dd($segrestaWalletAuth);
142
+
143
+        if($segrestaWalletAuth['success'] === false){
144
+            return [
145
+                'result' => false,
146
+                'message' => $segrestaWalletAuth['message'],
147
+            ];
148
+        }
149
+        if($segrestaWalletAuth['success'] && $segrestaWalletAuth['api_token'] !== null){
150
+            try{
151
+                // dd($url, $segrestaWalletAuth['api_token']);
152
+            $response = Http::timeout(10)
153
+            ->retry(3)
154
+            ->withHeaders(['Content-Type' => 'application/json'])
155
+            ->withToken($segrestaWalletAuth['api_token'])
156
+            ->post($url, [
157
+                'tag_id' => $tag_id,
158
+            ]);
159
+            }catch(\Exception $e){
160
+                return [
161
+                    'result' => false,
162
+                    'message' => $e->getMessage(),
163
+                ];
164
+            }
165
+            return [
166
+                'result' => $response->json()['result'],
167
+                'message' => $response->json()['message'],
168
+            ];
169
+        }
170
+    }
171
+        // public function checkCredito(Request $request){
172
+    //     $url = $this->url.'/api/v2/operazione_bar/checkCredito';
173
+
174
+    //     if($this->user_isAuth && $this->api_token !== null){
175
+    //         $response = Http::post($url, [
176
+    //             'api_token' => $this->api_token,
177
+    //             'user_id' => $this->user_id,
178
+    //             'tag_id' => $request->tag_id,
179
+    //         ]);
180
+    //     }elseif($this->authUser()['success']){
181
+    //         $response = Http::post($url, [
182
+    //             'api_token' => $this->api_token,
183
+    //             'user_id' => $this->user_id,
184
+    //             'tag_id' => $request->tag_id,
185
+    //         ]);
186
+    //     }
187
+
188
+    //     return $response->json();
189
+
190
+    // }
191
+}

+ 17
- 0
app/Services/Paga/Stripe.php Näytä tiedosto

@@ -0,0 +1,17 @@
1
+<?php
2
+
3
+namespace App\Services\Paga;
4
+
5
+use App\Models\MetodoPagamento;
6
+use App\Models\Pagamento;
7
+use Illuminate\Support\Facades\Http;
8
+use Illuminate\Support\Facades\Log;
9
+
10
+class Stripe
11
+{
12
+    public function __construct(){
13
+
14
+    }
15
+
16
+   
17
+}

+ 9
- 9
config/custom.php Näytä tiedosto

@@ -9,12 +9,12 @@ return [
9 9
   'custom' => [
10 10
     'myLayout' => 'vertical', // Layout type: 'vertical' (default), 'horizontal'
11 11
     // 'primaryColor' => '#FF4646', // Set the primary color
12
-    'myTheme' => 'light', // Theme options: 'light' (default), 'dark', 'system'
12
+    'myTheme' => 'system', // Theme options: 'light' (default), 'dark', 'system'
13 13
     'mySkins' => 'default', // Skin options: 'default', 'bordered'
14 14
     'hasSemiDark' => false, // Semi-dark mode: true/false (false by default)
15 15
     'myRTLMode' => false, // Right-to-left (RTL) layout: true/false (false by default)
16
-    'hasCustomizer' => false, // Enable/Disable customizer: true (default) or false
17
-    'displayCustomizer' => false, // Display customizer UI: true (default) or false
16
+    'hasCustomizer' => true, // Enable/Disable customizer: true (default) or false
17
+    'displayCustomizer' => true, // Display customizer UI: true (default) or false
18 18
     'contentLayout' => 'wide', // Layout size: 'compact' (container-xxl) or 'wide' (container-fluid)
19 19
     'navbarType' => 'sticky', // Navbar type: 'sticky', 'static', or 'hidden' (only for vertical layout)
20 20
     'footerFixed' => true, // Footer fixed position: true/false (false by default)
@@ -25,13 +25,13 @@ return [
25 25
     'customizerControls' => [
26 26
       'color', // Enable/Disable color picker in customizer
27 27
       'theme', // Enable/Disable theme selection in customizer
28
-      'skins', // Enable/Disable skin options in customizer
28
+      // 'skins', // Enable/Disable skin options in customizer
29 29
       'semiDark', // Enable/Disable semi-dark mode in customizer
30
-      'layoutCollapsed', // Enable/Disable collapsed layout in customizer
31
-      'layoutNavbarOptions', // Enable/Disable navbar options in customizer
32
-      'headerType', // Enable/Disable header type selection in customizer
33
-      'contentLayout', // Enable/Disable content layout options in customizer
34
-      'rtl' // Enable/Disable RTL layout options in customizer
30
+      // 'layoutCollapsed', // Enable/Disable collapsed layout in customizer
31
+      // 'layoutNavbarOptions', // Enable/Disable navbar options in customizer
32
+      // 'headerType', // Enable/Disable header type selection in customizer
33
+      // 'contentLayout', // Enable/Disable content layout options in customizer
34
+      // 'rtl' // Enable/Disable RTL layout options in customizer
35 35
     ], // List of available customizer controls
36 36
   ],
37 37
 ];

+ 1
- 1
database/migrations/2026_03_25_004544_attivita.php Näytä tiedosto

@@ -36,7 +36,7 @@ return new class extends Migration
36 36
 
37 37
 
38 38
     // Aggiungi il campo attivita_id e la relativa FK a più tabelle
39
-    $gruppoTabelle = ['dispositivo', 'cucina', 'prenotazione', 'evento', 'fornitore', 'piatto', 'bacheca'];
39
+    $gruppoTabelle = ['dispositivo', 'cucina', 'prenotazione', 'evento', 'fornitore', 'piatto', 'bacheca', 'metodo_pagamento', 'categoria_contabile'];
40 40
 
41 41
     foreach ($gruppoTabelle as $nomeTabella) {
42 42
         Schema::table($nomeTabella, function (Blueprint $table) {

+ 1
- 0
database/migrations/2026_03_27_223801_metodo_pagamento.php Näytä tiedosto

@@ -13,6 +13,7 @@ return new class extends Migration
13 13
     {
14 14
         Schema::create('metodo_pagamento', function (Blueprint $table) {
15 15
             $table->id();
16
+            $table->bigInteger('attivita_id')->unsigned()->nullable();
16 17
             $table->string('nome');
17 18
             $table->string('descrizione')->nullable();
18 19
             $table->boolean('is_attivo')->default(true);

+ 1
- 0
database/migrations/2026_05_15_230716_categoria_contabile.php Näytä tiedosto

@@ -13,6 +13,7 @@ return new class extends Migration
13 13
     {
14 14
         Schema::create('categoria_contabile', function (Blueprint $table) {
15 15
             $table->id();
16
+            $table->bigInteger('attivita_id')->unsigned()->nullable();
16 17
             $table->string('nome')->unique();
17 18
             $table->string('descrizione')->nullable();
18 19
             $table->boolean('is_attiva')->default(true);

+ 33
- 0
database/migrations/2026_06_13_170432_voucher.php Näytä tiedosto

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        schema::create('voucher', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->string('codice');
17
+            $table->string('stato');
18
+            $table->decimal('importo', 10, 2);
19
+            $table->bigInteger('attivita_id')->unsigned()->nullable();
20
+            $table->string('Nominativo');
21
+            $table->string('email');
22
+            $table->timestamps();
23
+        });
24
+    }
25
+
26
+    /**
27
+     * Reverse the migrations.
28
+     */
29
+    public function down(): void
30
+    {
31
+        Schema::dropIfExists('voucher');
32
+    }
33
+};

+ 2
- 1
database/seeders/DatabaseSeeder.php Näytä tiedosto

@@ -17,7 +17,8 @@ class DatabaseSeeder extends Seeder
17 17
     $this->call(AdminSeed::class);
18 18
     $this->call(PermissionSeed::class);
19 19
     $this->call(AllergeneSeed::class);
20
-
20
+    $this->call(TombolaSeed::class);
21
+    $this->call(MetodoPagamentoSeed::class);
21 22
     // Per ogni attività: cucine seed + almeno 9 piatti per cucina (anche cucine già esistenti con stessa attività).
22 23
     $this->call(AttivitaCucinaPiattiSeeder::class);
23 24
 

+ 58
- 0
database/seeders/MetodoPagamentoSeed.php Näytä tiedosto

@@ -0,0 +1,58 @@
1
+<?php
2
+
3
+namespace Database\Seeders;
4
+
5
+use Illuminate\Database\Seeder;
6
+use Carbon\Carbon;
7
+use App\Models\MetodoPagamento;
8
+
9
+class MetodoPagamentoSeed extends Seeder
10
+{
11
+  /**
12
+  * Run the database seeds.
13
+  *
14
+  * @return void
15
+  */
16
+  public function run()
17
+  {
18
+    $default =  [
19
+      MetodoPagamento::CONTANTI => [
20
+      'label' => 'Contanti',
21
+      'value' => MetodoPagamento::CONTANTI,
22
+      'icon' => 'bx-money',
23
+  ],
24
+MetodoPagamento::CUPON => [
25
+      'label' => 'Cupon',
26
+      'value' => MetodoPagamento::CUPON,
27
+      'icon' => 'bx-purchase-tag',
28
+  ],
29
+  MetodoPagamento::SEGRESTA_WALLET => [
30
+      'label' => 'Segresta Wallet',
31
+      'value' => MetodoPagamento::SEGRESTA_WALLET,
32
+      'icon' => 'bx-wallet',
33
+  ],
34
+  MetodoPagamento::POS => [
35
+      'label' => 'POS',
36
+      'value' => MetodoPagamento::POS,
37
+      'icon' => 'bx-credit-card',
38
+  ],
39
+];
40
+    foreach ($default as $tipo => $info) {
41
+        $metodoPagamento = MetodoPagamento::firstOrCreate(
42
+            ['tipo' => $info['value']],
43
+            [
44
+                'is_attivo' => true,
45
+                'is_pubblico' => false,
46
+                'nome' => $info['label'] ?? null,
47
+                'descrizione' => $info['label'] ?? null,
48
+                'path_img' => $info['icon'] ?? null,
49
+                'key' => null,
50
+                'secret' => null,
51
+                'tipo' => $info['value'] ?? null,
52
+                'info' => null,
53
+           
54
+            ]
55
+        );
56
+    }
57
+  }
58
+}

+ 8
- 1
database/seeders/PermissionSeed.php Näytä tiedosto

@@ -28,16 +28,23 @@ class PermissionSeed extends Seeder
28 28
         if ($file == '.' || $file == '..' || !preg_match('/\.php/', $file) || !preg_match('/^(?!.*(Has).*$)(......)/xs', $file)) continue;
29 29
         $c = preg_replace('/\Controller.php$/', '', $file);
30 30
         if($c != '') $controllers[] = $c;
31
+
31 32
         $class = '\App\Http\Controllers\\'.$c.'Controller';
33
+
32 34
         if(!isset($class::$permissions)) continue;
33 35
 
34 36
         foreach($class::$permissions as $key => $value){
35 37
           $permission = Permission::firstOrCreate(['name' => $key, 'group' => $class::$permission_group, 'guard_name' => 'web']);
36 38
           $permission->display_name = $value;
37
-          $permission->assignRole(['amministratore', 'superadmin']);
39
+          if($permission->group == 'Utenti'){
40
+            $permission->syncRoles(['superadmin']);
41
+          }else{
42
+            $permission->syncRoles(['amministratore', 'superadmin']);
43
+          }
38 44
           $permission->save();
39 45
         }
40 46
 
41 47
       }
42 48
     }
49
+
43 50
 }

+ 15
- 0
resources/assets/vendor/js/template-customizer.js Näytä tiedosto

@@ -1653,6 +1653,21 @@ TemplateCustomizer.LANGUAGES = {
1653 1653
     content_label: 'Inhalt',
1654 1654
     layout_navbar_label: 'Art der Navigationsleiste',
1655 1655
     direction_label: 'Richtung'
1656
+  },
1657
+  it: {
1658
+    panel_header: 'UX personalizzatore',
1659
+    panel_sub_header: 'Personalizza e visualizza in tempo reale',
1660
+    theming_header: 'personalizzazione',
1661
+    color_label: 'colore primario',
1662
+    theme_label: 'tema',
1663
+    skin_label: 'skin',
1664
+    semiDark_label: 'semi-scuro',
1665
+    layout_header: 'layout',
1666
+    layout_label: 'menu (navigazione)',
1667
+    layout_header_label: 'tipi di intestazione',
1668
+    content_label: 'contenuto',
1669
+    layout_navbar_label: 'tipo di barra di navigazione',
1670
+    direction_label: 'direzione'
1656 1671
   }
1657 1672
 }
1658 1673
 

+ 2
- 0
resources/css/app.css Näytä tiedosto

@@ -36,3 +36,5 @@ tailwind utilities;*/
36 36
 }
37 37
 
38 38
 
39
+
40
+

+ 23
- 0
resources/css/fest-theme.css Näytä tiedosto

@@ -38,3 +38,26 @@
38 38
 .dataTables_wrapper .dt-buttons > button.dt-button:only-child {
39 39
   border-radius: var(--bs-border-radius, 0.375rem);
40 40
 }
41
+
42
+.bx-chef-hat{
43
+  --svg: url("data:image/svg+xml,%3csvg width='24' height='24' fill='currentColor' viewBox='0 0 24 24' transform='' xmlns='http://www.w3.org/2000/svg'%3e%3c!--Boxicons v3.0.8 https://boxicons.com %7c License https://docs.boxicons.com/free--%3e%3cpath d='M17.13 5.54C16.33 3.42 14.32 2 12 2S7.67 3.42 6.87 5.54A5.506 5.506 0 0 0 2 11c0 2.07 1.18 3.95 3 4.88V18c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-2.12c1.82-.93 3-2.81 3-4.88 0-2.82-2.13-5.15-4.87-5.46m.53 8.75c-.4.14-.67.52-.67.94v1.78H7v-1.78c0-.42-.27-.8-.67-.94-1.4-.5-2.33-1.82-2.33-3.28 0-1.93 1.57-3.5 3.42-3.5.04 0 .14.01.18.02.49 0 .9-.31 1-.78.36-1.61 1.76-2.73 3.41-2.73s3.05 1.12 3.41 2.73c.1.47.51.81 1 .78.06 0 .12 0 .09-.01 1.93 0 3.5 1.57 3.5 3.5 0 1.47-.94 2.79-2.33 3.28ZM5 20h14v2H5z'%3e%3c/path%3e%3c/svg%3e");
44
+}
45
+
46
+/* Default desktop */
47
+.text-sm-small {
48
+  /* font-size: 1rem; */
49
+}
50
+
51
+/* Tablet */
52
+@media (max-width: 992px) {
53
+  .text-sm-small {
54
+    font-size: 1rem;
55
+  }
56
+}
57
+
58
+/* Mobile */
59
+@media (max-width: 576px) {
60
+  .text-sm-small {
61
+    font-size: 0.9rem;
62
+  }
63
+}

+ 107
- 81
resources/menu/verticalMenu.json Näytä tiedosto

@@ -44,37 +44,98 @@
44 44
     {
45 45
       "menuHeader": "Consulta"
46 46
     },
47
+    {
48
+      "name": "Eventi",
49
+      "icon": "menu-icon icon-base bx bx-calendar-check",
50
+      "slug": "evento.index",
51
+      "url": "admin/evento",
52
+      "can": "permission:view-evento"
53
+    },
47 54
     {
48 55
       "name": "Ordini",
49 56
       "icon": "menu-icon icon-base bx bx-receipt",
50 57
       "slug": "ordine.index",
51 58
       "url": "admin/ordine",
52
-      "can": "permission:view-ordine"
53
-    },
54
-    {
55
-      "name": "Carrelli aperti",
56
-      "icon": "menu-icon icon-base bx bx-store",
57
-      "slug": "ordine.index",
58
-      "url": "admin/ordine?carrelli_aperti=true",
59
-      "can": "permission:view-ordine"
59
+      "can": "permission:view-ordine",
60
+      "submenu": [
61
+        {
62
+          "name": "Carrelli aperti",
63
+          "icon": "menu-icon icon-base bx bx-store",
64
+          "slug": "ordine.index",
65
+          "url": "admin/ordine?carrelli_aperti=true",
66
+          "can": "permission:view-ordine"
67
+        },
68
+        {
69
+          "name": "Storico",
70
+          "icon": "menu-icon icon-base bx bx-history",
71
+          "slug": "ordine.index",
72
+          "url": "admin/ordine",
73
+          "can": "permission:view-ordine"
74
+        }
75
+      ]
60 76
     },
61 77
     {
62 78
       "name": "Prenotazioni",
63 79
       "icon": "menu-icon icon-base bx bx-calendar",
64 80
       "slug": "prenotazione.index",
65
-      "url": "admin/prenotazione",
66
-      "can": "permission:view-prenotazione"
67
-    },
68
-    {
69
-      "name": "Eventi",
70
-      "icon": "menu-icon icon-base bx bx-calendar-check",
71
-      "slug": "evento.index",
72
-      "url": "admin/evento",
73
-      "can": "permission:view-evento"
81
+      "can": "permission:view-prenotazione",
82
+      "submenu":[
83
+        {
84
+          "name": "Tavolo",
85
+          "icon": "menu-icon icon-base bx bx-calendar",
86
+          "slug": "prenotazione.tavolo.index",
87
+          "url": "admin/prenotazione/tavolo",
88
+          "can": "permission:view-prenotazione-tavolo"
89
+        },
90
+        {
91
+          "name": "Prenotazioni per evento",
92
+          "icon": "menu-icon icon-base bx bx-calendar",
93
+          "slug": "prenotazione.index",
94
+          "url": "admin/prenotazione",
95
+          "can": "permission:view-prenotazione"
96
+        }
97
+      ]
74 98
     },
99
+
75 100
     {
76 101
       "menuHeader": "Gestisci"
77 102
     },
103
+    {
104
+      "name": "Contabilità",
105
+      "icon": "menu-icon icon-base bx bx-chart",
106
+      "slug": "contabilita.index",
107
+      "url": "admin/contabilita",
108
+      "can": "permission:view-contabilita",
109
+      "submenu": [
110
+        {
111
+          "name": "Prima nota",
112
+          "icon": "menu-icon icon-base bx bx-receipt",
113
+          "slug": "prima-nota.index",
114
+          "url": "admin/prima-nota",
115
+          "can": "permission:view-primanota"
116
+        },
117
+        {
118
+          "name": "Pagamenti",
119
+          "icon": "menu-icon icon-base bx bx-money",
120
+          "slug": "pagamento.index",
121
+          "url": "admin/pagamento",
122
+          "can": "permission:view-pagamento"
123
+        },
124
+        {
125
+          "name": "Bilancio",
126
+          "icon": "menu-icon icon-base bx bx-chart",
127
+          "slug": "bilancio.index",
128
+          "url": "admin/bilancio",
129
+          "can": "permission:view-bilancio"
130
+        },
131
+        {
132
+          "name": "Report",
133
+          "icon": "menu-icon icon-base bx bx-file",
134
+          "slug": "report.index",
135
+          "url": "admin/report",
136
+          "can": "permission:view-report"
137
+        }
138
+        ]},
78 139
     {
79 140
       "name": "Dispositivi",
80 141
       "icon": "menu-icon icon-base bx bx-devices",
@@ -164,42 +225,6 @@
164 225
         }
165 226
       ]
166 227
     },
167
-    {
168
-      "name": "Contabilità",
169
-      "icon": "menu-icon icon-base bx bx-chart",
170
-      "slug": "contabilita.index",
171
-      "url": "admin/contabilita",
172
-      "can": "permission:view-contabilita",
173
-      "submenu": [
174
-        {
175
-          "name": "Prima nota",
176
-          "icon": "menu-icon icon-base bx bx-receipt",
177
-          "slug": "primanota.index",
178
-          "url": "admin/primanota",
179
-          "can": "permission:view-primanota"
180
-        },
181
-        {
182
-          "name": "Pagamenti",
183
-          "icon": "menu-icon icon-base bx bx-money",
184
-          "slug": "pagamento.index",
185
-          "url": "admin/pagamento",
186
-          "can": "permission:view-pagamento"
187
-        },
188
-        {
189
-          "name": "Bilancio",
190
-          "icon": "menu-icon icon-base bx bx-chart",
191
-          "slug": "bilancio.index",
192
-          "url": "admin/bilancio",
193
-          "can": "permission:view-bilancio"
194
-        },
195
-        {
196
-          "name": "Report",
197
-          "icon": "menu-icon icon-base bx bx-file",
198
-          "slug": "report.index",
199
-          "url": "admin/report",
200
-          "can": "permission:view-report"
201
-        }
202
-        ]},
203 228
         {
204 229
       "menuHeader": "Amministra"
205 230
     },
@@ -209,20 +234,6 @@
209 234
       "slug": "attivita.index",
210 235
       "url": "admin/attivita"
211 236
     },
212
-    {
213
-      "name": "Users",
214
-      "icon": "menu-icon icon-base bx bx-user",
215
-      "slug": "user.index",
216
-      "url": "admin/user",
217
-      "can": "role:superadmin"
218
-    },
219
-    {
220
-      "name": "Ruoli e Permessi",
221
-      "icon": "menu-icon icon-base bx bx-check-shield",
222
-      "slug": "role",
223
-      "url": "admin/role",
224
-      "can": "role:superadmin"
225
-    },
226 237
     {
227 238
       "name": "Configurazioni",
228 239
       "icon": "menu-icon icon-base bx bx-cog",
@@ -237,13 +248,6 @@
237 248
           "url": "admin/allergene",
238 249
           "can": "permission:view-allergene"
239 250
         },
240
-        {
241
-          "name": "Categorie contabili",
242
-          "icon": "menu-icon icon-base bx bx-category",
243
-          "slug": "categoria_contabile.index",
244
-          "url": "admin/categoria-contabile",
245
-          "can": "permission:view-categoria_contabile"
246
-        },
247 251
         {
248 252
           "name": "Cucine",
249 253
           "icon": "menu-icon icon-base bx bx-chef-hat",
@@ -251,19 +255,19 @@
251 255
           "url": "admin/cucina",
252 256
           "can": "permission:view-cucina"
253 257
         },
258
+        {
259
+          "name": "Categorie contabili",
260
+          "icon": "menu-icon icon-base bx bx-category",
261
+          "slug": "categoria_contabile.index",
262
+          "url": "admin/categoria-contabile",
263
+          "can": "permission:view-categoria_contabile"
264
+        },
254 265
         {
255 266
           "name": "Fornitori",
256 267
           "icon": "menu-icon icon-base bx bxs-truck",
257 268
           "slug": "fornitore.index",
258 269
           "url": "admin/fornitore",
259 270
           "can": "permission:view-fornitore"
260
-        },  
261
-        {
262
-          "name": "Operatori",
263
-          "icon": "menu-icon icon-base bx bx-user",
264
-          "slug": "operatore.index",
265
-          "url": "admin/operatore",
266
-          "can": "permission:view-operatore"
267 271
         },
268 272
         {
269 273
           "name": "Metodi di pagamento",
@@ -271,6 +275,13 @@
271 275
           "slug": "metodo_pagamento.index",
272 276
           "url": "admin/metodo-pagamento",
273 277
           "can": "permission:view-metodo_pagamento"
278
+        },  
279
+        {
280
+          "name": "Operatori",
281
+          "icon": "menu-icon icon-base bx bx-user",
282
+          "slug": "operatore.index",
283
+          "url": "admin/operatore",
284
+          "can": "permission:view-operatore"
274 285
         },
275 286
         {
276 287
           "name": "Piatti",
@@ -288,6 +299,21 @@
288 299
         }
289 300
       ]
290 301
 
302
+    },
303
+    {
304
+      "name": "Organizzazioni",
305
+      "icon": "menu-icon icon-base bx bx-building",
306
+      "slug": "user.index",
307
+      "url": "admin/user",
308
+      "can": "role:superadmin"
309
+    },
310
+    {
311
+      "name": "Ruoli e Permessi",
312
+      "icon": "menu-icon icon-base bx bx-check-shield",
313
+      "slug": "role",
314
+      "url": "admin/role",
315
+      "can": "role:superadmin"
291 316
     }
317
+    
292 318
   ]
293 319
 }

+ 25
- 0
resources/views/_partials/badge.blade.php Näytä tiedosto

@@ -0,0 +1,25 @@
1
+@if(isset($success))
2
+<span class="px-3 py-1 alert alert-success ms-2">
3
+    {{ $success }}
4
+</span>
5
+@endif
6
+@if(isset($error))
7
+<span class="px-3 py-1 alert alert-danger ms-2">
8
+    {{ $error }}
9
+</span>
10
+@endif
11
+@if(isset($warning))
12
+<span class="px-3 py-1 alert alert-warning ms-2">
13
+    {{ $warning }}
14
+</span>
15
+@endif
16
+@if(isset($info))
17
+<span class="px-3 py-1 alert alert-info ms-2">
18
+    {{ $info }}
19
+</span>
20
+@endif
21
+@if(isset($dark))
22
+<span class="px-3 py-1 alert alert-dark ms-2">
23
+    {{ $dark }}
24
+</span>
25
+@endif

+ 16
- 1
resources/views/allergene/index.blade.php Näytä tiedosto

@@ -37,7 +37,22 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1">Allergeni</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4">
41
+    <i class="bx bx-error-circle d-none d-md-inline-flex d-lg-inline-flex"></i> 
42
+    Allergeni
43
+  </h4>
44
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45
+            <ol class="breadcrumb breadcrumb-custom-icon">
46
+      
47
+              <li class="breadcrumb-item">
48
+                <a href="#">Configurazioni</a>
49
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
50
+              </li>
51
+              <li class="breadcrumb-item active text-primary">
52
+                <a href="{{ route('allergene.index') }}">Allergeni</a>
53
+              </li>
54
+            </ol>
55
+          </nav>
41 56
 </div>
42 57
 @endsection
43 58
 

+ 6
- 3
resources/views/attivita/_partials/parziali.blade.php Näytä tiedosto

@@ -1,10 +1,13 @@
1 1
 @switch($oggetto)
2 2
 
3 3
 @case('seleziona_attivita')
4
-
5
-    <button class="btn btn-primary" >
6
-        <i class="bx bx-log-in-circle" ></i>
4
+<form action="{{ route('attivita.select', ['attivita_id' => $entity->id]) }}" method="POST">
5
+    @csrf
6
+    <button type="submit" class="btn btn-primary">
7
+        <i class="bx bx-check-circle" ></i>
8
+        <span>Seleziona attività</span>
7 9
     </button>
10
+</form>
8 11
 
9 12
 @break
10 13
 

+ 14
- 2
resources/views/attivita/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-aperture"></i> Attività</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-aperture d-none d-md-inline-flex d-lg-inline-flex"></i> Attività</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('attivita.index') }}">Attività</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 15
- 2
resources/views/bacheca/index.blade.php Näytä tiedosto

@@ -38,8 +38,21 @@ $configData = Helper::appClasses();
38 38
 
39 39
 @section('pageTitle')
40 40
 <div class="d-flex flex-column">
41
-  <h4 class="mb-1"> 
42
-    <i class="bx bx-book"></i> Bacheche 
41
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
42
+    <i class="bx bx-book d-none d-md-inline-flex d-lg-inline-flex"></i> Bacheche
43
+    </h4>
44
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45
+            <ol class="breadcrumb breadcrumb-custom-icon">
46
+      
47
+              <li class="breadcrumb-item">
48
+                <a href="#">Configurazioni</a>
49
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
50
+              </li>
51
+              <li class="breadcrumb-item active text-primary">
52
+                <a href="{{ route('bacheca.index') }}">Bacheche</a>
53
+              </li>
54
+            </ol>
55
+          </nav>
43 56
 </div>
44 57
 @endsection
45 58
 

+ 15
- 2
resources/views/bilancio/index.blade.php Näytä tiedosto

@@ -40,9 +40,22 @@ $configData = Helper::appClasses();
40 40
 
41 41
 @section('pageTitle')
42 42
 <div class="d-flex flex-column">
43
-  <h4 class="mb-1">
44
-    <i class="bx bx-chart"></i> Bilancio annuale
43
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4">
44
+    <i class="bx bx-chart d-none d-md-inline-flex d-lg-inline-flex"></i> Bilancio annuale
45 45
   </h4>
46
+  
47
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
48
+            <ol class="breadcrumb breadcrumb-custom-icon">
49
+      
50
+              <li class="breadcrumb-item">
51
+                <a href="#">Configurazioni</a>
52
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
53
+              </li>
54
+              <li class="breadcrumb-item active text-primary">
55
+                <a href="{{ route('bilancio.index') }}">Bilancio annuale</a>
56
+              </li>
57
+            </ol>
58
+          </nav>
46 59
 </div>
47 60
 @endsection
48 61
 

+ 15
- 2
resources/views/categoria_contabile/index.blade.php Näytä tiedosto

@@ -37,9 +37,22 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1">
41
-    <i class="bx bx-category"></i> Categorie contabili
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4">
41
+    <i class="bx bx-category d-none d-md-inline-flex d-lg-inline-flex"></i> Categorie contabili
42 42
   </h4>
43
+
44
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45
+            <ol class="breadcrumb breadcrumb-custom-icon">
46
+      
47
+              <li class="breadcrumb-item">
48
+                <a href="#">Configurazioni</a>
49
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
50
+              </li>
51
+              <li class="breadcrumb-item active text-primary">
52
+                <a href="{{ route('categoria-contabile.index') }}">Categorie contabili</a>
53
+              </li>
54
+            </ol>
55
+          </nav>
43 56
 </div>
44 57
 @endsection
45 58
 

+ 14
- 2
resources/views/contenuto_bacheca/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-clipboard"></i> Contenuti Bacheca</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-clipboard d-none d-md-inline-flex d-lg-inline-flex"></i> Contenuti Bacheca</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('contenuto-bacheca.index') }}">Contenuti Bacheca</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 14
- 2
resources/views/cucina/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-chef-hat"></i> Cucine</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-chef-hat d-none d-md-inline-flex d-lg-inline-flex"></i> Cucine</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('cucina.index') }}">Cucine</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 3
- 3
resources/views/dashboard/index.blade.php Näytä tiedosto

@@ -39,9 +39,9 @@ $configData = Helper::appClasses();
39 39
 
40 40
 @section('pageTitle')
41 41
 <div class="d-flex flex-column">
42
-  <h4 class="mb-1"> 
43
-    <i class="bx bx-home-smile"></i> Dashboard
44
-    <span class="text-muted fs-6 fw-normal text-primary"> di {{ \App\Models\Attivita::find(session()->get('attivita_attuale'))->nome }}</span>
42
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
43
+    <i class="bx bx-home-smile d-none d-md-inline-flex d-lg-inline-flex"></i> Dashboard
44
+    <!-- <span class="text-muted fs-6 fw-normal text-primary d-none d-md-inline-flex d-lg-inline-flex"> di {{ \App\Models\Attivita::find(session()->get('attivita_attuale'))->nome }}</span> -->
45 45
   </h4>
46 46
 </div>
47 47
 @endsection

+ 19
- 2
resources/views/endpoint/index.blade.php Näytä tiedosto

@@ -38,8 +38,25 @@ $configData = Helper::appClasses();
38 38
 
39 39
 @section('pageTitle')
40 40
 <div class="d-flex flex-column">
41
-  <h4 class="mb-1"> 
42
-    <i class="bx bx-server"></i> Endpoint <span class="text-muted text-primary fs-6 fw-normal"> di {{ Attivita::find(session()->get('attivita_attuale'))->nome }}</span></h4>
41
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
42
+    <i class="bx bx-server d-none d-md-inline-flex d-lg-inline-flex"></i>
43
+     Endpoint 
44
+     <span class="text-muted text-primary fs-6 fw-normal d-none d-md-inline-flex d-lg-inline-flex"> di {{ Attivita::find(session()->get('attivita_attuale'))->nome }}</span>
45
+     </h4>
46
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
47
+            <ol class="breadcrumb breadcrumb-custom-icon">
48
+      
49
+              <li class="breadcrumb-item">
50
+                <a href="#">Configurazioni</a>
51
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
52
+              </li>
53
+              <li class="breadcrumb-item">
54
+                <a href="#">Stampa</a>
55
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
56
+              </li>
57
+              <li class="breadcrumb-item active text-primary">
58
+                <a href="{{ route('endpoint.index') }}">Endpoint</a>
59
+              </li>
43 60
 </div>
44 61
 @endsection
45 62
 

+ 14
- 2
resources/views/evento/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-calendar-check"></i> Eventi</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-calendar-check d-none d-md-inline-flex d-lg-inline-flex"></i> Eventi</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('evento.index') }}">Eventi</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 14
- 2
resources/views/fornitore/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bxs-truck"></i> Fornitori</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bxs-truck d-none d-md-inline-flex d-lg-inline-flex"></i> Fornitori</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('fornitore.index') }}">Fornitori</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 2
- 2
resources/views/layouts/sections/menu/verticalMenu.blade.php Näytä tiedosto

@@ -4,14 +4,14 @@ use Illuminate\Support\Facades\Session;
4 4
 $configData = Helper::appClasses();
5 5
 @endphp
6 6
 
7
-@section('style')
7
+<!-- @section('style')
8 8
 
9 9
 <style>
10 10
 .bx-chef-hat{
11 11
   --svg: url("data:image/svg+xml,%3csvg width='24' height='24' fill='currentColor' viewBox='0 0 24 24' transform='' xmlns='http://www.w3.org/2000/svg'%3e%3c!--Boxicons v3.0.8 https://boxicons.com %7c License https://docs.boxicons.com/free--%3e%3cpath d='M17.13 5.54C16.33 3.42 14.32 2 12 2S7.67 3.42 6.87 5.54A5.506 5.506 0 0 0 2 11c0 2.07 1.18 3.95 3 4.88V18c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-2.12c1.82-.93 3-2.81 3-4.88 0-2.82-2.13-5.15-4.87-5.46m.53 8.75c-.4.14-.67.52-.67.94v1.78H7v-1.78c0-.42-.27-.8-.67-.94-1.4-.5-2.33-1.82-2.33-3.28 0-1.93 1.57-3.5 3.42-3.5.04 0 .14.01.18.02.49 0 .9-.31 1-.78.36-1.61 1.76-2.73 3.41-2.73s3.05 1.12 3.41 2.73c.1.47.51.81 1 .78.06 0 .12 0 .09-.01 1.93 0 3.5 1.57 3.5 3.5 0 1.47-.94 2.79-2.33 3.28ZM5 20h14v2H5z'%3e%3c/path%3e%3c/svg%3e");
12 12
 }
13 13
 </style>
14
-@endsection
14
+@endsection -->
15 15
 
16 16
 <aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme"
17 17
     @foreach ($configData['menuAttributes'] as $attribute => $value)

+ 26
- 4
resources/views/layouts/sections/navbar/navbar-partial.blade.php Näytä tiedosto

@@ -359,6 +359,21 @@ class="layout-menu-toggle navbar-nav align-items-xl-center me-4 me-xl-0{{ isset(
359 359
                                       </ul>
360 360
                                     </li> --}}
361 361
                                     <!--/ Notification -->
362
+
363
+                                    <!-- Accedi a punto vendita se in Session -->
364
+                                    @if(\Illuminate\Support\Facades\Cookie::has('binding_token'))
365
+                                    <?php
366
+                                    $binding_token = \Illuminate\Support\Facades\Cookie::get('binding_token');
367
+                                    $puntoVendita = \App\Models\Dispositivo::findByBindingCookieToken($binding_token);
368
+                                    ?>
369
+                               
370
+                                    <a href="{{ route('punto-vendita.show', ['punto_vendita_id' => $puntoVendita->id]) }}" class="mx-5 btn text-bg-primary px-2 py-1">
371
+                                      Torna a {{ $puntoVendita->nome }}
372
+                                      <i class="bx bx-arrow-back rotate-180 float-end"></i>
373
+                                    </a>
374
+                                    @endif
375
+                                    <!-- END - Accedi a punto vendita se in Session -->
376
+
362 377
                                     <!-- Attività -->
363 378
                                     @if(session()->has('attivita_attuale') && session()->get('attivita_attuale') != null && session()->get('attivita_attuale') != 0)
364 379
                                     <li class="d-none d-lg-flex nav-item navbar-dropdown dropdown-user dropdown mx-12">
@@ -368,16 +383,23 @@ class="layout-menu-toggle navbar-nav align-items-xl-center me-4 me-xl-0{{ isset(
368 383
                                         <span class="fw-semibold text-primary text-uppercase"> 
369 384
                                           {{ \App\Models\Attivita::find(session()->get('attivita_attuale'))->nome }}
370 385
                                         </span>
386
+                                      </a>
371 387
                                         @else
372 388
                                         <!-- Attività non selezionata -->
373 389
                                         @endif
374
-                                      </a>
375 390
                                       <ul class="dropdown-menu dropdown-menu-end">
391
+                                        @foreach(Auth::user()->attivita as $attivita)
376 392
                                         <li>
377
-                                          <a class="dropdown-item" href="{{ route('attivita.index') }}">
378
-                                            <i class="bx bx-aperture bx-md me-3"></i><span>Cambia attività</span>
379
-                                          </a>
393
+                                          <form action="{{ route('attivita.select', ['attivita_id' => $attivita->id]) }}" method="POST">
394
+                                            @csrf
395
+
396
+                                            <button type="submit" class="dropdown-item">
397
+                                              <span>{{ $attivita->nome }}</span>
398
+                                              <i class="bx bx-arrow-back rotate-180 text-primary"></i>
399
+                                            </button>
400
+                                          </form>
380 401
                                         </li>
402
+                                        @endforeach
381 403
                                       </ul>
382 404
                                     </li>
383 405
                                     <!--/ Attività -->

+ 16
- 2
resources/views/metodo_pagamento/index.blade.php Näytä tiedosto

@@ -37,8 +37,22 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-credit-card"></i> Metodi di pagamento</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-credit-card d-none d-md-inline-flex d-lg-inline-flex"></i> Metodi di pagamento</h4>
42
+
43
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
44
+            <ol class="breadcrumb breadcrumb-custom-icon">
45
+      
46
+              <li class="breadcrumb-item" >
47
+                <a href="#">Configurazioni</a>
48
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
49
+              </li>
50
+              <li class="breadcrumb-item active text-primary">
51
+                <a href="{{ route('metodo-pagamento.index') }}">Metodi di pagamento</a>
52
+              </li>
53
+            </ol>
54
+          </nav>
55
+
42 56
 </div>
43 57
 @endsection
44 58
 

+ 3
- 3
resources/views/monitor/index.blade.php Näytä tiedosto

@@ -37,11 +37,11 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-0 mt-4"> 
41
-    <i class="bx bx-tv"></i> 
40
+  <h4 class="mb-0 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-tv d-none d-md-inline-flex d-lg-inline-flex"></i> 
42 42
     Monitor
43 43
   </h4>
44
-  <nav aria-label="breadcrumb" style="font-size: smaller;">
44
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45 45
             <ol class="breadcrumb breadcrumb-custom-icon">
46 46
               <li class="breadcrumb-item">
47 47
                 <a href="{{-- route('home') --}}">Home</a>

+ 3
- 3
resources/views/operatore/index.blade.php Näytä tiedosto

@@ -37,11 +37,11 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-0 mt-4"> 
41
-    <i class="bx bx-user"></i> 
40
+  <h4 class="mb-0 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-user d-none d-md-inline-flex d-lg-inline-flex"></i> 
42 42
     Operatori
43 43
   </h4>
44
-  <nav aria-label="breadcrumb" style="font-size: smaller;">
44
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45 45
             <ol class="breadcrumb breadcrumb-custom-icon">
46 46
       
47 47
               <li class="breadcrumb-item">

+ 16
- 3
resources/views/ordine/index.blade.php Näytä tiedosto

@@ -37,12 +37,25 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41 41
     @if(request()->get('carrelli_aperti'))
42
-      <i class="bx bx-cart"></i> Carrelli aperti
42
+      <i class="bx bx-cart d-none d-md-inline-flex d-lg-inline-flex"></i> Carrelli aperti
43 43
     @else
44
-      <i class="bx bx-receipt"></i> Ordini
44
+      <i class="bx bx-receipt d-none d-md-inline-flex d-lg-inline-flex"></i> Storico Ordini
45 45
     @endif
46
+</h4>
47
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
48
+            <ol class="breadcrumb breadcrumb-custom-icon">
49
+      
50
+              <li class="breadcrumb-item">
51
+                <a href="#">Configurazioni</a>
52
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
53
+              </li>
54
+              <li class="breadcrumb-item active text-primary">
55
+                <a href="{{ route('ordine.index') }}">Storico Ordini</a>
56
+              </li>
57
+            </ol>
58
+          </nav>
46 59
 </div>
47 60
 @endsection
48 61
 

+ 14
- 2
resources/views/pagamento/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-money"></i> Pagamenti</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-money d-none d-md-inline-flex d-lg-inline-flex"></i> Pagamenti</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('pagamento.index') }}">Pagamenti</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 19
- 5
resources/views/piatto/index.blade.php Näytä tiedosto

@@ -39,15 +39,29 @@ $configData = Helper::appClasses();
39 39
 
40 40
 @section('pageTitle')
41 41
 <div class="d-flex flex-column">
42
-  <h4 class="mb-1">
43
-    <i class="bx bx-dish"></i> Piatti
44
-  <!-- </h4> -->
45
-  <!-- <span class="text-muted"> -->
42
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4">
43
+    <i class="bx bx-dish d-none d-md-inline-flex d-lg-inline-flex"></i> Piatti
46 44
     @if(request()->get('cucina_id'))
47 45
        della cucina <strong class="text-primary">{{ Cucina::find(request()->get('cucina_id'))->nome }}</strong>
48 46
     @endif
49
-  <!-- </span> -->
50 47
   </h4>
48
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
49
+            <ol class="breadcrumb breadcrumb-custom-icon">
50
+      
51
+              <li class="breadcrumb-item">
52
+                <a href="#">Configurazioni</a>
53
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
54
+              </li>
55
+              <li class="breadcrumb-item active text-primary">
56
+                <a href="{{ route('piatto.index') }}">Piatti</a>
57
+              </li>
58
+              @if(request()->get('cucina_id'))
59
+              <li class="breadcrumb-item active text-primary">
60
+                <a href="{{ route('piatto.index', ['cucina_id' => request()->get('cucina_id')]) }}">{{ Cucina::find(request()->get('cucina_id'))->nome }}</a>
61
+              </li>
62
+              @endif
63
+            </ol>
64
+          </nav>
51 65
 </div>
52 66
 @endsection
53 67
 

+ 3
- 3
resources/views/prenotazione/index.blade.php Näytä tiedosto

@@ -37,8 +37,8 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-0 mt-4"> 
41
-    <i class="bx bx-calendar"></i> 
40
+  <h4 class="mb-0 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-calendar d-none d-md-inline-flex d-lg-inline-flex"></i> 
42 42
     Prenotazioni
43 43
     @if(isset($evento))
44 44
     <a href="{{ route('evento.show', $evento->id) }}" class="text-success">
@@ -47,7 +47,7 @@ $configData = Helper::appClasses();
47 47
     @endif
48 48
     
49 49
   </h4>
50
-  <nav aria-label="breadcrumb" style="font-size: smaller;">
50
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
51 51
             <ol class="breadcrumb breadcrumb-custom-icon">
52 52
               @if(!isset($evento))
53 53
               <li class="breadcrumb-item">

+ 14
- 2
resources/views/prima_nota/index.blade.php Näytä tiedosto

@@ -35,8 +35,20 @@ use Illuminate\Support\Facades\Auth;
35 35
 
36 36
 @section('pageTitle')
37 37
 <div class="d-flex flex-column">
38
-  <h4 class="mb-1"> 
39
-    <i class="bx bx-receipt"></i> Prima Nota</h4>
38
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
39
+    <i class="bx bx-receipt d-none d-md-inline-flex d-lg-inline-flex"></i> Prima Nota</h4>
40
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
41
+            <ol class="breadcrumb breadcrumb-custom-icon">
42
+      
43
+              <li class="breadcrumb-item">
44
+                <a href="#">Configurazioni</a>
45
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
46
+              </li>
47
+              <li class="breadcrumb-item active text-primary">
48
+                <a href="{{ route('prima-nota.index') }}">Prima Nota</a>
49
+              </li>
50
+            </ol>
51
+          </nav>
40 52
 </div>
41 53
 @endsection
42 54
 

+ 14
- 2
resources/views/print_job/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-printer"></i> Code di stampa</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-printer d-none d-md-inline-flex d-lg-inline-flex"></i> Code di stampa</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Dispositivi</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('code-stampa.index') }}">Code di stampa</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 14
- 2
resources/views/punto_operatore/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-user"></i> Punti Operatore</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-user d-none d-md-inline-flex d-lg-inline-flex"></i> Punti Operatore</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Dispositivi</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('punto-operatore.index') }}">Punti Operatore</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 172
- 3
resources/views/punto_vendita/cassa/_partials/carrello/pagamento/checkout.blade.php Näytä tiedosto

@@ -16,6 +16,8 @@ $nRighe = $ordine ? $ordine->righe_ordine->count() : 0;
16 16
         <input type="hidden" name="ordine_id" value="{{ $ordine->id }}">
17 17
         <input type="hidden" name="dispositivo_id" value="{{ $dispositivo->id }}">
18 18
         <input type="hidden" name="attivita_id" value="{{ $attivita->id }}">
19
+        <input type="hidden" name="tag_id" id="tag_id" value="">
20
+
19 21
 <div class="card px-2 px-sm-3 border-0 shadow-none bg-transparent">
20 22
   <div class="row g-0">
21 23
     <div class="col-lg-7 card-body border-end border-secondary border-opacity-10 p-md-6 p-3">
@@ -37,10 +39,16 @@ $nRighe = $ordine ? $ordine->righe_ordine->count() : 0;
37 39
                 <label class="form-check-label custom-option-content form-check-input-payment d-flex gap-3 gap-md-4 align-items-center" for="metodoPagamento{{ $metodo->id }}">
38 40
                   <input
39 41
                     name="metodo_pagamento_id"
40
-                    class="form-check-input"
42
+                    id="metodoPagamento{{ $metodo->id }}"
43
+
41 44
                     type="radio"
42 45
                     value="{{ $metodo->id }}"
43
-                    id="metodoPagamento{{ $metodo->id }}"
46
+                    @if($metodo->tipo == MetodoPagamento::SEGRESTA_WALLET)
47
+                      class="form-check-input segrestaWalletInput"
48
+                      data-tipo="{{ MetodoPagamento::SEGRESTA_WALLET }}"
49
+                    @else
50
+                      class="form-check-input"
51
+                      @endif
44 52
                     {{ $loop->first ? 'checked' : '' }}
45 53
                   />
46 54
                   <span class="custom-option-body d-flex align-items-center">
@@ -55,8 +63,14 @@ $nRighe = $ordine ? $ordine->righe_ordine->count() : 0;
55 63
                         <span class="d-block small text-muted fw-normal mt-1">{{ Str::limit($metodo->descrizione, 80) }}</span>
56 64
                       @endif
57 65
                     </span>
66
+
58 67
                   </span>
59 68
                 </label>
69
+                @if($metodo->tipo == MetodoPagamento::SEGRESTA_WALLET)
70
+                  <span class="badge text-wrap small text-muted fw-normal mt-1" id="segrestaWalletAlertToScan" style="display: none;">
71
+                    Scansiona un braccialetto NFC valido per pagare con Segresta Wallet.
72
+                  </span>
73
+                @endif
60 74
               </div>
61 75
             </div>
62 76
           @endforeach
@@ -118,6 +132,9 @@ $nRighe = $ordine ? $ordine->righe_ordine->count() : 0;
118 132
           </button>
119 133
 
120 134
         </div>
135
+        <p class="mt-6 mb-0 small text-muted" id="segrestaWalletChiE" style="display: none;">
136
+        </p>
137
+
121 138
         <p class="mt-6 mb-0 small text-muted">
122 139
           Confermando, registri il pagamento secondo il metodo selezionato. Verifica sempre l’importo in cassa.
123 140
         </p>
@@ -127,4 +144,156 @@ $nRighe = $ordine ? $ordine->righe_ordine->count() : 0;
127 144
 </div>
128 145
 
129 146
 
130
-</form>
147
+</form>
148
+
149
+<script>
150
+$(document).ready(function(){
151
+    $('input[name="metodo_pagamento_id"]').on('change', function(){
152
+
153
+      checkUX($(this));
154
+  });
155
+});
156
+
157
+function checkUX(input){
158
+  $('input[name="metodo_pagamento_id"]').parents('div.form-check').removeClass('checked');
159
+  input.parents('div.form-check').addClass('checked');
160
+      // 
161
+
162
+
163
+      if(input.data('tipo') == "{{ MetodoPagamento::SEGRESTA_WALLET }}"){
164
+        $('#segrestaWalletAlertToScan').show();
165
+        $('button[type="submit"]').prop('disabled', true);
166
+        scanningNfcRequest();
167
+      
168
+    }else{
169
+      $('#segrestaWalletAlertToScan').hide();
170
+      $('button[type="submit"]').prop('disabled', false);
171
+      ;
172
+    }
173
+  
174
+}
175
+
176
+function chiE(tag_id){
177
+  var response = null;
178
+  $.ajax({
179
+    url: "{{ route('metodo-pagamento.segresta-wallet.chiE') }}",
180
+    type: 'POST',
181
+    data: { 
182
+      tag_id: tag_id,
183
+      _token: "{{ csrf_token() }}"
184
+    },
185
+    success: function(response){
186
+      if(response.success){
187
+        $('#segrestaWalletChiE').show().text(response.message);
188
+      }else{
189
+        $('#segrestaWalletChiE').show().text(response.message);
190
+      }
191
+    }
192
+  });
193
+}
194
+
195
+/////////////////////// spostato in INDEX
196
+// let nfcAbortController = null;
197
+
198
+// function stopNfcScan() {
199
+//   if (nfcAbortController) {
200
+//     try { nfcAbortController.abort(); } catch (e) {}
201
+//     nfcAbortController = null;
202
+//   }
203
+// }
204
+
205
+// function scanningNfcRequest() {
206
+//   const $status = $('#segrestaWalletAlertToScan');
207
+//   const $submit = $('button[type="submit"]');
208
+//   const $tag = $('#tag_id');
209
+
210
+//   stopNfcScan();
211
+//   $tag.val('');
212
+//   $submit.prop('disabled', true);
213
+
214
+//   if (!('NDEFReader' in window)) {
215
+//     $status
216
+//       .show()
217
+//       .removeClass('alert-warning alert-success')
218
+//       .addClass('alert-danger')
219
+//       .text('NFC non supportato su questo dispositivo/browser.');
220
+//       ///
221
+//     $status
222
+//       .show()
223
+//       .removeClass('alert-warning alert-success')
224
+//       .addClass('alert-danger')
225
+//       .text('NFC non supportato da questo dispositivo/browser. Inserisci manualmente il codice del braccialetto.');
226
+
227
+//     // Prompt manuale tramite prompt JS
228
+//     const manualTag = prompt('NFC non disponibile. Inserisci manualmente il codice del braccialetto/tag per pagare con Segresta Wallet:');
229
+//     if (manualTag && manualTag.trim() !== '') {
230
+//       $tag.val(manualTag.trim());
231
+//       $status
232
+//         .removeClass('alert-danger alert-warning')
233
+//         .addClass('alert-success')
234
+//         .text('Codice braccialetto inserito manualmente: ' + manualTag + '. Puoi confermare il pagamento.');
235
+//       $submit.prop('disabled', false);
236
+//     } else {
237
+//       $status
238
+//         .removeClass('alert-success alert-warning')
239
+//         .addClass('alert-danger')
240
+//         .text('Inserimento del codice del braccialetto annullato o non valido.');
241
+//       $submit.prop('disabled', true);
242
+//     }
243
+//     /////
244
+//     return;
245
+//   }
246
+
247
+//   nfcAbortController = new AbortController();
248
+//   const reader = new NDEFReader();
249
+
250
+//   reader.scan({ signal: nfcAbortController.signal })
251
+//     .then(() => {
252
+//       $status
253
+//         .show()
254
+//         .removeClass('alert-danger alert-success')
255
+//         .addClass('alert-warning')
256
+//         .text('Lettore NFC attivo: avvicina il braccialetto.');
257
+
258
+//       reader.onreading = (event) => {
259
+//         const tagId = event.serialNumber || '';
260
+
261
+//         if (!tagId) {
262
+//           $status
263
+//             .removeClass('alert-warning alert-success')
264
+//             .addClass('alert-danger')
265
+//             .text('Tag letto ma seriale non disponibile. Riprova.');
266
+//           $submit.prop('disabled', true);
267
+//           return;
268
+//         }
269
+
270
+//         $tag.val(tagId);
271
+//         $status
272
+//           .removeClass('alert-warning alert-danger')
273
+//           .addClass('alert-success')
274
+//           .text('Braccialetto letto: ' + tagId + '. Puoi confermare il pagamento.');
275
+//         $submit.prop('disabled', false);
276
+
277
+//         // opzionale: una lettura basta
278
+//         stopNfcScan();
279
+//       };
280
+
281
+//       reader.onerror = () => {
282
+//         $status
283
+//           .removeClass('alert-warning alert-success')
284
+//           .addClass('alert-danger')
285
+//           .text('Errore durante la lettura NFC. Riprova.');
286
+//         $submit.prop('disabled', true);
287
+//       };
288
+//     })
289
+//     .catch((err) => {
290
+//       if (err?.name === 'AbortError') return;
291
+//       $status
292
+//         .show()
293
+//         .removeClass('alert-warning alert-success')
294
+//         .addClass('alert-danger')
295
+//         .text('Impossibile avviare NFC: ' + (err?.message || 'errore sconosciuto'));
296
+//       $submit.prop('disabled', true);
297
+//     });
298
+// }
299
+</script>

+ 10
- 2
resources/views/punto_vendita/cassa/_partials/scripts.blade.php Näytä tiedosto

@@ -1,3 +1,6 @@
1
+
2
+{{ $dataTable_rigaordine->scripts(attributes: ['type' => 'module']) }}
3
+
1 4
 <script>
2 5
 const initialOrdineId = Number("{{ $ordine->id ?? 0 }}") || null;
3 6
 let currentOrdineId = initialOrdineId;
@@ -6,7 +9,7 @@ function getOrdineId() {
6 9
     return currentOrdineId ?? initialOrdineId;
7 10
 }
8 11
 
9
-        document.querySelectorAll('.piatto-card, .cassa-piatto-card').forEach(function (card) {
12
+        document.querySelectorAll('.piatto-card, .cassa-piatto-card, .cassa-sb-product').forEach(function (card) {
10 13
             card.addEventListener('click', function () {
11 14
                 const piattoId = card.getAttribute('data-piatto-id');
12 15
             aumentaQuantita(piattoId);
@@ -272,7 +275,12 @@ function azzeraCarrelloAjax() {
272 275
     aggiornaTotaleCarrello();
273 276
     $(".dt-empty").text("Carrello vuoto");
274 277
         $('.mb-6 .card').addClass('shadow-none');
275
-    $('.mb-6').removeClass('mb-6');    
278
+    $('.mb-6').removeClass('mb-6');
279
+
280
+    @if(isset($vista) && $vista == 'catalogo')
281
+      $('table').removeClass('datatable table dt-inline');
282
+    @endif
283
+
276 284
 }
277 285
 
278 286
   function aggiornaTotaleCarrello() {

+ 123
- 6
resources/views/punto_vendita/cassa/index.blade.php Näytä tiedosto

@@ -140,25 +140,35 @@ $cucine = $cucine ?? collect();
140 140
       </h4>
141 141
     </div>    
142 142
     
143
-    <div class="col-4">
143
+    <div class="align-content-center col-4 gap-x-2">
144 144
       @if(Auth::guard('operatore')->check())
145
-      <a href="{{ route('operatore.dashDispositivi') }}" class="btn btn-primary">
145
+      <a href="{{ route('operatore.dashDispositivi') }}" class="ms-2 px-3 py-1 alert text-bg-primary"> <!-- btn btn-primary -->
146 146
         <i class="bx bx-category"></i>
147 147
         Dashboard
148 148
       </a>
149 149
       @elseif(Auth::guard('web')->check())
150
-      <a href="{{ route('dashboard') }}" class="btn btn-primary">
150
+      <a href="{{ route('dashboard') }}" class="ms-2 px-3 py-1 alert text-bg-secondary"> <!-- btn btn-primary -->
151 151
         <i class="bx bx-category"></i>
152 152
         Dashboard
153 153
       </a>
154
+      
155
+      <a href="{{ route('profile.show') }}" class="ms-2 px-3 py-1 alert text-bg-secondary"> <!-- btn btn-primary -->
156
+        <i class="bx bx-user-circle mx-1"></i>
157
+        {{ Auth::user()->fullName()}}
158
+      </a>
154 159
       @endif
155 160
 
156
-      <a href="#" class="btn btn-primary">{{ Auth::user()->username}}</a>
157 161
       @if($punto_vendita->binding_token)
158
-        <span class="alert alert-success ms-2"> 
162
+        <span class="px-3 py-1 alert alert-success ms-2"> 
163
+          <i class="bx bx-link"></i>
159 164
           Linked
160 165
         </span>
161 166
       @endif
167
+
168
+      <a href="{{ route('punto-vendita.show', ['punto_vendita_id' => $punto_vendita->id , 'vista' => 'catalogo']) }}" class="ms-2 px-3 py-1 alert text-bg-primary"> <!-- btn btn-primary -->
169
+        <i class="bx bx-list-ul mx-1"></i>
170
+        vista catalogo
171
+      </a>
162 172
       <!-- <span class="badge badge-info">{{ $punto_vendita->binding_token }}</span> -->
163 173
     </div>
164 174
     
@@ -237,7 +247,6 @@ $cucine = $cucine ?? collect();
237 247
 @section('page-script')
238 248
 
239 249
 
240
-{{ $dataTable_rigaordine->scripts(attributes: ['type' => 'module']) }}
241 250
 <script>
242 251
 
243 252
     
@@ -289,6 +298,114 @@ $cucine = $cucine ?? collect();
289 298
       }
290 299
     });
291 300
   }
301
+
302
+
303
+  
304
+let nfcAbortController = null;
305
+
306
+function stopNfcScan() {
307
+  if (nfcAbortController) {
308
+    try { nfcAbortController.abort(); } catch (e) {}
309
+    nfcAbortController = null;
310
+  }
311
+}
312
+
313
+function scanningNfcRequest() {
314
+  const $status = $('#segrestaWalletAlertToScan');
315
+  const $submit = $('button[type="submit"]');
316
+  const $tag = $('#tag_id');
317
+
318
+  stopNfcScan();
319
+  $tag.val('');
320
+  $submit.prop('disabled', true);
321
+
322
+  if (!('NDEFReader' in window)) {
323
+    $status
324
+      .show()
325
+      .removeClass('alert-warning alert-success')
326
+      .addClass('alert-danger')
327
+      .text('NFC non supportato su questo dispositivo/browser.');
328
+      ///
329
+    $status
330
+      .show()
331
+      .removeClass('alert-warning alert-success')
332
+      .addClass('alert-danger')
333
+      .text('NFC non supportato da questo dispositivo/browser. Inserisci manualmente il codice del braccialetto.');
334
+
335
+    // Prompt manuale tramite prompt JS
336
+    const manualTag = prompt('NFC non disponibile. Inserisci manualmente il codice del braccialetto/tag per pagare con Segresta Wallet:');
337
+    if (manualTag && manualTag.trim() !== '') {
338
+      $tag.val(manualTag.trim());
339
+
340
+      var chiEResponse = chiE(manualTag);
341
+      $status
342
+        .removeClass('alert-danger alert-warning')
343
+        .addClass('alert-success')
344
+        .text('Codice braccialetto inserito manualmente: ' + manualTag + '. Puoi confermare il pagamento.\n' + chiEResponse);
345
+      $submit.prop('disabled', false);
346
+    } else {
347
+      $status
348
+        .removeClass('alert-success alert-warning')
349
+        .addClass('alert-danger')
350
+        .text('Inserimento del codice del braccialetto annullato o non valido.');
351
+      $submit.prop('disabled', true);
352
+    }
353
+    /////
354
+    return;
355
+  }
356
+
357
+  nfcAbortController = new AbortController();
358
+  const reader = new NDEFReader();
359
+
360
+  reader.scan({ signal: nfcAbortController.signal })
361
+    .then(() => {
362
+      $status
363
+        .show()
364
+        .removeClass('alert-danger alert-success')
365
+        .addClass('alert-warning')
366
+        .text('Lettore NFC attivo: avvicina il braccialetto.');
367
+
368
+      reader.onreading = (event) => {
369
+        const tagId = event.serialNumber || '';
370
+
371
+        if (!tagId) {
372
+          $status
373
+            .removeClass('alert-warning alert-success')
374
+            .addClass('alert-danger')
375
+            .text('Tag letto ma seriale non disponibile. Riprova.');
376
+          $submit.prop('disabled', true);
377
+          return;
378
+        }
379
+
380
+        $tag.val(tagId);
381
+        $status
382
+          .removeClass('alert-warning alert-danger')
383
+          .addClass('alert-success')
384
+          .text('Braccialetto letto: ' + tagId + '. Puoi confermare il pagamento.');
385
+        $submit.prop('disabled', false);
386
+
387
+        // opzionale: una lettura basta
388
+        stopNfcScan();
389
+      };
390
+
391
+      reader.onerror = () => {
392
+        $status
393
+          .removeClass('alert-warning alert-success')
394
+          .addClass('alert-danger')
395
+          .text('Errore durante la lettura NFC. Riprova.');
396
+        $submit.prop('disabled', true);
397
+      };
398
+    })
399
+    .catch((err) => {
400
+      if (err?.name === 'AbortError') return;
401
+      $status
402
+        .show()
403
+        .removeClass('alert-warning alert-success')
404
+        .addClass('alert-danger')
405
+        .text('Impossibile avviare NFC: ' + (err?.message || 'errore sconosciuto'));
406
+      $submit.prop('disabled', true);
407
+    });
408
+}
292 409
 </script>
293 410
 
294 411
 @include('punto_vendita.cassa._partials.scripts')

+ 0
- 758
resources/views/punto_vendita/cassa/vista2.blade.php Näytä tiedosto

@@ -1,758 +0,0 @@
1
-<?php
2
-use Illuminate\Support\Facades\Auth;
3
-?>
4
-
5
-@php
6
-  $cucine = ($cucine ?? collect())
7
-    ->sortBy(fn ($cucina) => mb_strtolower((string) ($cucina->nome ?? ''), 'UTF-8'))
8
-    ->values();
9
-
10
-  $righeOrdine = $ordine->righe_ordine ?? collect();
11
-  $righeIniziali = $righeOrdine->map(function ($riga) {
12
-    return [
13
-      'id' => (string) ($riga->piatto_id ?? $riga->id),
14
-      'title' => (string) ($riga->piatto->nome ?? ('Riga #' . $riga->id)),
15
-      'price' => (float) ($riga->prezzo ?? 0),
16
-      'qty' => (int) ($riga->quantita ?? 1),
17
-    ];
18
-  })->values();
19
-@endphp
20
-
21
-@extends('layouts/blankLayout')
22
-
23
-@section('title', 'Cassa - Vista 2')
24
-
25
-@section('content')
26
-<style>
27
-  .cassa-sb-wrapper {
28
-    height: 100dvh;
29
-    padding: .75rem;
30
-    background: #eef3fa;
31
-    overflow: hidden;
32
-  }
33
-  .cassa-sb-topbar {
34
-    height: 3rem;
35
-    background: #fff;
36
-    border: 1px solid #dbe4f3;
37
-    border-radius: 12px;
38
-    padding: .3rem .6rem;
39
-    margin-bottom: .45rem;
40
-    display: flex;
41
-    align-items: center;
42
-    justify-content: space-between;
43
-    gap: .75rem;
44
-  }
45
-  .cassa-sb-layout {
46
-    height: calc(100dvh - 4.2rem);
47
-    min-height: 0;
48
-    display: grid;
49
-    grid-template-columns: minmax(0, 1.7fr) 360px;
50
-    gap: .65rem;
51
-  }
52
-  .cassa-sb-panel {
53
-    min-height: 0;
54
-    background: #fff;
55
-    border: 1px solid #dbe4f3;
56
-    border-radius: 12px;
57
-    overflow: hidden;
58
-  }
59
-  .cassa-sb-catalog {
60
-    display: grid;
61
-    grid-template-columns: 170px minmax(0, 1fr);
62
-    min-height: 0;
63
-  }
64
-  .cassa-sb-sidebar {
65
-    min-height: 0;
66
-    border-right: 1px solid #e8edf8;
67
-    padding: .4rem;
68
-    display: grid;
69
-    grid-template-rows: auto minmax(0, 1fr) auto;
70
-    gap: .35rem;
71
-  }
72
-  .cassa-sb-side-title {
73
-    font-size: .68rem;
74
-    text-transform: uppercase;
75
-    letter-spacing: .04em;
76
-    color: #74829b;
77
-    font-weight: 800;
78
-    margin: 0;
79
-  }
80
-  .cassa-sb-kitchens {
81
-    min-height: 0;
82
-    display: grid;
83
-    grid-template-rows: repeat(10, minmax(0, 1fr));
84
-    gap: .28rem;
85
-  }
86
-  .cassa-sb-kitchen-btn {
87
-    min-height: 0;
88
-    border: 1px solid #d7e0ef;
89
-    border-radius: 8px;
90
-    /* background: #f6f9ff; */
91
-    text-align: left;
92
-    padding: 1em;
93
-    font-weight: 800;
94
-    color: #4b5c77;
95
-    display: grid;
96
-    align-content: center;
97
-    line-height: .95rem;
98
-    font-size: 1.1rem;
99
-  }
100
-  .cassa-sb-kitchen-label {
101
-    white-space: nowrap;
102
-    text-overflow: ellipsis;
103
-    overflow: hidden;
104
-    font-weight: 800;
105
-  }
106
-  .cassa-sb-kitchen-count {
107
-    font-size: .64rem;
108
-    color: #7a889f;
109
-    margin-top: .06rem;
110
-    font-weight: 700;
111
-  }
112
-  .cassa-sb-kitchen-btn.is-active .cassa-sb-kitchen-count {
113
-    color: #dbe6ff;
114
-  }
115
-  .cassa-sb-kitchen-btn.is-active {
116
-    background: #315fc9;
117
-    border-color: #315fc9;
118
-    color: #fff;
119
-  }
120
-  .cassa-sb-side-pager {
121
-    display: grid;
122
-    grid-template-columns: 1fr auto 1fr;
123
-    gap: .3rem;
124
-    align-items: center;
125
-  }
126
-  .cassa-sb-side-pager button {
127
-    height: 30px;
128
-    border: 1px solid #d5dfef;
129
-    border-radius: 8px;
130
-    background: #f4f8ff;
131
-    font-weight: 800;
132
-    color: #4a5a75;
133
-  }
134
-  .cassa-sb-side-pager span {
135
-    font-size: .78rem;
136
-    color: #6f7f98;
137
-    font-weight: 800;
138
-    min-width: 52px;
139
-    text-align: center;
140
-  }
141
-  .cassa-sb-main {
142
-    min-height: 0;
143
-    display: grid;
144
-    grid-template-rows: auto minmax(0, 1fr);
145
-  }
146
-  .cassa-sb-main-head {
147
-    border-bottom: 1px solid #e8edf8;
148
-    padding: .35rem .4rem;
149
-    display: grid;
150
-    grid-template-columns: minmax(0, 1fr) auto auto;
151
-    gap: .35rem;
152
-    align-items: center;
153
-  }
154
-  .cassa-sb-selected-kitchen {
155
-    font-size: .74rem;
156
-    color: #5f6f8b;
157
-    border: 1px solid #d7e1f1;
158
-    border-radius: 8px;
159
-    padding: .38rem .5rem;
160
-    background: #f8fbff;
161
-    white-space: nowrap;
162
-  }
163
-  .cassa-sb-search {
164
-    height: 34px;
165
-    border: 1px solid #d5dfef;
166
-    border-radius: 8px;
167
-    padding: 0 .55rem;
168
-    font-size: .86rem;
169
-  }
170
-  .cassa-sb-main-pager {
171
-    display: inline-flex;
172
-    gap: .35rem;
173
-    align-items: center;
174
-  }
175
-  .cassa-sb-main-pager button {
176
-    min-width: 52px;
177
-    height: 34px;
178
-    border: 1px solid #d5dfef;
179
-    border-radius: 7px;
180
-    background: #f4f8ff;
181
-    font-weight: 800;
182
-    color: #4a5a75;
183
-  }
184
-  .cassa-sb-main-pager span {
185
-    min-width: 48px;
186
-    font-size: .74rem;
187
-    color: #6f7f98;
188
-    font-weight: 800;
189
-    text-align: center;
190
-  }
191
-  .cassa-sb-products-wrap {
192
-    min-height: 0;
193
-    padding: .35rem;
194
-  }
195
-  .cassa-sb-products {
196
-    /* height: 100%; */
197
-    min-height: 0;
198
-    display: grid;
199
-    grid-template-columns: repeat(5, minmax(0, 1fr));
200
-    grid-template-rows: repeat(4, minmax(0, 1fr));
201
-    gap: .3rem;
202
-  }
203
-  .cassa-sb-product {
204
-    min-height: 0;
205
-    border: 1px solid #d9e2f2;
206
-    border-radius: 8px;
207
-    background: #fff;
208
-    padding: .3rem;
209
-    display: flex;
210
-    flex-direction: column;
211
-    justify-content: flex-start;
212
-    cursor: pointer;
213
-  }
214
-  .cassa-sb-product:active { transform: scale(.99); }
215
-  .cassa-sb-product:hover { border-color: #93afe4; }
216
-  .cassa-sb-product-title {
217
-    font-size: .8rem;
218
-    font-weight: 900;
219
-    color: #2f3d58;
220
-    line-height: .92rem;
221
-    display: -webkit-box;
222
-    -webkit-line-clamp: 2;
223
-    -webkit-box-orient: vertical;
224
-    overflow: hidden;
225
-  }
226
-  .cassa-sb-product-sub {
227
-    font-size: .64rem;
228
-    color: #7b889f;
229
-    margin-top: .12rem;
230
-  }
231
-  .cassa-sb-product-price {
232
-    margin-top: .18rem;
233
-    font-size: .8rem;
234
-    color: #315fc9;
235
-    font-weight: 900;
236
-  }
237
-  .cassa-sb-placeholder {
238
-    border: 1px dashed #d7e0f1;
239
-    border-radius: 12px;
240
-    background: #f8fbff;
241
-    opacity: .75;
242
-  }
243
-  .cassa-sb-cart {
244
-    display: grid;
245
-    grid-template-rows: auto minmax(0, 1fr) auto;
246
-    min-height: 0;
247
-  }
248
-  .cassa-sb-cart-head {
249
-    border-bottom: 1px solid #e9eef8;
250
-    padding: .42rem .48rem;
251
-    display: flex;
252
-    justify-content: space-between;
253
-    align-items: center;
254
-    gap: .45rem;
255
-  }
256
-  .cassa-sb-cart-list {
257
-    min-height: 0;
258
-    padding: .35rem;
259
-    display: grid;
260
-    grid-template-rows: repeat(6, minmax(0, 1fr));
261
-    gap: .28rem;
262
-  }
263
-  .cassa-sb-cart-row {
264
-    border: 1px solid #dce6f6;
265
-    border-radius: 8px;
266
-    padding: .26rem .34rem;
267
-    display: grid;
268
-    grid-template-columns: minmax(0, 1fr) auto;
269
-    gap: .4rem;
270
-    min-height: 0;
271
-  }
272
-  .cassa-sb-cart-name {
273
-    font-size: .78rem;
274
-    font-weight: 900;
275
-    color: #2f3d58;
276
-    line-height: .92rem;
277
-    display: -webkit-box;
278
-    -webkit-line-clamp: 1;
279
-    -webkit-box-orient: vertical;
280
-    overflow: hidden;
281
-  }
282
-  .cassa-sb-cart-meta {
283
-    font-size: .64rem;
284
-    color: #6f7f98;
285
-  }
286
-  .cassa-sb-qty {
287
-    display: inline-flex;
288
-    align-items: center;
289
-    border: 1px solid #d4deef;
290
-    border-radius: 8px;
291
-    overflow: hidden;
292
-    height: 24px;
293
-  }
294
-  .cassa-sb-qty button {
295
-    width: 22px;
296
-    border: 0;
297
-    background: #f4f7fc;
298
-    font-weight: 800;
299
-  }
300
-  .cassa-sb-qty span {
301
-    min-width: 22px;
302
-    text-align: center;
303
-    font-size: .7rem;
304
-    font-weight: 800;
305
-  }
306
-  .cassa-sb-footer {
307
-    border-top: 1px solid #e9eef8;
308
-    padding: .35rem;
309
-    display: grid;
310
-    gap: .28rem;
311
-  }
312
-  .cassa-sb-total {
313
-    border: 1px solid #d8e4fa;
314
-    background: #f3f7ff;
315
-    border-radius: 8px;
316
-    padding: .32rem .38rem;
317
-    display: flex;
318
-    align-items: center;
319
-    justify-content: space-between;
320
-  }
321
-  .cassa-sb-total-value {
322
-    font-size: 1.02rem;
323
-    font-weight: 900;
324
-    color: #2f56b5;
325
-  }
326
-  .cassa-sb-pay-grid {
327
-    display: grid;
328
-    grid-template-columns: 1fr 1fr;
329
-    gap: .22rem;
330
-  }
331
-  .cassa-sb-pay-grid button {
332
-    min-height: 40px;
333
-    border-radius: 8px;
334
-    border: 1px solid #d5dfef;
335
-    font-weight: 900;
336
-  }
337
-  .cassa-sb-main-btn {
338
-    background: #315fc9;
339
-    border-color: #315fc9 !important;
340
-    color: #fff;
341
-  }
342
-  .cassa-sb-cash-btn {
343
-    background: #ebf8ef;
344
-    color: #1f8b56;
345
-  }
346
-  .cassa-sb-card-btn {
347
-    background: #ecf2ff;
348
-    color: #2f56b5;
349
-  }
350
-  .cassa-sb-clear-btn {
351
-    background: #fff2f2;
352
-    color: #c23a3a;
353
-  }
354
-  @media (max-width: 1400px) {
355
-    .cassa-sb-layout { grid-template-columns: minmax(0, 1fr) 320px; }
356
-    .cassa-sb-catalog { grid-template-columns: 155px minmax(0, 1fr); }
357
-    .cassa-sb-kitchens { grid-template-rows: repeat(10, minmax(0, 1fr)); }
358
-    .cassa-sb-products { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-rows: repeat(5, minmax(0, 1fr)); }
359
-  }
360
-</style>
361
-
362
-<div class="cassa-sb-wrapper">
363
-  <div class="cassa-sb-topbar">
364
-    <div class="d-flex align-items-center">
365
-      <h5 class="mb-0">
366
-        {{ $punto_vendita->nome ?? 'Cassa' }}
367
-        <span class="text-muted fs-6">| Ordine #{{ $ordine->id ?? '-' }}</span>
368
-      </h5>
369
-      <!-- <small class="text-muted">Sidebar cucine + catalogo compatto</small> -->
370
-    </div>
371
-    <div>
372
-      @if(Auth::guard('operatore')->check())
373
-        <a href="{{ route('operatore.dashDispositivi') }}" class="btn btn-sm btn-outline-primary">Dashboard</a>
374
-      @elseif(Auth::guard('web')->check())
375
-        <a href="{{ route('dashboard') }}" class="btn btn-sm btn-outline-primary">Dashboard</a>
376
-      @endif
377
-    </div>
378
-  </div>
379
-
380
-  <div class="cassa-sb-layout">
381
-    <section class="cassa-sb-panel cassa-sb-catalog">
382
-      <aside class="cassa-sb-sidebar">
383
-        <p class="cassa-sb-side-title">Cucine</p>
384
-        <div class="cassa-sb-kitchens" id="kitchen-list">
385
-          @foreach($cucine as $cucina)
386
-
387
-          <?php
388
-            // Calcolo il migliore contrasto (bianco o nero) dato un colore di background in $hexColor
389
-            $bgColore = $cucina->info['colore'] ?? '#808080';
390
-
391
-            // Rimuovo il carattere '#' se presente
392
-            $strippedHex = ltrim($bgColore, '#');
393
-            // Espando formato breve (#abc -> #aabbcc)
394
-            if(strlen($strippedHex) == 3) {
395
-              $r = hexdec(str_repeat($strippedHex[0], 2));
396
-              $g = hexdec(str_repeat($strippedHex[1], 2));
397
-              $b = hexdec(str_repeat($strippedHex[2], 2));
398
-            } else {
399
-              $r = hexdec(substr($strippedHex,0,2));
400
-              $g = hexdec(substr($strippedHex,2,2));
401
-              $b = hexdec(substr($strippedHex,4,2));
402
-            }
403
-            // Calcolo luminanza percepita del colore
404
-            $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
405
-            // Soglia: se luminanza alta, uso testo scuro, altrimenti bianco
406
-            $textColor = $luminance > 0.6 ? '#222' : '#fff';
407
-          ?>
408
-
409
-            <button
410
-              type="button"
411
-              class="cassa-sb-kitchen-btn"
412
-
413
-              style="background-color: {{ $bgColore }}; color: {{ $textColor }};"
414
-              data-kitchen-tab
415
-              data-kitchen-id="{{ $cucina->id }}"
416
-              data-kitchen-name="{{ mb_strtolower((string) ($cucina->nome ?? ''), 'UTF-8') }}"
417
-
418
-            >
419
-              <span class="cassa-sb-kitchen-label">{{ $cucina->nome }}</span>
420
-              <span class="cassa-sb-kitchen-count">{{ ($cucina->piatti ?? collect())->count() }} piatti</span>
421
-            </button>
422
-          @endforeach
423
-        </div>
424
-        <div class="cassa-sb-side-pager">
425
-          <button type="button" id="kitchen-prev">Prec</button>
426
-          <span id="kitchen-status">1 / 1</span>
427
-          <button type="button" id="kitchen-next">Next</button>
428
-        </div>
429
-      </aside>
430
-
431
-      <div class="cassa-sb-main">
432
-        <div class="cassa-sb-main-head">
433
-          <input id="product-search" type="text" class="cassa-sb-search" placeholder="Cerca piatto nella cucina selezionata">
434
-          <div class="cassa-sb-selected-kitchen" id="selected-kitchen-label">Tutte</div>
435
-          <div class="cassa-sb-main-pager">
436
-            <button type="button" id="product-prev">Prec</button>
437
-            <span id="product-status">1 / 1</span>
438
-            <button type="button" id="product-next">Next</button>
439
-          </div>
440
-        </div>
441
-        <div class="cassa-sb-products-wrap">
442
-          <div class="cassa-sb-products" id="product-grid">
443
-            @foreach($cucine as $cucina)
444
-              @foreach(($cucina->piatti ?? collect()) as $piatto)
445
-                <article
446
-                  class="cassa-sb-product"
447
-                  data-product-item
448
-                  data-kitchen-id="{{ $cucina->id }}"
449
-                  data-name="{{ mb_strtolower((string) ($piatto->nome ?? ''), 'UTF-8') }}"
450
-                  data-id="{{ $piatto->id }}"
451
-                  data-title="{{ $piatto->nome }}"
452
-                  data-price="{{ (float) ($piatto->prezzo ?? 0) }}"
453
-                >
454
-                  <div>
455
-                    <div class="cassa-sb-product-title">{{ $piatto->nome }}</div>
456
-                    <div class="cassa-sb-product-sub">{{ $cucina->nome }}</div>
457
-                  </div>
458
-                  <div class="cassa-sb-product-price">EUR {{ number_format((float) ($piatto->prezzo ?? 0), 2, ',', '.') }}</div>
459
-                </article>
460
-              @endforeach
461
-            @endforeach
462
-          </div>
463
-        </div>
464
-      </div>
465
-    </section>
466
-
467
-    <aside class="cassa-sb-panel cassa-sb-cart">
468
-      <div class="cassa-sb-cart-head">
469
-        <div>
470
-          <strong>Carrello</strong>
471
-          <span class="badge bg-label-primary ms-1" id="cart-badge">0 articoli</span>
472
-        </div>
473
-        <div class="cassa-sb-main-pager">
474
-          <button type="button" id="cart-prev">Prec</button>
475
-          <span id="cart-status">1 / 1</span>
476
-          <button type="button" id="cart-next">Next</button>
477
-        </div>
478
-      </div>
479
-
480
-      <div class="cassa-sb-cart-list" id="cart-list">
481
-        <div class="text-muted small">Nessun articolo selezionato.</div>
482
-      </div>
483
-
484
-      <div class="cassa-sb-footer">
485
-        <div class="cassa-sb-total">
486
-          <span class="fw-semibold">Totale</span>
487
-          <span class="cassa-sb-total-value" id="cart-total">EUR 0,00</span>
488
-        </div>
489
-        <div class="cassa-sb-pay-grid">
490
-          <button type="button" class="cassa-sb-main-btn">Paga ora</button>
491
-          <button type="button" class="cassa-sb-cash-btn">Contanti</button>
492
-          <button type="button" class="cassa-sb-card-btn">Carta</button>
493
-          <button type="button" class="cassa-sb-clear-btn" id="cart-reset">Svuota</button>
494
-        </div>
495
-      </div>
496
-    </aside>
497
-  </div>
498
-</div>
499
-
500
-<script>
501
-  (function () {
502
-    const KITCHEN_PAGE_SIZE = 10;
503
-    const PRODUCT_PAGE_SIZE = 20;
504
-    const CART_PAGE_SIZE = 6;
505
-    const money = new Intl.NumberFormat('it-IT', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
506
-
507
-    const kitchenTabs = Array.from(document.querySelectorAll('[data-kitchen-tab]'));
508
-    const kitchenList = document.getElementById('kitchen-list');
509
-    const kitchenPrev = document.getElementById('kitchen-prev');
510
-    const kitchenNext = document.getElementById('kitchen-next');
511
-    const kitchenStatus = document.getElementById('kitchen-status');
512
-
513
-    const productGrid = document.getElementById('product-grid');
514
-    const productItems = Array.from(document.querySelectorAll('[data-product-item]'));
515
-    const productSearch = document.getElementById('product-search');
516
-    const productPrev = document.getElementById('product-prev');
517
-    const productNext = document.getElementById('product-next');
518
-    const productStatus = document.getElementById('product-status');
519
-    const selectedKitchenLabel = document.getElementById('selected-kitchen-label');
520
-
521
-    const cartList = document.getElementById('cart-list');
522
-    const cartPrev = document.getElementById('cart-prev');
523
-    const cartNext = document.getElementById('cart-next');
524
-    const cartStatus = document.getElementById('cart-status');
525
-    const cartBadge = document.getElementById('cart-badge');
526
-    const cartTotal = document.getElementById('cart-total');
527
-    const cartReset = document.getElementById('cart-reset');
528
-
529
-    const initialCart = @json($righeIniziali);
530
-    const cart = new Map();
531
-
532
-    let selectedKitchen = kitchenTabs.length ? kitchenTabs[0].dataset.kitchenId : 'all';
533
-    let kitchenPage = 1;
534
-    let productPage = 1;
535
-    let cartPage = 1;
536
-    let visibleKitchens = [];
537
-    let visibleProducts = [];
538
-    let visibleCartRows = [];
539
-
540
-    initialCart.forEach(function (row) {
541
-      if (!row.id) return;
542
-      const key = String(row.id);
543
-      const existing = cart.get(key);
544
-      if (existing) {
545
-        existing.qty += Number(row.qty || 0);
546
-        cart.set(key, existing);
547
-      } else {
548
-        cart.set(key, {
549
-          id: key,
550
-          title: row.title || 'Prodotto',
551
-          price: Number(row.price || 0),
552
-          qty: Number(row.qty || 1)
553
-        });
554
-      }
555
-    });
556
-
557
-    const renderKitchenTabs = function () {
558
-      visibleKitchens = kitchenTabs;
559
-      const maxPage = Math.max(1, Math.ceil(visibleKitchens.length / KITCHEN_PAGE_SIZE));
560
-      if (kitchenPage > maxPage) kitchenPage = maxPage;
561
-      const start = (kitchenPage - 1) * KITCHEN_PAGE_SIZE;
562
-      const end = start + KITCHEN_PAGE_SIZE;
563
-
564
-      kitchenTabs.forEach(function (tab) { tab.style.display = 'none'; });
565
-      const current = visibleKitchens.slice(start, end);
566
-      current.forEach(function (tab) {
567
-        tab.style.display = '';
568
-        tab.classList.toggle('is-active', tab.dataset.kitchenId === selectedKitchen);
569
-      });
570
-
571
-      kitchenList.querySelectorAll('.js-kitchen-placeholder').forEach(function (node) { node.remove(); });
572
-      const placeholders = Math.max(0, KITCHEN_PAGE_SIZE - current.length);
573
-      for (let i = 0; i < placeholders; i += 1) {
574
-        const placeholder = document.createElement('div');
575
-        placeholder.className = 'cassa-sb-placeholder js-kitchen-placeholder';
576
-        kitchenList.appendChild(placeholder);
577
-      }
578
-
579
-      kitchenStatus.textContent = kitchenPage + ' / ' + maxPage;
580
-      kitchenPrev.disabled = kitchenPage <= 1;
581
-      kitchenNext.disabled = kitchenPage >= maxPage;
582
-    };
583
-
584
-    const renderProducts = function () {
585
-      const term = (productSearch?.value || '').trim().toLowerCase();
586
-      const selectedTab = kitchenTabs.find(function (tab) {
587
-        return tab.dataset.kitchenId === selectedKitchen;
588
-      });
589
-      if (selectedKitchenLabel) {
590
-        const labelEl = selectedTab ? selectedTab.querySelector('.cassa-sb-kitchen-label') : null;
591
-        selectedKitchenLabel.textContent = labelEl ? labelEl.textContent.trim() : 'Tutte';
592
-      }
593
-      visibleProducts = productItems.filter(function (item) {
594
-        const okKitchen = selectedKitchen === 'all' || item.dataset.kitchenId === selectedKitchen;
595
-        const okSearch = term === '' || (item.dataset.name || '').includes(term);
596
-        return okKitchen && okSearch;
597
-      });
598
-
599
-      const maxPage = Math.max(1, Math.ceil(visibleProducts.length / PRODUCT_PAGE_SIZE));
600
-      if (productPage > maxPage) productPage = maxPage;
601
-      const start = (productPage - 1) * PRODUCT_PAGE_SIZE;
602
-      const end = start + PRODUCT_PAGE_SIZE;
603
-
604
-      productItems.forEach(function (item) { item.style.display = 'none'; });
605
-      const current = visibleProducts.slice(start, end);
606
-      current.forEach(function (item) { item.style.display = ''; });
607
-
608
-      productGrid.querySelectorAll('.js-product-placeholder').forEach(function (node) { node.remove(); });
609
-      const placeholders = Math.max(0, PRODUCT_PAGE_SIZE - current.length);
610
-      for (let i = 0; i < placeholders; i += 1) {
611
-        const placeholder = document.createElement('div');
612
-        placeholder.className = 'cassa-sb-placeholder js-product-placeholder';
613
-        productGrid.appendChild(placeholder);
614
-      }
615
-
616
-      productStatus.textContent = productPage + ' / ' + maxPage;
617
-      productPrev.disabled = productPage <= 1;
618
-      productNext.disabled = productPage >= maxPage;
619
-    };
620
-
621
-    const renderCart = function () {
622
-      const rows = Array.from(cart.values()).sort(function (a, b) {
623
-        return a.title.localeCompare(b.title, 'it');
624
-      });
625
-
626
-      const itemCount = rows.reduce((acc, row) => acc + row.qty, 0);
627
-      const total = rows.reduce((acc, row) => acc + (row.qty * row.price), 0);
628
-      cartBadge.textContent = itemCount + ' articoli';
629
-      cartTotal.textContent = 'EUR ' + money.format(total);
630
-
631
-      if (!rows.length) {
632
-        cartList.innerHTML = '<div class="text-muted small">Nessun articolo selezionato.</div>';
633
-        cartStatus.textContent = '1 / 1';
634
-        cartPrev.disabled = true;
635
-        cartNext.disabled = true;
636
-        visibleCartRows = [];
637
-        return;
638
-      }
639
-
640
-      visibleCartRows = rows;
641
-      const maxPage = Math.max(1, Math.ceil(rows.length / CART_PAGE_SIZE));
642
-      if (cartPage > maxPage) cartPage = maxPage;
643
-      const start = (cartPage - 1) * CART_PAGE_SIZE;
644
-      const end = start + CART_PAGE_SIZE;
645
-      const current = rows.slice(start, end);
646
-      const placeholders = Math.max(0, CART_PAGE_SIZE - current.length);
647
-
648
-      cartList.innerHTML = current.map(function (row) {
649
-        const rowTotal = row.qty * row.price;
650
-        return '<div class="cassa-sb-cart-row">' +
651
-          '<div><div class="cassa-sb-cart-name">' + row.title + '</div>' +
652
-          '<div class="cassa-sb-cart-meta">Qta ' + row.qty + ' x EUR ' + money.format(row.price) + '</div></div>' +
653
-          '<div class="text-end"><div class="cassa-sb-qty">' +
654
-          '<button type="button" data-cart-action="dec" data-id="' + row.id + '">-</button>' +
655
-          '<span>' + row.qty + '</span>' +
656
-          '<button type="button" data-cart-action="inc" data-id="' + row.id + '">+</button>' +
657
-          '</div><div class="mt-1 fw-bold">EUR ' + money.format(rowTotal) + '</div></div></div>';
658
-      }).join('') + Array.from({ length: placeholders }).map(function () {
659
-        return '<div class="cassa-sb-cart-row" style="opacity:.35"><div class="text-muted small">-</div><div></div></div>';
660
-      }).join('');
661
-
662
-      cartStatus.textContent = cartPage + ' / ' + maxPage;
663
-      cartPrev.disabled = cartPage <= 1;
664
-      cartNext.disabled = cartPage >= maxPage;
665
-    };
666
-
667
-    kitchenTabs.forEach(function (tab) {
668
-      tab.addEventListener('click', function () {
669
-        selectedKitchen = tab.dataset.kitchenId || 'all';
670
-        productPage = 1;
671
-        renderKitchenTabs();
672
-        renderProducts();
673
-      });
674
-    });
675
-
676
-    kitchenPrev?.addEventListener('click', function () {
677
-      if (kitchenPage <= 1) return;
678
-      kitchenPage -= 1;
679
-      renderKitchenTabs();
680
-    });
681
-    kitchenNext?.addEventListener('click', function () {
682
-      const maxPage = Math.max(1, Math.ceil(visibleKitchens.length / KITCHEN_PAGE_SIZE));
683
-      if (kitchenPage >= maxPage) return;
684
-      kitchenPage += 1;
685
-      renderKitchenTabs();
686
-    });
687
-
688
-    productSearch?.addEventListener('input', function () {
689
-      productPage = 1;
690
-      renderProducts();
691
-    });
692
-    productPrev?.addEventListener('click', function () {
693
-      if (productPage <= 1) return;
694
-      productPage -= 1;
695
-      renderProducts();
696
-    });
697
-    productNext?.addEventListener('click', function () {
698
-      const maxPage = Math.max(1, Math.ceil(visibleProducts.length / PRODUCT_PAGE_SIZE));
699
-      if (productPage >= maxPage) return;
700
-      productPage += 1;
701
-      renderProducts();
702
-    });
703
-
704
-    productItems.forEach(function (item) {
705
-      item.addEventListener('click', function () {
706
-        const id = String(item.dataset.id || '');
707
-        if (!id) return;
708
-        const row = cart.get(id) || {
709
-          id: id,
710
-          title: item.dataset.title || 'Prodotto',
711
-          price: parseFloat(item.dataset.price || '0'),
712
-          qty: 0
713
-        };
714
-        row.qty += 1;
715
-        cart.set(id, row);
716
-        cartPage = Math.max(1, Math.ceil(cart.size / CART_PAGE_SIZE));
717
-        renderCart();
718
-      });
719
-    });
720
-
721
-    cartList?.addEventListener('click', function (evt) {
722
-      const target = evt.target;
723
-      if (!(target instanceof HTMLElement)) return;
724
-      const action = target.dataset.cartAction;
725
-      const id = target.dataset.id;
726
-      if (!action || !id || !cart.has(id)) return;
727
-      const row = cart.get(id);
728
-      if (!row) return;
729
-      if (action === 'inc') row.qty += 1;
730
-      if (action === 'dec') row.qty -= 1;
731
-      if (row.qty <= 0) cart.delete(id);
732
-      else cart.set(id, row);
733
-      renderCart();
734
-    });
735
-
736
-    cartPrev?.addEventListener('click', function () {
737
-      if (cartPage <= 1) return;
738
-      cartPage -= 1;
739
-      renderCart();
740
-    });
741
-    cartNext?.addEventListener('click', function () {
742
-      const maxPage = Math.max(1, Math.ceil(visibleCartRows.length / CART_PAGE_SIZE));
743
-      if (cartPage >= maxPage) return;
744
-      cartPage += 1;
745
-      renderCart();
746
-    });
747
-    cartReset?.addEventListener('click', function () {
748
-      cart.clear();
749
-      cartPage = 1;
750
-      renderCart();
751
-    });
752
-
753
-    renderKitchenTabs();
754
-    renderProducts();
755
-    renderCart();
756
-  })();
757
-</script>
758
-@endsection

+ 16
- 0
resources/views/punto_vendita/cassa/viste/catalogo/_partials/carrello-item.blade.php Näytä tiedosto

@@ -0,0 +1,16 @@
1
+<div class="cassa-sb-cart-row">
2
+  <div class="cassa-sb-cart-name">{{ $riga_ordine->piatto->nome }}</div>
3
+  <div class="cassa-sb-qty">
4
+    <button type="button" data-cart-action="dec" data-id="{{ $riga_ordine->piatto_id }}" onclick="diminuisciQuantita({{ $riga_ordine->piatto_id }}, {{ $riga_ordine->id }})" >-</button>
5
+    <span>{{ $riga_ordine->quantita }}</span>
6
+    <button type="button" data-cart-action="inc" data-id="{{ $riga_ordine->piatto_id }}" onclick="aumentaQuantita({{ $riga_ordine->piatto_id }}, {{ $riga_ordine->id }})">+</button>
7
+  </div>
8
+  <div class="cassa-sb-note-row">
9
+      @if($riga_ordine->note)
10
+      <button type="button" class="cassa-sb-note-btn" onclick="aggiungiNota({{ $riga_ordine->piatto_id }}, {{ $riga_ordine->id }}, '{{ $riga_ordine->note }}')">{{ $riga_ordine->note }}</button>
11
+      @else
12
+      <button type="button" class="cassa-sb-note-btn" onclick="aggiungiNota({{ $riga_ordine->piatto_id }}, {{ $riga_ordine->id }}, '{{ $riga_ordine->note }}')"> + Nota</button>
13
+    @endif
14
+</div>
15
+  <div class="cassa-sb-cart-total"> € {{ number_format($riga_ordine->prezzo, 2, ',', '.') }}</div>
16
+</div>

+ 1
- 0
resources/views/punto_vendita/cassa/viste/catalogo/_partials/scripts.blade.php Näytä tiedosto

@@ -0,0 +1 @@
1
+@include('punto_vendita.cassa._partials.scripts')

+ 672
- 0
resources/views/punto_vendita/cassa/viste/catalogo/_partials/style.blade.php Näytä tiedosto

@@ -0,0 +1,672 @@
1
+<style>
2
+  .cassa-sb-wrapper {
3
+    --sb-page-bg: var(--bs-body-bg);
4
+    --sb-surface: var(--bs-paper-bg, var(--bs-body-bg));
5
+    --sb-surface-soft: var(--bs-tertiary-bg);
6
+    --sb-border: var(--bs-border-color);
7
+    --sb-text: var(--bs-heading-color);
8
+    --sb-text-muted: var(--bs-secondary-color);
9
+    --sb-text-soft: var(--bs-body-color);
10
+    --sb-primary: var(--bs-primary);
11
+    --sb-primary-soft: var(--bs-primary-bg-subtle);
12
+    --sb-primary-border: var(--bs-primary-border-subtle);
13
+    --sb-success-soft: var(--bs-success-bg-subtle);
14
+    --sb-success-text: var(--bs-success-text-emphasis);
15
+    --sb-danger-soft: var(--bs-danger-bg-subtle);
16
+    --sb-danger-text: var(--bs-danger-text-emphasis);
17
+
18
+    height: 100dvh;
19
+    padding: .75rem;
20
+    background: var(--sb-page-bg);
21
+    overflow: hidden;
22
+  }
23
+  .cassa-sb-topbar {
24
+    height: 3rem;
25
+    background: var(--sb-surface);
26
+    border: 1px solid var(--sb-border);
27
+    border-radius: 12px;
28
+    padding: .3rem .6rem;
29
+    margin-bottom: .45rem;
30
+    display: flex;
31
+    align-items: center;
32
+    justify-content: space-between;
33
+    gap: .75rem;
34
+  }
35
+  .cassa-sb-layout {
36
+    height: calc(100dvh - 4.2rem);
37
+    min-height: 0;
38
+    display: grid;
39
+    grid-template-columns: minmax(0, 1.7fr) 360px;
40
+    gap: .65rem;
41
+  }
42
+  .cassa-sb-panel {
43
+    min-height: 0;
44
+    background: var(--sb-surface);
45
+    border: 1px solid var(--sb-border);
46
+    border-radius: 12px;
47
+    overflow: hidden;
48
+  }
49
+  .cassa-sb-catalog {
50
+    display: grid;
51
+    grid-template-columns: 170px minmax(0, 1fr);
52
+    min-height: 0;
53
+  }
54
+  .cassa-sb-sidebar {
55
+    min-height: 0;
56
+    border-right: 1px solid var(--sb-border);
57
+    padding: .4rem;
58
+    display: grid;
59
+    grid-template-rows: auto minmax(0, 1fr) auto;
60
+    gap: .35rem;
61
+  }
62
+  .cassa-sb-side-title {
63
+    font-size: .68rem;
64
+    text-transform: uppercase;
65
+    letter-spacing: .04em;
66
+    color: var(--sb-text-muted);
67
+    font-weight: 800;
68
+    margin: 0;
69
+  }
70
+  .cassa-sb-kitchens {
71
+    min-height: 0;
72
+    display: grid;
73
+    grid-template-rows: repeat(10, minmax(0, 1fr));
74
+    gap: .28rem;
75
+  }
76
+  .cassa-sb-kitchen-btn {
77
+    min-height: 0;
78
+    border: 1px solid var(--sb-border);
79
+    border-radius: 8px;
80
+    /* background: #f6f9ff; */
81
+    text-align: left;
82
+    padding: 1em;
83
+    font-weight: 800;
84
+    color: var(--sb-text-soft);
85
+    display: grid;
86
+    align-content: center;
87
+    line-height: .95rem;
88
+    font-size: 1.1rem;
89
+    position: relative;
90
+    transition: transform .12s ease, box-shadow .18s ease, border-color .18s ease, filter .18s ease;
91
+  }
92
+  .cassa-sb-kitchen-label {
93
+    white-space: nowrap;
94
+    text-overflow: ellipsis;
95
+    overflow: hidden;
96
+    font-weight: 800;
97
+  }
98
+  .cassa-sb-kitchen-count {
99
+    font-size: .64rem;
100
+    color: var(--sb-text-muted);
101
+    margin-top: .06rem;
102
+    font-weight: 700;
103
+  }
104
+  .cassa-sb-kitchen-btn.is-active .cassa-sb-kitchen-count {
105
+    color: rgba(var(--bs-white-rgb), .85);
106
+  }
107
+  .cassa-sb-kitchen-btn.is-active {
108
+    border-color: var(--sb-primary) !important;
109
+    box-shadow:
110
+      0 0 0 2px var(--sb-surface),
111
+      0 0 0 4px rgba(var(--bs-primary-rgb), .55),
112
+      0 .45rem .9rem rgba(var(--bs-primary-rgb), .35);
113
+    transform: translateY(-1px) scale(1.01);
114
+    filter: saturate(1.08);
115
+  }
116
+  .cassa-sb-kitchen-btn.is-active::after {
117
+    content: '';
118
+    position: absolute;
119
+    top: 6px;
120
+    right: 6px;
121
+    width: 8px;
122
+    height: 8px;
123
+    border-radius: 999px;
124
+    background: var(--bs-white);
125
+    box-shadow: 0 0 0 2px rgba(0, 0, 0, .2);
126
+  }
127
+  .cassa-sb-side-pager {
128
+    display: grid;
129
+    grid-template-columns: 1fr auto 1fr;
130
+    gap: .3rem;
131
+    align-items: center;
132
+  }
133
+  .cassa-sb-side-pager button {
134
+    height: 30px;
135
+    border: 1px solid var(--sb-border);
136
+    border-radius: 8px;
137
+    background: var(--sb-surface-soft);
138
+    font-weight: 800;
139
+    color: var(--sb-text-soft);
140
+  }
141
+  .cassa-sb-side-pager span {
142
+    font-size: .78rem;
143
+    color: var(--sb-text-muted);
144
+    font-weight: 800;
145
+    min-width: 52px;
146
+    text-align: center;
147
+  }
148
+  .cassa-sb-main {
149
+    min-height: 0;
150
+    display: grid;
151
+    grid-template-rows: auto minmax(0, 1fr);
152
+  }
153
+  .cassa-sb-main-head {
154
+    border-bottom: 1px solid var(--sb-border);
155
+    padding: .35rem .4rem;
156
+    display: grid;
157
+    grid-template-columns: minmax(0, 1fr) auto auto;
158
+    gap: .35rem;
159
+    align-items: center;
160
+  }
161
+  .cassa-sb-selected-kitchen {
162
+    font-size: .74rem;
163
+    color: var(--sb-text-soft);
164
+    border: 1px solid var(--sb-border);
165
+    border-radius: 8px;
166
+    padding: .38rem .5rem;
167
+    background: var(--sb-surface-soft);
168
+    white-space: nowrap;
169
+  }
170
+  .cassa-sb-search {
171
+    height: 34px;
172
+    border: 1px solid var(--sb-border);
173
+    border-radius: 8px;
174
+    padding: 0 .55rem;
175
+    font-size: .86rem;
176
+  }
177
+  .cassa-sb-main-pager {
178
+    display: inline-flex;
179
+    gap: .35rem;
180
+    align-items: center;
181
+  }
182
+  .cassa-sb-main-pager button {
183
+    min-width: 52px;
184
+    height: 34px;
185
+    border: 1px solid var(--sb-border);
186
+    border-radius: 7px;
187
+    background: var(--sb-surface-soft);
188
+    font-weight: 800;
189
+    color: var(--sb-text-soft);
190
+  }
191
+  .cassa-sb-main-pager span {
192
+    min-width: 48px;
193
+    font-size: .74rem;
194
+    color: var(--sb-text-muted);
195
+    font-weight: 800;
196
+    text-align: center;
197
+  }
198
+  .cassa-sb-products-wrap {
199
+    min-height: 0;
200
+    padding: .35rem;
201
+  }
202
+  .cassa-sb-products {
203
+    /* height: 100%; */
204
+    min-height: 0;
205
+    display: grid;
206
+    grid-template-columns: repeat(5, minmax(0, 1fr));
207
+    grid-template-rows: repeat(4, minmax(0, 1fr));
208
+    gap: .3rem;
209
+  }
210
+  .cassa-sb-product {
211
+    min-height: 0;
212
+    border: 1px solid var(--sb-border);
213
+    border-radius: 8px;
214
+    background: var(--sb-surface);
215
+    padding: 1rem;
216
+    display: flex;
217
+    flex-direction: column;
218
+    justify-content: flex-start;
219
+    cursor: pointer;
220
+    position: relative;
221
+  }
222
+  .cassa-sb-product:active { transform: scale(.99); }
223
+  .cassa-sb-product:hover { border-color: var(--sb-primary-border); }
224
+  .cassa-sb-product-title {
225
+    font-size: clamp(.84rem, 1.1vw, 1.08rem);
226
+    font-weight: 900;
227
+    color: var(--sb-text);
228
+    line-height: 1.05;
229
+    display: -webkit-box;
230
+    -webkit-line-clamp: 3;
231
+    -webkit-box-orient: vertical;
232
+    overflow: hidden;
233
+  }
234
+  .cassa-sb-product-title.is-long {
235
+    font-size: clamp(.78rem, 1vw, .95rem);
236
+  }
237
+  .cassa-sb-product-title.is-xlong {
238
+    font-size: clamp(.72rem, .95vw, .88rem);
239
+  }
240
+  .cassa-sb-product-sub {
241
+    font-size: .64rem;
242
+    color: var(--sb-text-muted);
243
+    margin-top: .12rem;
244
+  }
245
+  .cassa-sb-product-price {
246
+    margin-top: .18rem;
247
+    font-size: .8rem;
248
+    color: var(--sb-primary);
249
+    font-weight: 900;
250
+  }
251
+  .cassa-sb-allergen-trigger {
252
+    position: absolute;
253
+    top: .4rem;
254
+    right: .4rem;
255
+    width: 1.35rem;
256
+    height: 1.35rem;
257
+    border-radius: 999px;
258
+    border: 1px solid var(--sb-primary-border);
259
+    background: var(--sb-primary);
260
+    color: var(--bs-white);
261
+    font-size: .78rem;
262
+    font-weight: 900;
263
+    line-height: 1;
264
+    display: inline-flex;
265
+    align-items: center;
266
+    justify-content: center;
267
+    cursor: pointer;
268
+    z-index: 2;
269
+  }
270
+  .cassa-sb-allergen-trigger:hover {
271
+    filter: brightness(1.05);
272
+  }
273
+  .cassa-sb-allergen-tooltip {
274
+    position: absolute;
275
+    top: 1.85rem;
276
+    right: .4rem;
277
+    width: min(220px, 80vw);
278
+    border: 1px solid var(--sb-border);
279
+    background: var(--sb-surface);
280
+    color: var(--sb-text);
281
+    border-radius: .6rem;
282
+    box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .18);
283
+    padding: .45rem .55rem;
284
+    font-size: .72rem;
285
+    line-height: 1.3;
286
+    display: none;
287
+    z-index: 4;
288
+    pointer-events: none;
289
+  }
290
+  .cassa-sb-allergen-tooltip.is-open {
291
+    display: block;
292
+  }
293
+  .cassa-sb-allergen-tooltip-title {
294
+    font-weight: 800;
295
+    margin-bottom: .2rem;
296
+  }
297
+  .cassa-sb-placeholder {
298
+    /* border: 1px dashed var(--sb-border); */
299
+    border-radius: 12px;
300
+    /* background: var(--sb-surface-soft); */
301
+    opacity: .75;
302
+  }
303
+  .cassa-sb-cart {
304
+    display: grid;
305
+    grid-template-rows: auto minmax(0, 1fr) auto;
306
+    min-height: 0;
307
+  }
308
+  .cassa-sb-cart-head {
309
+    border-bottom: 1px solid var(--sb-border);
310
+    padding: .42rem .48rem;
311
+    display: flex;
312
+    justify-content: space-between;
313
+    align-items: center;
314
+    gap: .45rem;
315
+  }
316
+  .cassa-sb-cart-list {
317
+    min-height: 0;
318
+    padding: .35rem;
319
+    display: grid;
320
+    grid-template-rows: repeat(6, minmax(0, 1fr));
321
+    gap: .28rem;
322
+  }
323
+  .cassa-sb-cart-row {
324
+    border: 1px solid var(--sb-border);
325
+    border-radius: 10px;
326
+    background: var(--sb-surface);
327
+    padding: .5rem .55rem;
328
+    display: grid;
329
+    grid-template-columns: minmax(0, 1fr) auto;
330
+    grid-template-areas:
331
+      "name total"
332
+      "note qty";
333
+    /* column-gap: .55rem;
334
+    row-gap: .35rem; */
335
+    align-items: center;
336
+    min-height: 0;
337
+  }
338
+  .cassa-sb-cart-name {
339
+    grid-area: name;
340
+    font-size: .84rem;
341
+    font-weight: 900;
342
+    color: var(--sb-text);
343
+    line-height: 1.1;
344
+    display: -webkit-box;
345
+    -webkit-line-clamp: 2;
346
+    -webkit-box-orient: vertical;
347
+    overflow: hidden;
348
+  }
349
+  .cassa-sb-note-row {
350
+    grid-area: note;
351
+    display: flex;
352
+    align-items: center;
353
+  }
354
+  .cassa-sb-note-btn {
355
+    border: 1px solid var(--sb-border);
356
+    background: var(--sb-surface-soft);
357
+    color: var(--sb-text-soft);
358
+    border-radius: 999px;
359
+    height: 26px;
360
+    padding: 0 .65rem;
361
+    font-size: .67rem;
362
+    font-weight: 800;
363
+    white-space: nowrap;
364
+    display: inline-flex;
365
+    align-items: center;
366
+    gap: .22rem;
367
+  }
368
+  .cassa-sb-note-btn::before {
369
+    /* content: 'i';
370
+    width: 14px;
371
+    height: 14px;
372
+    border-radius: 999px;
373
+    border: 1px solid currentColor;
374
+    display: inline-flex;
375
+    align-items: center;
376
+    justify-content: center;
377
+    font-size: .58rem;
378
+    line-height: 1; */
379
+  }
380
+  .cassa-sb-cart-total {
381
+    grid-area: total;
382
+    font-size: 1.1rem;
383
+    font-weight: 900;
384
+    color: var(--sb-primary);
385
+    white-space: nowrap;
386
+    text-align: right;
387
+    align-self: center;
388
+  }
389
+  .cassa-sb-qty {
390
+    grid-area: qty;
391
+    justify-self: end;
392
+    display: inline-flex;
393
+    align-items: center;
394
+    border: 1px solid var(--sb-border);
395
+    border-radius: 8px;
396
+    overflow: hidden;
397
+    height: 28px;
398
+  }
399
+  .cassa-sb-qty button {
400
+    width: 40px;
401
+    height: 40px;
402
+    border: 0;
403
+    background: var(--sb-surface-soft);
404
+    font-weight: 800;
405
+    font-size: 1.5rem;
406
+    color: var(--sb-text);
407
+  }
408
+  .cassa-sb-qty span {
409
+    min-width: 28px;
410
+    text-align: center;
411
+    font-size: .78rem;
412
+    font-weight: 800;
413
+    color: var(--sb-text);
414
+  }
415
+  .cassa-sb-footer {
416
+    border-top: 1px solid var(--sb-border);
417
+    padding: .35rem;
418
+    display: grid;
419
+    gap: .28rem;
420
+  }
421
+  .cassa-sb-total {
422
+    border: 1px solid var(--sb-primary-border);
423
+    background: var(--sb-primary-soft);
424
+    border-radius: 8px;
425
+    padding: .32rem .38rem;
426
+    display: flex;
427
+    align-items: center;
428
+    justify-content: space-between;
429
+  }
430
+  .cassa-sb-total-value {
431
+    font-size: 1.02rem;
432
+    font-weight: 900;
433
+    color: var(--sb-primary);
434
+  }
435
+  .cassa-sb-pay-grid {
436
+    display: grid;
437
+    grid-template-columns: 1fr 1fr;
438
+    gap: .22rem;
439
+  }
440
+  .cassa-sb-pay-grid button {
441
+    min-height: 40px;
442
+    border-radius: 8px;
443
+    border: 1px solid var(--sb-border);
444
+    font-weight: 900;
445
+  }
446
+  .cassa-sb-main-btn {
447
+    background: var(--sb-primary);
448
+    border-color: var(--sb-primary) !important;
449
+    color: var(--bs-white);
450
+  }
451
+  .cassa-sb-cash-btn {
452
+    background: var(--sb-success-soft);
453
+    color: var(--sb-success-text);
454
+  }
455
+  .cassa-sb-card-btn {
456
+    background: var(--sb-primary-soft);
457
+    color: var(--sb-primary);
458
+  }
459
+  .cassa-sb-clear-btn {
460
+    background: var(--sb-danger-soft);
461
+    color: var(--sb-danger-text);
462
+  }
463
+  @media (max-width: 1400px) {
464
+    .cassa-sb-layout { grid-template-columns: minmax(0, 1fr) 320px; }
465
+    .cassa-sb-catalog { grid-template-columns: 155px minmax(0, 1fr); }
466
+    .cassa-sb-kitchens { grid-template-rows: repeat(10, minmax(0, 1fr)); }
467
+    .cassa-sb-products { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-rows: repeat(5, minmax(0, 1fr)); }
468
+  }
469
+  @media (max-width: 1200px) {
470
+    .cassa-sb-wrapper {
471
+      padding: .5rem;
472
+      height: auto;
473
+      min-height: 100dvh;
474
+      overflow: auto;
475
+    }
476
+    .cassa-sb-layout {
477
+      height: auto;
478
+      grid-template-columns: minmax(0, 1fr);
479
+      gap: .5rem;
480
+    }
481
+    .cassa-sb-panel {
482
+      min-height: auto;
483
+    }
484
+    .cassa-sb-catalog {
485
+      grid-template-columns: 140px minmax(0, 1fr);
486
+      min-height: 64dvh;
487
+    }
488
+    .cassa-sb-cart {
489
+      min-height: 38dvh;
490
+    }
491
+    .cassa-sb-products {
492
+      grid-template-columns: repeat(3, minmax(0, 1fr));
493
+      grid-template-rows: repeat(7, minmax(0, 1fr));
494
+    }
495
+  }
496
+  @media (max-width: 768px) {
497
+    .cassa-sb-wrapper {
498
+      padding: .4rem;
499
+    }
500
+    .cassa-sb-topbar {
501
+      height: auto;
502
+      min-height: 3rem;
503
+      flex-wrap: wrap;
504
+      align-items: center;
505
+      gap: .45rem;
506
+      padding: .4rem .5rem;
507
+    }
508
+    .cassa-sb-topbar h5 {
509
+      font-size: 1rem;
510
+      line-height: 1.15;
511
+    }
512
+    .cassa-sb-catalog {
513
+      grid-template-columns: 118px minmax(0, 1fr);
514
+      min-height: 66dvh;
515
+    }
516
+    .cassa-sb-sidebar {
517
+      padding: .3rem;
518
+      gap: .28rem;
519
+    }
520
+    .cassa-sb-kitchen-btn {
521
+      padding: .45rem .35rem;
522
+      font-size: .86rem;
523
+      line-height: 1.02;
524
+    }
525
+    .cassa-sb-kitchen-count {
526
+      font-size: .6rem;
527
+    }
528
+    .cassa-sb-main-head {
529
+      grid-template-columns: 1fr;
530
+    }
531
+    .cassa-sb-selected-kitchen {
532
+      width: 100%;
533
+      text-align: center;
534
+    }
535
+    .cassa-sb-main-pager {
536
+      width: 100%;
537
+      justify-content: space-between;
538
+    }
539
+    .cassa-sb-main-pager button {
540
+      min-width: 60px;
541
+      flex: 1;
542
+    }
543
+    .cassa-sb-products {
544
+      grid-template-columns: repeat(2, minmax(0, 1fr));
545
+      grid-template-rows: auto;
546
+      gap: .25rem;
547
+    }
548
+    .cassa-sb-product {
549
+      min-height: 76px;
550
+      padding: .28rem;
551
+    }
552
+    .cassa-sb-product-title {
553
+      -webkit-line-clamp: 2;
554
+    }
555
+    .cassa-sb-product-price {
556
+      margin-top: .1rem;
557
+      font-size: .76rem;
558
+    }
559
+    .cassa-sb-cart-list {
560
+      grid-template-rows: repeat(5, minmax(0, 1fr));
561
+    }
562
+    .cassa-sb-cart-row {
563
+      padding: .34rem .38rem;
564
+      column-gap: .35rem;
565
+      row-gap: .25rem;
566
+    }
567
+    .cassa-sb-cart-total {
568
+      text-align: right;
569
+    }
570
+    .cassa-sb-pay-grid {
571
+      grid-template-columns: 1fr 1fr;
572
+      gap: .2rem;
573
+    }
574
+    .cassa-sb-pay-grid button {
575
+      min-height: 36px;
576
+      font-size: .8rem;
577
+      padding: .2rem .3rem;
578
+    }
579
+  }
580
+  @media (max-width: 480px) {
581
+    .cassa-sb-wrapper {
582
+      padding: .32rem;
583
+    }
584
+    .cassa-sb-catalog {
585
+      grid-template-columns: 100px minmax(0, 1fr);
586
+      min-height: 64dvh;
587
+    }
588
+    .cassa-sb-side-title {
589
+      font-size: .62rem;
590
+    }
591
+    .cassa-sb-kitchen-btn {
592
+      padding: .38rem .25rem;
593
+      font-size: .78rem;
594
+    }
595
+    .cassa-sb-kitchen-btn.is-active {
596
+      box-shadow:
597
+        0 0 0 1px var(--sb-surface),
598
+        0 0 0 3px rgba(var(--bs-primary-rgb), .5),
599
+        0 .25rem .55rem rgba(var(--bs-primary-rgb), .28);
600
+      transform: none;
601
+    }
602
+    .cassa-sb-side-pager button,
603
+    .cassa-sb-main-pager button {
604
+      min-width: 52px;
605
+      height: 30px;
606
+      font-size: .72rem;
607
+    }
608
+    .cassa-sb-main-head {
609
+      padding: .3rem;
610
+      gap: .28rem;
611
+    }
612
+    .cassa-sb-search {
613
+      height: 32px;
614
+      font-size: .8rem;
615
+    }
616
+    .cassa-sb-products {
617
+      gap: .22rem;
618
+    }
619
+    .cassa-sb-product {
620
+      min-height: 70px;
621
+      border-radius: 7px;
622
+    }
623
+    .cassa-sb-product-title {
624
+      font-size: .82rem;
625
+      line-height: 1.02;
626
+    }
627
+    .cassa-sb-product-title.is-long {
628
+      font-size: .76rem;
629
+    }
630
+    .cassa-sb-product-title.is-xlong {
631
+      font-size: .7rem;
632
+    }
633
+    .cassa-sb-product-price {
634
+      font-size: .72rem;
635
+    }
636
+    .cassa-sb-cart-head {
637
+      padding: .32rem;
638
+    }
639
+    .cassa-sb-cart-list {
640
+      padding: .28rem;
641
+      gap: .22rem;
642
+    }
643
+    .cassa-sb-cart-name {
644
+      font-size: .72rem;
645
+    }
646
+    .cassa-sb-note-row {
647
+      min-height: 24px;
648
+    }
649
+    .cassa-sb-note-btn {
650
+      height: 24px;
651
+      font-size: .62rem;
652
+      padding: 0 .45rem;
653
+    }
654
+    .cassa-sb-note-btn::before {
655
+      width: 12px;
656
+      height: 12px;
657
+      font-size: .52rem;
658
+    }
659
+    .cassa-sb-cart-total {
660
+      font-size: .72rem;
661
+    }
662
+    .cassa-sb-total {
663
+      padding: .28rem .32rem;
664
+    }
665
+    .cassa-sb-total-value {
666
+      font-size: .92rem;
667
+    }
668
+    .cassa-sb-pay-grid {
669
+      grid-template-columns: 1fr;
670
+    }
671
+  }
672
+</style>

+ 511
- 0
resources/views/punto_vendita/cassa/viste/catalogo/index.blade.php Näytä tiedosto

@@ -0,0 +1,511 @@
1
+<?php
2
+use Illuminate\Support\Facades\Auth;
3
+?>
4
+
5
+@php
6
+  $cucine = ($cucine ?? collect())
7
+    ->sortBy(fn ($cucina) => mb_strtolower((string) ($cucina->nome ?? ''), 'UTF-8'))
8
+    ->values();
9
+
10
+  $righeOrdine = $ordine->righe_ordine ?? collect();
11
+  $righeIniziali = $righeOrdine->map(function ($riga) {
12
+    return [
13
+      'id' => (string) ($riga->piatto_id ?? $riga->id),
14
+      'title' => (string) ($riga->piatto->nome ?? ('Riga #' . $riga->id)),
15
+      'price' => (float) ($riga->prezzo ?? 0),
16
+      'qty' => (int) ($riga->quantita ?? 1),
17
+    ];
18
+  })->values();
19
+@endphp
20
+
21
+@extends('layouts/blankLayout')
22
+
23
+@php
24
+$title = 'Cassa - ' . ($punto_vendita->attivita->nome ?? 'Attività ND');
25
+@endphp
26
+
27
+
28
+@section('title', $title)
29
+
30
+@section('content')
31
+
32
+@include('punto_vendita.cassa.viste.catalogo._partials.style')
33
+
34
+<div class="cassa-sb-wrapper">
35
+  <div class="cassa-sb-topbar">
36
+    <div class="d-flex align-items-center">
37
+      <h5 class="mb-0">
38
+        {{ $punto_vendita->nome ?? 'Cassa' }}
39
+        <span class="text-muted fs-6">| Ordine #{{ $ordine->id ?? '-' }}</span>
40
+      </h5>
41
+      <!-- <small class="text-muted">Sidebar cucine + catalogo compatto</small> -->
42
+    </div>
43
+    <div>
44
+      @if(Auth::guard('operatore')->check())
45
+        <a href="{{ route('operatore.dashDispositivi') }}" class="btn btn-sm btn-outline-primary">Dashboard</a>
46
+      @elseif(Auth::guard('web')->check())
47
+        <a href="{{ route('dashboard') }}" class="btn btn-sm btn-outline-primary">Dashboard</a>
48
+      @endif
49
+    </div>
50
+  </div>
51
+
52
+  <div class="cassa-sb-layout">
53
+    <section class="cassa-sb-panel cassa-sb-catalog">
54
+      <aside class="cassa-sb-sidebar">
55
+        <p class="cassa-sb-side-title">Cucine</p>
56
+        <div class="cassa-sb-kitchens" id="kitchen-list">
57
+          @foreach($cucine as $cucina)
58
+
59
+          <?php
60
+            // Calcolo il migliore contrasto (bianco o nero) dato un colore di background in $hexColor
61
+            $bgColore = $cucina->info['colore'] ?? '#808080';
62
+
63
+            // Rimuovo il carattere '#' se presente
64
+            $strippedHex = ltrim($bgColore, '#');
65
+            // Espando formato breve (#abc -> #aabbcc)
66
+            if(strlen($strippedHex) == 3) {
67
+              $r = hexdec(str_repeat($strippedHex[0], 2));
68
+              $g = hexdec(str_repeat($strippedHex[1], 2));
69
+              $b = hexdec(str_repeat($strippedHex[2], 2));
70
+            } else {
71
+              $r = hexdec(substr($strippedHex,0,2));
72
+              $g = hexdec(substr($strippedHex,2,2));
73
+              $b = hexdec(substr($strippedHex,4,2));
74
+            }
75
+            // Calcolo luminanza percepita del colore
76
+            $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
77
+            // Soglia: se luminanza alta, uso testo scuro, altrimenti bianco
78
+            $textColor = $luminance > 0.6 ? '#222' : '#fff';
79
+          ?>
80
+
81
+            <button
82
+              type="button"
83
+              class="cassa-sb-kitchen-btn"
84
+
85
+              style="background-color: {{ $bgColore }}; color: {{ $textColor }};"
86
+              data-kitchen-tab
87
+              data-kitchen-id="{{ $cucina->id }}"
88
+              data-kitchen-name="{{ mb_strtolower((string) ($cucina->nome ?? ''), 'UTF-8') }}"
89
+
90
+            >
91
+              <span class="cassa-sb-kitchen-label">{{ $cucina->nome }}</span>
92
+              <span class="cassa-sb-kitchen-count">{{ ($cucina->piatti ?? collect())->count() }} piatti</span>
93
+            </button>
94
+          @endforeach
95
+        </div>
96
+        <div class="cassa-sb-side-pager">
97
+          <button type="button" id="kitchen-prev">Prec</button>
98
+          <span id="kitchen-status">1 / 1</span>
99
+          <button type="button" id="kitchen-next">Next</button>
100
+        </div>
101
+      </aside>
102
+
103
+      <div class="cassa-sb-main">
104
+        <div class="cassa-sb-main-head">
105
+          <input id="product-search" type="text" class="cassa-sb-search" placeholder="Cerca piatto nella cucina selezionata">
106
+          <div class="cassa-sb-selected-kitchen" id="selected-kitchen-label">Tutte</div>
107
+          <div class="cassa-sb-main-pager">
108
+            <button type="button" id="product-prev">Prec</button>
109
+            <span id="product-status">1 / 1</span>
110
+            <button type="button" id="product-next">Next</button>
111
+          </div>
112
+        </div>
113
+        <div class="cassa-sb-products-wrap">
114
+          <div class="cassa-sb-products" id="product-grid">
115
+            @foreach($cucine as $cucina)
116
+              @foreach(($cucina->piatti ?? collect()) as $piatto)
117
+                
118
+                <article
119
+                  class="cassa-sb-product"
120
+                  data-product-item
121
+                  data-kitchen-id="{{ $cucina->id }}"
122
+                  data-name="{{ mb_strtolower((string) ($piatto->nome ?? ''), 'UTF-8') }}"
123
+                  data-piatto-id="{{ $piatto->id }}"
124
+                  data-title="{{ $piatto->nome }}"
125
+                  data-price="{{ (float) ($piatto->prezzo ?? 0) }}"
126
+                  onclik=""
127
+                >
128
+                  @if($piatto->elencoAllergeni?->isNotEmpty() ?? false)
129
+                    <button
130
+                      type="button"
131
+                      class="cassa-sb-allergen-trigger"
132
+                      data-allergen-toggle
133
+                      aria-label="Mostra allergeni"
134
+                    >
135
+                    !
136
+                    <!-- A -->
137
+                      <!-- <i class="bx bx-error-circle"></i> -->
138
+                    </button>
139
+                    <div class="cassa-sb-allergen-tooltip" data-allergen-tooltip>
140
+                      <div class="cassa-sb-allergen-tooltip-title text-primary">Allergeni</div>
141
+                      <div data-allergen-tooltip-text>
142
+                        
143
+                        {{ $piatto->elencoAllergeni->pluck('nome')->implode(', ') }}
144
+                      </div>
145
+                    </div>
146
+                  @endif
147
+                  @php
148
+                    $piattoNome = (string) ($piatto->nome ?? '');
149
+                    $nomeLen = mb_strlen($piattoNome, 'UTF-8');
150
+                    $titleSizeClass = $nomeLen > 24 ? 'is-xlong' : ($nomeLen > 16 ? 'is-long' : '');
151
+                  @endphp
152
+                  <div class="cassa-sb-product-title {{ $titleSizeClass }}">{{ $piattoNome }}</div>
153
+                  <div class="cassa-sb-product-price">EUR {{ number_format((float) ($piatto->prezzo ?? 0), 2, ',', '.') }}</div>
154
+                </article>
155
+              @endforeach
156
+            @endforeach
157
+          </div>
158
+        </div>
159
+      </div>
160
+    </section>
161
+
162
+    <aside class="cassa-sb-panel cassa-sb-cart">
163
+      <div class="cassa-sb-cart-head">
164
+        <div>
165
+          <strong>Carrello</strong>
166
+          <span class="badge bg-label-primary ms-1" id="cart-badge">0 articoli</span>
167
+        </div>
168
+        <div class="cassa-sb-main-pager">
169
+          <button type="button" id="cart-prev">Prec</button>
170
+          <span id="cart-status">1 / 1</span>
171
+          <button type="button" id="cart-next">Next</button>
172
+        </div>
173
+      </div>
174
+
175
+      <div class="cassa-sb-cart-list" id="cart-list">
176
+        <!-- <div class="text-muted small">Nessun articolo selezionato.</div> -->
177
+         {{ $dataTable_rigaordine->table() }}
178
+
179
+      </div>
180
+
181
+      <div class="cassa-sb-footer">
182
+        <div class="cassa-sb-total">
183
+          <span class="fw-semibold">Totale</span>
184
+          <span class="cassa-sb-total-value" id="cart-total">EUR 0,00</span>
185
+        </div>
186
+        <div class="cassa-sb-pay-grid">
187
+          <button type="button" class="cassa-sb-main-btn">Paga ora</button>
188
+          <button type="button" class="cassa-sb-cash-btn">Contanti</button>
189
+          <button type="button" class="cassa-sb-card-btn">Carta</button>
190
+          <button type="button" class="cassa-sb-clear-btn" id="cart-reset" onclick="azzeraCarrello()">Svuota</button>
191
+        </div>
192
+      </div>
193
+    </aside>
194
+  </div>
195
+</div>
196
+
197
+
198
+<script>
199
+  (function () {
200
+    const KITCHEN_PAGE_SIZE = 10;
201
+    const PRODUCT_PAGE_SIZE = 40;
202
+    // const CART_PAGE_SIZE = 6;
203
+    // const money = new Intl.NumberFormat('it-IT', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
204
+
205
+    const kitchenTabs = Array.from(document.querySelectorAll('[data-kitchen-tab]'));
206
+    const kitchenList = document.getElementById('kitchen-list');
207
+    const kitchenPrev = document.getElementById('kitchen-prev');
208
+    const kitchenNext = document.getElementById('kitchen-next');
209
+    const kitchenStatus = document.getElementById('kitchen-status');
210
+
211
+    const productGrid = document.getElementById('product-grid');
212
+    const productItems = Array.from(document.querySelectorAll('[data-product-item]'));
213
+    const productSearch = document.getElementById('product-search');
214
+    const productPrev = document.getElementById('product-prev');
215
+    const productNext = document.getElementById('product-next');
216
+    const productStatus = document.getElementById('product-status');
217
+    const selectedKitchenLabel = document.getElementById('selected-kitchen-label');
218
+
219
+    // const cartList = document.getElementById('cart-list');
220
+    // const cartPrev = document.getElementById('cart-prev');
221
+    // const cartNext = document.getElementById('cart-next');
222
+    // const cartStatus = document.getElementById('cart-status');
223
+    // const cartBadge = document.getElementById('cart-badge');
224
+    // const cartTotal = document.getElementById('cart-total');
225
+    // const cartReset = document.getElementById('cart-reset');
226
+
227
+    // const initialCart = @json($righeIniziali);
228
+    // const cart = new Map();
229
+
230
+    let selectedKitchen = kitchenTabs.length ? kitchenTabs[0].dataset.kitchenId : 'all';
231
+    let kitchenPage = 1;
232
+    let productPage = 1;
233
+    // let cartPage = 1;
234
+    let visibleKitchens = [];
235
+    let visibleProducts = [];
236
+    // let visibleCartRows = [];
237
+
238
+    // initialCart.forEach(function (row) {
239
+    //   if (!row.id) return;
240
+    //   const key = String(row.id);
241
+    //   const existing = cart.get(key);
242
+    //   if (existing) {
243
+    //     existing.qty += Number(row.qty || 0);
244
+    //     cart.set(key, existing);
245
+    //   } else {
246
+    //     cart.set(key, {
247
+    //       id: key,
248
+    //       title: row.title || 'Prodotto',
249
+    //       price: Number(row.price || 0),
250
+    //       qty: Number(row.qty || 1)
251
+    //     });
252
+    //   }
253
+    // });
254
+
255
+    const renderKitchenTabs = function () {
256
+      visibleKitchens = kitchenTabs;
257
+      const maxPage = Math.max(1, Math.ceil(visibleKitchens.length / KITCHEN_PAGE_SIZE));
258
+      if (kitchenPage > maxPage) kitchenPage = maxPage;
259
+      const start = (kitchenPage - 1) * KITCHEN_PAGE_SIZE;
260
+      const end = start + KITCHEN_PAGE_SIZE;
261
+
262
+      kitchenTabs.forEach(function (tab) { tab.style.display = 'none'; });
263
+      const current = visibleKitchens.slice(start, end);
264
+      current.forEach(function (tab) {
265
+        tab.style.display = '';
266
+        tab.classList.toggle('is-active', tab.dataset.kitchenId === selectedKitchen);
267
+      });
268
+
269
+      kitchenList.querySelectorAll('.js-kitchen-placeholder').forEach(function (node) { node.remove(); });
270
+      const placeholders = Math.max(0, KITCHEN_PAGE_SIZE - current.length);
271
+      for (let i = 0; i < placeholders; i += 1) {
272
+        const placeholder = document.createElement('div');
273
+        placeholder.className = 'cassa-sb-placeholder js-kitchen-placeholder';
274
+        kitchenList.appendChild(placeholder);
275
+      }
276
+
277
+      kitchenStatus.textContent = kitchenPage + ' / ' + maxPage;
278
+      kitchenPrev.disabled = kitchenPage <= 1;
279
+      kitchenNext.disabled = kitchenPage >= maxPage;
280
+    };
281
+
282
+    const renderProducts = function () {
283
+      const term = (productSearch?.value || '').trim().toLowerCase();
284
+      const selectedTab = kitchenTabs.find(function (tab) {
285
+        return tab.dataset.kitchenId === selectedKitchen;
286
+      });
287
+      if (selectedKitchenLabel) {
288
+        const labelEl = selectedTab ? selectedTab.querySelector('.cassa-sb-kitchen-label') : null;
289
+        selectedKitchenLabel.textContent = labelEl ? labelEl.textContent.trim() : 'Tutte';
290
+      }
291
+      visibleProducts = productItems.filter(function (item) {
292
+        const okKitchen = selectedKitchen === 'all' || item.dataset.kitchenId === selectedKitchen;
293
+        const okSearch = term === '' || (item.dataset.name || '').includes(term);
294
+        return okKitchen && okSearch;
295
+      });
296
+
297
+      const maxPage = Math.max(1, Math.ceil(visibleProducts.length / PRODUCT_PAGE_SIZE));
298
+      if (productPage > maxPage) productPage = maxPage;
299
+      const start = (productPage - 1) * PRODUCT_PAGE_SIZE;
300
+      const end = start + PRODUCT_PAGE_SIZE;
301
+
302
+      productItems.forEach(function (item) { item.style.display = 'none'; });
303
+      const current = visibleProducts.slice(start, end);
304
+      current.forEach(function (item) { item.style.display = ''; });
305
+
306
+      productGrid.querySelectorAll('.js-product-placeholder').forEach(function (node) { node.remove(); });
307
+      const placeholders = Math.max(0, PRODUCT_PAGE_SIZE - current.length);
308
+      for (let i = 0; i < placeholders; i += 1) {
309
+        const placeholder = document.createElement('div');
310
+        placeholder.className = 'cassa-sb-placeholder js-product-placeholder';
311
+        productGrid.appendChild(placeholder);
312
+      }
313
+
314
+      productStatus.textContent = productPage + ' / ' + maxPage;
315
+      productPrev.disabled = productPage <= 1;
316
+      productNext.disabled = productPage >= maxPage;
317
+    };
318
+
319
+    // --- Carrello demo client-side (disabilitato: usa DataTable reale) ---
320
+    // const renderCart = function () {
321
+    //   const rows = Array.from(cart.values()).sort(function (a, b) {
322
+    //     return a.title.localeCompare(b.title, 'it');
323
+    //   });
324
+    //
325
+    //   const itemCount = rows.reduce((acc, row) => acc + row.qty, 0);
326
+    //   const total = rows.reduce((acc, row) => acc + (row.qty * row.price), 0);
327
+    //   cartBadge.textContent = itemCount + ' articoli';
328
+    //   cartTotal.textContent = 'EUR ' + money.format(total);
329
+    //
330
+    //   if (!rows.length) {
331
+    //     cartList.innerHTML = '<div class="text-muted small">Nessun articolo selezionato.</div>';
332
+    //     cartStatus.textContent = '1 / 1';
333
+    //     cartPrev.disabled = true;
334
+    //     cartNext.disabled = true;
335
+    //     visibleCartRows = [];
336
+    //     return;
337
+    //   }
338
+    //
339
+    //   visibleCartRows = rows;
340
+    //   const maxPage = Math.max(1, Math.ceil(rows.length / CART_PAGE_SIZE));
341
+    //   if (cartPage > maxPage) cartPage = maxPage;
342
+    //   const start = (cartPage - 1) * CART_PAGE_SIZE;
343
+    //   const end = start + CART_PAGE_SIZE;
344
+    //   const current = rows.slice(start, end);
345
+    //   const placeholders = Math.max(0, CART_PAGE_SIZE - current.length);
346
+    //
347
+    //   cartList.innerHTML = current.map(function (row) {
348
+    //     const rowTotal = row.qty * row.price;
349
+    //     return '<div class="cassa-sb-cart-row">' +
350
+    //       '<div class="cassa-sb-cart-name">' + row.title + '</div>' +
351
+    //       '<div class="cassa-sb-qty">' +
352
+    //         '<button type="button" data-cart-action="dec" data-id="' + row.id + '">-</button>' +
353
+    //         '<span>' + row.qty + '</span>' +
354
+    //         '<button type="button" data-cart-action="inc" data-id="' + row.id + '">+</button>' +
355
+    //       '</div>' +
356
+    //       '<div class="cassa-sb-note-row"><button type="button" class="cassa-sb-note-btn">Nota</button></div>' +
357
+    //       '<div class="cassa-sb-cart-total">EUR ' + money.format(rowTotal) + '</div>' +
358
+    //       '</div>';
359
+    //   }).join('') + Array.from({ length: placeholders }).map(function () {
360
+    //     return '<div class="cassa-sb-cart-row" style="opacity:.35">' +
361
+    //       '<div class="text-muted small">-</div>' +
362
+    //       '<div></div>' +
363
+    //       '<div class="cassa-sb-note-row"></div>' +
364
+    //       '<div></div>' +
365
+    //     '</div>';
366
+    //   }).join('');
367
+    //
368
+    //   cartStatus.textContent = cartPage + ' / ' + maxPage;
369
+    //   cartPrev.disabled = cartPage <= 1;
370
+    //   cartNext.disabled = cartPage >= maxPage;
371
+    // };
372
+
373
+    kitchenTabs.forEach(function (tab) {
374
+      tab.addEventListener('click', function () {
375
+        selectedKitchen = tab.dataset.kitchenId || 'all';
376
+        productPage = 1;
377
+        renderKitchenTabs();
378
+        renderProducts();
379
+      });
380
+    });
381
+
382
+    kitchenPrev?.addEventListener('click', function () {
383
+      if (kitchenPage <= 1) return;
384
+      kitchenPage -= 1;
385
+      renderKitchenTabs();
386
+    });
387
+    kitchenNext?.addEventListener('click', function () {
388
+      const maxPage = Math.max(1, Math.ceil(visibleKitchens.length / KITCHEN_PAGE_SIZE));
389
+      if (kitchenPage >= maxPage) return;
390
+      kitchenPage += 1;
391
+      renderKitchenTabs();
392
+    });
393
+
394
+    productSearch?.addEventListener('input', function () {
395
+      productPage = 1;
396
+      renderProducts();
397
+    });
398
+    productPrev?.addEventListener('click', function () {
399
+      if (productPage <= 1) return;
400
+      productPage -= 1;
401
+      renderProducts();
402
+    });
403
+    productNext?.addEventListener('click', function () {
404
+      const maxPage = Math.max(1, Math.ceil(visibleProducts.length / PRODUCT_PAGE_SIZE));
405
+      if (productPage >= maxPage) return;
406
+      productPage += 1;
407
+      renderProducts();
408
+    });
409
+
410
+    // Click piatto → carrello demo (disabilitato: usare aumentaQuantita() lato server)
411
+    // productItems.forEach(function (item) {
412
+    //   item.addEventListener('click', function () {
413
+    //     if (item.dataset.allergenOpen === '1') return;
414
+    //     const id = String(item.dataset.id || '');
415
+    //     if (!id) return;
416
+    //     const row = cart.get(id) || {
417
+    //       id: id,
418
+    //       title: item.dataset.title || 'Prodotto',
419
+    //       price: parseFloat(item.dataset.price || '0'),
420
+    //       qty: 0
421
+    //     };
422
+    //     row.qty += 1;
423
+    //     cart.set(id, row);
424
+    //     cartPage = Math.max(1, Math.ceil(cart.size / CART_PAGE_SIZE));
425
+    //     renderCart();
426
+    //   });
427
+    // });
428
+
429
+    document.addEventListener('click', function (evt) {
430
+      const target = evt.target;
431
+      if (!(target instanceof HTMLElement)) return;
432
+
433
+      const closeAllTooltips = function () {
434
+        document.querySelectorAll('[data-allergen-tooltip].is-open').forEach(function (tip) {
435
+          tip.classList.remove('is-open');
436
+        });
437
+        document.querySelectorAll('[data-product-item][data-allergen-open="1"]').forEach(function (card) {
438
+          card.dataset.allergenOpen = '0';
439
+        });
440
+      };
441
+
442
+      const trigger = target.closest('[data-allergen-toggle]');
443
+      if (!trigger) {
444
+        if (!target.closest('[data-allergen-tooltip]')) {
445
+          closeAllTooltips();
446
+        }
447
+        return;
448
+      }
449
+
450
+      evt.preventDefault();
451
+      evt.stopPropagation();
452
+
453
+      const card = trigger.closest('[data-product-item]');
454
+      if (!card) return;
455
+      const tooltip = card.querySelector('[data-allergen-tooltip]');
456
+      const textNode = card.querySelector('[data-allergen-tooltip-text]');
457
+      if (!tooltip || !textNode) return;
458
+
459
+      const wasOpen = tooltip.classList.contains('is-open');
460
+      closeAllTooltips();
461
+      if (wasOpen) return;
462
+
463
+      // textNode.textContent = card.dataset.allergens || 'Nessun allergene';
464
+      tooltip.classList.add('is-open');
465
+      card.dataset.allergenOpen = '1';
466
+    });
467
+
468
+    // cartList?.addEventListener('click', function (evt) {
469
+    //   const target = evt.target;
470
+    //   if (!(target instanceof HTMLElement)) return;
471
+    //   const action = target.dataset.cartAction;
472
+    //   const id = target.dataset.id;
473
+    //   if (!action || !id || !cart.has(id)) return;
474
+    //   const row = cart.get(id);
475
+    //   if (!row) return;
476
+    //   if (action === 'inc') row.qty += 1;
477
+    //   if (action === 'dec') row.qty -= 1;
478
+    //   if (row.qty <= 0) cart.delete(id);
479
+    //   else cart.set(id, row);
480
+    //   renderCart();
481
+    // });
482
+
483
+    // cartPrev?.addEventListener('click', function () {
484
+    //   if (cartPage <= 1) return;
485
+    //   cartPage -= 1;
486
+    //   renderCart();
487
+    // });
488
+    // cartNext?.addEventListener('click', function () {
489
+    //   const maxPage = Math.max(1, Math.ceil(visibleCartRows.length / CART_PAGE_SIZE));
490
+    //   if (cartPage >= maxPage) return;
491
+    //   cartPage += 1;
492
+    //   renderCart();
493
+    // });
494
+    // cartReset?.addEventListener('click', function () {
495
+    //   cart.clear();
496
+    //   cartPage = 1;
497
+    //   renderCart();
498
+    // });
499
+
500
+    renderKitchenTabs();
501
+    renderProducts();
502
+    // renderCart();
503
+  })();
504
+</script>
505
+@endsection
506
+
507
+
508
+@section('page-script')
509
+  @include('punto_vendita.cassa.viste.catalogo._partials.scripts')
510
+
511
+@endsection

+ 14
- 3
resources/views/punto_vendita/index.blade.php Näytä tiedosto

@@ -36,9 +36,20 @@ $configData = Helper::appClasses();
36 36
 @endsection
37 37
 
38 38
 @section('pageTitle')
39
-<div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-store"></i> Punti di vendita</h4>
39
+<div class="d-flex flex-column ">
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-store d-none d-md-inline-flex d-lg-inline-flex"></i> 
42
+    Punti di vendita
43
+  </h4>
44
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
45
+            <ol class="breadcrumb breadcrumb-custom-icon">
46
+      
47
+              <li class="breadcrumb-item">
48
+                <a href="#">Dispositivi</a>
49
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
50
+              </li>
51
+              <li class="breadcrumb-item active text-primary">
52
+                <a href="{{ route('punto-vendita.index') }}">Punti di vendita</a>
42 53
 </div>
43 54
 @endsection
44 55
 

+ 103
- 0
resources/views/punto_vendita/metodo_pagamento/segresta_wallet.blade.php Näytä tiedosto

@@ -0,0 +1,103 @@
1
+<!-- Modal Segresta Wallet: richiesta lettura tag NFC -->
2
+<div class="modal fade" id="segrestaWalletModal" tabindex="-1" aria-labelledby="segrestaWalletModalLabel" aria-hidden="true">
3
+  <div class="modal-dialog modal-dialog-centered">
4
+    <div class="modal-content">
5
+      <div class="modal-header bg-primary text-white">
6
+        <h5 class="modal-title" id="segrestaWalletModalLabel">
7
+          Segresta Wallet
8
+        </h5>
9
+        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
10
+      </div>
11
+      <div class="modal-body text-center">
12
+        <div class="mb-3">
13
+          <i class="bx bx-rfid bx-lg"></i>
14
+        </div>
15
+        <p>
16
+          Avvicina il braccialetto NFC al lettore per pagare con Segresta Wallet.
17
+        </p>
18
+        <div id="nfc-status" class="my-2">
19
+          <span class="badge bg-secondary">In attesa di lettura...</span>
20
+        </div>
21
+        <!-- NOTA: Questo form non va sempre nella cassa: normalmente l'input tag verrà popolato in una form già presente nella view della cassa principale. 
22
+             Il form qui rimane per fallback o testing standalone, ma non invierà il pagamento se incluso sopra una form principale
23
+         -->
24
+        <form id="segrestaWalletForm" action="{{ route('punto-vendita.paga-ordine') }}" method="POST" class="d-none">
25
+          @csrf
26
+          <input type="hidden" name="ordine_id" value="{{ $ordine->id ?? '' }}">
27
+          <input type="hidden" name="metodo_pagamento_id" value="{{ $metodo_pagamento->id ?? '' }}">
28
+          <input type="hidden" name="tag_id" id="tag_id_input" value="">
29
+        </form>
30
+      </div>
31
+      <div class="modal-footer">
32
+        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
33
+      </div>
34
+    </div>
35
+  </div>
36
+</div>
37
+
38
+<script>
39
+/**
40
+ * Quando questa modale viene inclusa nella view della cassa,
41
+ * la lettura del tag NFC popolerà l'input (id/tag_id_input).
42
+ * Attenzione: se esiste un campo input già nella cassa con ID "tag_id_input", verrà popolato quello!
43
+ * Se NON vuoi la form qui, puoi rimuoverla sopra e farla puntare solo agli input esterni.
44
+ */
45
+document.addEventListener("DOMContentLoaded", function() {
46
+    let nfcAbortController = null;
47
+    function resetNfcStatus() {
48
+        document.getElementById('nfc-status').innerHTML = '<span class="badge bg-secondary">In attesa di lettura...</span>';
49
+        // Reset sia l'input della modale che quello presente nella view principale (se esiste)
50
+        if(document.getElementById('tag_id_input')) document.getElementById('tag_id_input').value = '';
51
+    }
52
+    function readNfc() {
53
+        if (!('NDEFReader' in window)) {
54
+            document.getElementById('nfc-status').innerHTML = '<span class="badge bg-danger">NFC non supportato su questo dispositivo/browser</span>';
55
+            return;
56
+        }
57
+        nfcAbortController = new AbortController();
58
+        const reader = new NDEFReader();
59
+        reader.scan({signal: nfcAbortController.signal}).then(() => {
60
+            document.getElementById('nfc-status').innerHTML = '<span class="badge bg-warning text-dark">Avvicina ora il braccialetto al lettore...</span>';
61
+            reader.onreading = event => {
62
+                const { serialNumber, message } = event;
63
+                let tagId = serialNumber;
64
+                // Popola SEMPRE l'input con id tag_id_input visibile nella pagina (view cassa o fallback in modale)
65
+                // Se presente nella view principale, popoliamo direttamente quello
66
+                let tagInput = document.getElementById('tag_id_input');
67
+                if (tagInput) tagInput.value = tagId;
68
+
69
+                document.getElementById('nfc-status').innerHTML = '<span class="badge bg-success">Braccialetto letto! Puoi confermare il pagamento.</span>';
70
+
71
+                // Se siamo in presenza del form nascosto (la modale lavora in standalone), invialo (old behavior).
72
+                // Se invece esiste una form principale nella cassa, sarà la sua logica a inviare.
73
+                let modalForm = document.getElementById('segrestaWalletForm');
74
+                if (modalForm && modalForm.classList.contains('d-none')) {
75
+                  // Lo inviamo solo se non c'è una view cassa esterna da gestire (quindi fallback).
76
+                  setTimeout(() => {
77
+                    modalForm.submit();
78
+                  }, 700);
79
+                  // disabilita la lettura per questa istanza
80
+                  nfcAbortController.abort();
81
+                }
82
+            };
83
+            reader.onerror = event => {
84
+                document.getElementById('nfc-status').innerHTML = '<span class="badge bg-danger">Errore nella lettura NFC</span>';
85
+            };
86
+        }).catch(err => {
87
+            document.getElementById('nfc-status').innerHTML = '<span class="badge bg-danger">Impossibile avviare la lettura NFC: ' + err.message + '</span>';
88
+        });
89
+    }
90
+
91
+    // All'apertura modale: resetta e avvia la lettura NFC
92
+    var modal = document.getElementById('segrestaWalletModal');
93
+    modal.addEventListener('show.bs.modal', function () {
94
+        resetNfcStatus();
95
+        readNfc();
96
+    });
97
+    // Alla chiusura modale: annulla lettura NFC e resetta stato
98
+    modal.addEventListener('hide.bs.modal', function () {
99
+        if(nfcAbortController) nfcAbortController.abort();
100
+        resetNfcStatus();
101
+    });
102
+});
103
+</script>

+ 5
- 2
resources/views/role/index.blade.php Näytä tiedosto

@@ -9,8 +9,11 @@
9 9
 
10 10
 @section('pageTitle')
11 11
 <div class="d-flex flex-column">
12
-    <h4 class="mb-1"><i class="bx bx-shield"></i> Ruoli</h4>
13
-    <p class="mb-0">Lista di tutti i ruoli e i loro permessi</p>
12
+    <h4 class="mb-1 text-sm-small">
13
+      <i class="bx bx-shield d-none d-md-inline-flex d-lg-inline-flex"></i> 
14
+      Ruoli
15
+    </h4>
16
+    <p class="mb-0 d-none d-md-block d-lg-block">Lista di tutti i ruoli e i loro permessi</p>
14 17
 </div>
15 18
 @endsection
16 19
 

+ 3
- 3
resources/views/saltacoda/index.blade.php Näytä tiedosto

@@ -37,12 +37,12 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-0 mt-4"> 
41
-    <i class="bx bxs-user-badge"></i> 
40
+  <h4 class="mb-0 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bxs-user-badge d-none d-md-inline-flex d-lg-inline-flex"></i> 
42 42
     Saltacoda
43 43
     <!-- Saltacoda di {{ $attivita->nome }} -->
44 44
   </h4>
45
-  <nav aria-label="breadcrumb" style="font-size: smaller;">
45
+  <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
46 46
             <ol class="breadcrumb breadcrumb-custom-icon">
47 47
 
48 48
               <li class="breadcrumb-item">

+ 18
- 2
resources/views/stampante/index.blade.php Näytä tiedosto

@@ -37,8 +37,24 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-printer"></i> Stampanti</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-printer d-none d-md-inline-flex d-lg-inline-flex"></i> Stampanti</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Dispositivi</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item">
50
+                <a href="#">Stampa</a>
51
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
52
+              </li>
53
+              <li class="breadcrumb-item active text-primary">
54
+                <a href="{{ route('stampante.index') }}">Stampanti</a>
55
+              </li>
56
+            </ol>
57
+          </nav>
42 58
 </div>
43 59
 @endsection
44 60
 

+ 14
- 2
resources/views/testi/index.blade.php Näytä tiedosto

@@ -37,8 +37,20 @@ $configData = Helper::appClasses();
37 37
 
38 38
 @section('pageTitle')
39 39
 <div class="d-flex flex-column">
40
-  <h4 class="mb-1"> 
41
-    <i class="bx bx-text"></i> Testi</h4>
40
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4"> 
41
+    <i class="bx bx-text d-none d-md-inline-flex d-lg-inline-flex"></i> Testi</h4>
42
+    <nav aria-label="breadcrumb" style="font-size: smaller;" class="d-none d-md-block d-lg-block">
43
+            <ol class="breadcrumb breadcrumb-custom-icon">
44
+      
45
+              <li class="breadcrumb-item">
46
+                <a href="#">Configurazioni</a>
47
+                <i class="breadcrumb-icon icon-base bx bx-chevron-right align-middle"></i>
48
+              </li>
49
+              <li class="breadcrumb-item active text-primary">
50
+                <a href="{{ route('testi.index') }}">Testi</a>
51
+              </li>
52
+            </ol>
53
+          </nav>
42 54
 </div>
43 55
 @endsection
44 56
 

+ 26
- 4
resources/views/tombola/index.blade.php Näytä tiedosto

@@ -1,11 +1,19 @@
1
+<?php
2
+use Illuminate\Support\Facades\Auth;
3
+use Illuminate\Support\Facades\Session;
4
+use App\Models\Attivita;
5
+?>
6
+
1 7
 @extends('layouts/layoutMaster')
2 8
 
3 9
 @section('title', 'Tombola')
4 10
 
5 11
 @section('pageTitle')
6 12
 <div class="d-flex flex-column">
7
-  <h4 class="mb-1"><i class="bx bx-grid-alt me-1"></i> Tombola</h4>
8
-  <small class="text-muted">Situazione corrente e condivisione estrazioni</small>
13
+  <h4 class="mb-1 text-sm-small mt-md-4 mt-lg-4">
14
+    <i class="bx bx-grid-alt me-1 d-none d-md-inline-flex d-lg-inline-flex"></i>
15
+     Tombola
16
+    </h4>
9 17
 </div>
10 18
 @endsection
11 19
 
@@ -69,8 +77,8 @@
69 77
           @endif
70 78
         </div>
71 79
 
72
-        <div class="mt-4">
73
-          <form method="POST" action="{{ route('tombola.azzera') }}" onsubmit="return confirm('Confermi l\'azzeramento completo della tombola?');">
80
+        <div class="mt-4 col-4">
81
+          <form method="POST" action="{{ route('tombola.azzera' , ['attivita_id' => Session::get('attivita_attuale')]) }}" onsubmit="return confirm('Confermi l\'azzeramento completo della tombola?');">
74 82
             @csrf
75 83
             <button type="submit" class="btn btn-danger">
76 84
               <i class="bx bx-refresh me-1"></i> Azzera Tombola
@@ -78,6 +86,20 @@
78 86
           </form>
79 87
           <small class="text-muted d-block mt-2">Resetta tutti i numeri come non estratti.</small>
80 88
         </div>
89
+
90
+        @if( \App\Models\Tombola::where('attivita_id', Session::get('attivita_attuale'))->count() === 0)
91
+        <div class="mt-4 col-4">
92
+          <form method="POST" action="{{ route('tombola.getTabellone') }}">
93
+            @csrf
94
+            <button type="submit" class="btn btn-primary">
95
+              <i class="bx bx-refresh me-1"></i> Genera Tabellone
96
+            </button>
97
+          </form>
98
+          <small class="text-muted d-block mt-2">Resetta tutti i numeri come non estratti.</small>
99
+        </div>
100
+        @endif
101
+
102
+
81 103
       </div>
82 104
     </div>
83 105
   </div>

+ 4
- 4
resources/views/tombola/tabellone.blade.php Näytä tiedosto

@@ -1,14 +1,14 @@
1 1
 @extends('layouts/guest')
2 2
 @php
3 3
     use App\Models\Tombola;
4
-    $tutti = Tombola::orderBy('numero')->get();
5
-    $estratti = Tombola::where('estratto', true)
4
+    $tutti = Tombola::where('attivita_id', $attivita->id)->orderBy('numero')->get();
5
+    $estratti = Tombola::where('attivita_id', $attivita->id)->where('estratto', true)
6 6
         ->orderByDesc('estratto_at')
7 7
         ->pluck('numero')
8 8
         ->toArray();
9 9
     $ultimoEstratto = $estratti[0] ?? null;
10 10
     $storicoEstratti = array_slice($estratti, 1, 30);
11
-    $estrattiPublicUrl = route('cliente.tombola.estratti');
11
+    $estrattiPublicUrl = route('cliente.tombola.estratti', ['attivita_id' => $attivita->id]);
12 12
     $qrCodeUrl = 'https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=' . rawurlencode($estrattiPublicUrl);
13 13
 @endphp
14 14
 
@@ -463,7 +463,7 @@
463 463
                         <img src="{{ $qrCodeUrl }}" alt="QR code numeri estratti" class="tabellone-qr-img">
464 464
                         <p class="tabellone-qr-caption">Scansiona per vedere solo gli estratti</p>
465 465
                     </div>
466
-                    <form action="{{ route('tombola.estrai') }}" method="POST" id="tombola-estrazione-form">
466
+                    <form action="{{ route('tombola.estrai', ['attivita_id' => $attivita->id]) }}" method="POST" id="tombola-estrazione-form">
467 467
                         @csrf
468 468
                         <button type="submit" class="btn btn-primary w-100" id="tombola-estrazione-btn">Estrai Numero</button>
469 469
                     </form>

+ 5
- 2
resources/views/user/index.blade.php Näytä tiedosto

@@ -35,14 +35,17 @@ use Illuminate\Support\Facades\Auth;
35 35
 
36 36
 @section('pageTitle')
37 37
 <div class="d-flex flex-column">
38
-  <h4 class="mb-1">Utenti</h4>
38
+  <h4 class="mb-1 text-sm-small">
39
+    <i class="bx bx-building d-none d-md-inline-flex d-lg-inline-flex"></i>
40
+    Organizzazioni
41
+  </h4>
39 42
 </div>
40 43
 @endsection
41 44
 
42 45
 @section('content')
43 46
 
44 47
 <div class="row">
45
-  <div class="col mb-4 mt-2">
48
+  <div class="col col-12 mb-4 mt-2">
46 49
 
47 50
   @include('_partials.status')
48 51
     <!-- @if(session('success'))

+ 3
- 0
resources/views/voucher/index.blade.php Näytä tiedosto

@@ -0,0 +1,3 @@
1
+<div>
2
+    <!-- When there is no desire, all things are at peace. - Laozi -->
3
+</div>

+ 8
- 7
routes/web.php Näytä tiedosto

@@ -149,7 +149,7 @@ Route::middleware(['auth:sanctum', AttivitaMiddleware::class, config('jetstream.
149 149
 
150 150
   
151 151
   // Prima Nota
152
-  Route::resource('primanota', PrimaNotaController::class, ['only' => ['index', 'store']]);
152
+  Route::resource('prima-nota', PrimaNotaController::class, ['only' => ['index', 'store']])->names('prima-nota');
153 153
   
154 154
   // Pagamento
155 155
   Route::resource('pagamento', PagamentoController::class, ['only' => ['index', 'store']]);
@@ -186,7 +186,7 @@ Route::middleware(['auth:sanctum', AttivitaMiddleware::class, config('jetstream.
186 186
   Route::resource('mappa-dispositivi', MappaDispositiviController::class, ['only' => ['index', 'store']]);
187 187
   // Metodo Pagamento
188 188
   Route::resource('metodo-pagamento', MetodoPagamentoController::class, ['only' => ['index', 'store']]);
189
-
189
+  Route::post('metodo-pagamento/segresta-wallet/chiE', [MetodoPagamentoController::class, 'segresta_wallet_chiE'])->name('metodo-pagamento.segresta-wallet.chiE');
190 190
   //Dashboard
191 191
 Route::get('dashboard', [HomePageController::class, 'admin_dashboard'])->name('dashboard');
192 192
 
@@ -229,10 +229,11 @@ Route::resource('testi', TestiController::class, ['only' => ['index', 'store']])
229 229
 
230 230
 //Tombola
231 231
 Route::resource('tombola', TombolaController::class, ['only' => ['index', 'store']]);
232
-Route::get('tombola/tabellone', [TombolaController::class, 'tabellone'])->name('tombola.tabellone');
233
-Route::post('tombola/estrai', [TombolaController::class, 'estrai'])->name('tombola.estrai');
234
-Route::post('tombola/azzera', [TombolaController::class, 'azzera'])->name('tombola.azzera');
235
-Route::get('tombola/estratti', [TombolaController::class, 'estratti'])->name('tombola.estratti');
232
+Route::get('tombola/{attivita_id}/tabellone', [TombolaController::class, 'tabellone'])->name('tombola.tabellone');
233
+Route::post('tombola/{attivita_id}/estrai', [TombolaController::class, 'estrai'])->name('tombola.estrai');
234
+Route::post('tombola/{attivita_id}/azzera', [TombolaController::class, 'azzera'])->name('tombola.azzera');
235
+Route::get('tombola/{attivita_id}/estratti', [TombolaController::class, 'estratti'])->name('tombola.estratti');
236
+Route::post('tombola/getTabellone', [TombolaController::class, 'getTabellone'])->name('tombola.getTabellone');
236 237
 });
237 238
 
238 239
 
@@ -271,7 +272,7 @@ Route::prefix('cliente')->group(function(){
271 272
   Route::get('saltacoda/pre-ordine/show', [SaltacodaController::class, 'pre_ordine_show'])->name('saltacoda.pre-ordine.show');
272 273
 
273 274
   // Tombola (pubblico, per QR)
274
-  Route::get('tombola/estratti', [TombolaController::class, 'estratti'])->name('cliente.tombola.estratti');
275
+  Route::get('tombola/{attivita_id}/estratti', [TombolaController::class, 'estratti'])->name('cliente.tombola.estratti');
275 276
 
276 277
 });
277 278
 

Loading…
Peruuta
Tallenna