Browse Source

WIP: redesign clienti

Fabio Dalle Ave 2 tháng trước cách đây
mục cha
commit
2e4c66b266

+ 1 - 0
lib/core/constants.dart

@@ -13,4 +13,5 @@ class AppConstants {
   static const String kUrlParam = 'URL';
   static const String kLastUpdateParam = 'LAST_UPDATE';
   static const String kCustomerName = 'Ristoris';
+  static const String kBlocco = '001';
 }

+ 1 - 1
lib/ui/pages/customers/customer_detail_page.dart

@@ -56,7 +56,7 @@ class CustomerDetailPage extends ConsumerWidget {
               return TabBarView(
                 children: [
                   InfoTab(cliente: cliente, theme: theme),
-                  OrdersTab(idCliente: id, theme: theme),
+                  OrdersTab(cliente: cliente, theme: theme),
                   DestinationsTab(idCliente: id, theme: theme),
                   PaymentsTab(
                     idCliente: id ?? 0,

+ 461 - 17
lib/ui/pages/customers/tabs/orders_tab.dart

@@ -1,43 +1,487 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:ristoris/core/utils.dart';
-import 'package:ristoris/providers/database_provider.dart';
 import 'package:go_router/go_router.dart';
+import 'package:intl/intl.dart';
+import 'package:ristoris/database/database.dart';
+import 'package:ristoris/providers/database_provider.dart';
+import 'package:ristoris/core/constants.dart';
+import 'package:ristoris/ui/widgets/order_actions.dart';
+
+String _statoLabel(String? stato) {
+  switch (stato) {
+    case AppConstants.kStatusNew:
+      return 'Nuovo';
+    case AppConstants.kStatusTransferred:
+      return 'Trasmesso';
+    case AppConstants.kStatoHold:
+      return 'Sospeso';
+    default:
+      return stato ?? '';
+  }
+}
+
+Color _statoColor(String? stato) {
+  switch (stato) {
+    case AppConstants.kStatusNew:
+      return Colors.orange;
+    case AppConstants.kStatusTransferred:
+      return Colors.green;
+    case AppConstants.kStatoHold:
+      return Colors.blue;
+    default:
+      return Colors.grey;
+  }
+}
+
+class _StatoPill extends StatelessWidget {
+  final String? stato;
+  const _StatoPill({this.stato});
+
+  @override
+  Widget build(BuildContext context) {
+    final label = _statoLabel(stato);
+    final color = _statoColor(stato);
+
+    return Container(
+      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
+      decoration: BoxDecoration(
+        color: color.withAlpha(25),
+        borderRadius: BorderRadius.circular(4),
+      ),
+      child: Text(
+        label,
+        textAlign: TextAlign.center,
+        style: TextStyle(
+          fontSize: 12,
+          height: 16 / 12,
+          fontWeight: FontWeight.w500,
+          color: color,
+        ),
+      ),
+    );
+  }
+}
 
 class OrdersTab extends ConsumerWidget {
-  final int idCliente;
+  final Cliente cliente;
   final ThemeData theme;
-  const OrdersTab({required this.idCliente, required this.theme});
+  const OrdersTab({required this.cliente, required this.theme, super.key});
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final ordiniDao = ref.read(ordiniDaoProvider);
+    final isPhone = MediaQuery.of(context).size.width < 600;
+
+    Future<void> deleteOrder(VOrdiniData o) async {
+      final dao = ref.read(ordiniDaoProvider);
+      await dao.zapOrderLines(o.idOrdine);
+      await dao.deleteOrder(o.idOrdine);
+      if (context.mounted) context.go('/dashboard/customers');
+    }
+
+    final blocco = cliente.codBlocco;
+    final isBloccato = blocco == '001';
+    final hasWarning =
+        blocco != null && blocco.isNotEmpty && blocco != '001';
+
     return Scaffold(
       body: SafeArea(
         child: FutureBuilder(
-          future: ordiniDao.customerOrdersWidthData(idCliente, false),
+          future: ordiniDao.customerOrdersWidthData(cliente.idCliente, false),
           builder: (_, snap) {
             if (!snap.hasData) {
               return const Center(child: CircularProgressIndicator());
             }
             final orders = snap.data!;
-            if (orders.isEmpty) return const Center(child: Text('Nessun ordine'));
-            return ListView.builder(
-              itemCount: orders.length,
-              itemBuilder: (_, i) => ListTile(
-                title: Text('Ordine #${orders[i].numeroOrdine ?? ""}'),
-                subtitle: Text(Utils.formatDate(orders[i].dataOrdine) ?? ''),
-                onTap: () => context.push('/dashboard/orders/${orders[i].idOrdine}'),
-              ),
+            if (orders.isEmpty) {
+              return const Center(child: Text('Nessun ordine'));
+            }
+            if (isPhone) {
+              return ListView.builder(
+                padding: const EdgeInsets.all(16),
+                itemCount: orders.length,
+                itemBuilder: (_, i) => _OrderCard(
+                  order: orders[i],
+                  onEdit: () =>
+                      context.push('/dashboard/orders/${orders[i].idOrdine}'),
+                  onDelete: () => deleteOrder(orders[i]),
+                ),
+              );
+            }
+            return _OrderTable(
+              orders: orders,
+              onEdit: (o) => context.push('/dashboard/orders/${o.idOrdine}'),
+              onDelete: deleteOrder,
             );
           },
         ),
       ),
-      floatingActionButton: FloatingActionButton(
-        heroTag: 'addOrder',
-        child: const Icon(Icons.add),
-        onPressed: () => context.push('/dashboard/orders/new?cliente=$idCliente'),
+      floatingActionButton: isBloccato
+          ? null
+          : FloatingActionButton(
+              heroTag: 'addOrder',
+              backgroundColor: hasWarning ? Colors.amber : null,
+              onPressed: () {
+                if (hasWarning) {
+                  ScaffoldMessenger.of(context).showSnackBar(
+                    SnackBar(
+                      content: Text('Attenzione: cliente con blocco $blocco'),
+                      backgroundColor: Colors.amber.shade800,
+                    ),
+                  );
+                }
+                context.push('/dashboard/orders/new?cliente=${cliente.idCliente}');
+              },
+              child: hasWarning
+                  ? const Icon(Icons.warning_amber_rounded)
+                  : const Icon(Icons.add),
+            ),
+    );
+  }
+}
+
+class _OrderCard extends StatelessWidget {
+  final VOrdiniData order;
+  final VoidCallback onEdit;
+  final Future<void> Function() onDelete;
+  const _OrderCard({
+    required this.order,
+    required this.onEdit,
+    required this.onDelete,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final theme = Theme.of(context);
+    final cs = theme.colorScheme;
+    final dateFormat = DateFormat('dd/MM/yyyy');
+    final currencyFormat = NumberFormat.currency(
+      symbol: '€ ',
+      decimalDigits: 2,
+    );
+
+    return Card(
+      margin: const EdgeInsets.only(bottom: 12),
+      elevation: 0,
+      shape: RoundedRectangleBorder(
+        borderRadius: BorderRadius.circular(12),
+        side: BorderSide(color: cs.outlineVariant),
+      ),
+      child: InkWell(
+        onTap: onEdit,
+        borderRadius: BorderRadius.circular(12),
+        child: Padding(
+          padding: const EdgeInsets.all(16),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Row(
+                children: [
+                  Expanded(
+                    child: Text(
+                      '#${order.numeroOrdine ?? ''}',
+                      style: theme.textTheme.titleMedium?.copyWith(
+                        fontWeight: FontWeight.bold,
+                      ),
+                    ),
+                  ),
+                  Text(
+                    order.dataOrdine != null ? dateFormat.format(DateTime.parse(order.dataOrdine!)) : '',
+                    style: theme.textTheme.bodyMedium?.copyWith(
+                      color: cs.onSurfaceVariant,
+                    ),
+                  ),
+                  const SizedBox(width: 8),
+                  _StatoPill(stato: order.stato),
+                ],
+              ),
+              const SizedBox(height: 8),
+              Text(
+                '${order.filiale ?? ''}${order.indirizzo ?? ''} ${order.citta ?? ''}${order.provincia != null ? ' (${order.provincia})' : ''}',
+                style: theme.textTheme.bodySmall?.copyWith(
+                  color: cs.onSurfaceVariant,
+                ),
+                maxLines: 2,
+                overflow: TextOverflow.ellipsis,
+              ),
+              const SizedBox(height: 12),
+              Center(
+                child: Text(
+                  currencyFormat.format(order.totale ?? 0),
+                  style: theme.textTheme.titleLarge?.copyWith(
+                    fontWeight: FontWeight.bold,
+                  ),
+                ),
+              ),
+              const SizedBox(height: 8),
+              Align(
+                alignment: Alignment.centerRight,
+                child: OrderActions(
+                  order: order,
+                  onEdit: onEdit,
+                  onDelete: onDelete,
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class _OrderTable extends StatelessWidget {
+  final List<VOrdiniData> orders;
+  final void Function(VOrdiniData) onEdit;
+  final Future<void> Function(VOrdiniData) onDelete;
+  const _OrderTable({
+    required this.orders,
+    required this.onEdit,
+    required this.onDelete,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final theme = Theme.of(context);
+    final cs = theme.colorScheme;
+    final dateFormat = DateFormat('dd/MM/yyyy');
+    final currencyFormat = NumberFormat.currency(
+      symbol: '€ ',
+      decimalDigits: 2,
+    );
+
+    return LayoutBuilder(
+      builder: (context, constraints) {
+        final isCompact = constraints.maxWidth < 1024;
+        return SingleChildScrollView(
+          scrollDirection: Axis.horizontal,
+          child: ConstrainedBox(
+            constraints: BoxConstraints(
+              minWidth: constraints.maxWidth,
+              maxWidth: constraints.maxWidth,
+            ),
+            child: Column(
+              children: [
+                Container(
+                  padding: const EdgeInsets.symmetric(
+                    horizontal: 24,
+                    vertical: 14,
+                  ),
+                  decoration: BoxDecoration(
+                    color: cs.surfaceContainerHighest.withAlpha(50),
+                    border: Border(
+                      bottom: BorderSide(color: cs.outlineVariant),
+                    ),
+                  ),
+                  child: Row(
+                    children: isCompact
+                        ? [
+                            _headerCell(context, 'Ordine', flex: 3),
+                            _headerCell(context, 'Destinazione', flex: 5),
+                            _headerCell(context, 'Totale', flex: 2),
+                            _headerCell(context, 'Stato', flex: 2),
+                            _headerCell(context, 'Azioni', flex: 2),
+                          ]
+                        : [
+                            _headerCell(context, 'N. Ordine', flex: 1),
+                            _headerCell(context, 'Data', flex: 2),
+                            _headerCell(context, 'Destinazione', flex: 5),
+                            _headerCell(context, 'Totale', flex: 2),
+                            _headerCell(context, 'Stato', flex: 1),
+                            _headerCell(context, 'Azioni', flex: 2),
+                          ],
+                  ),
+                ),
+                Expanded(
+                  child: SingleChildScrollView(
+                    scrollDirection: Axis.vertical,
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.stretch,
+                      children: orders.map((o) {
+                        return Container(
+                          padding: const EdgeInsets.symmetric(
+                            horizontal: 24,
+                            vertical: 16,
+                          ),
+                          decoration: BoxDecoration(
+                            border: Border(
+                              bottom: BorderSide(
+                                color: cs.outlineVariant.withAlpha(80),
+                              ),
+                            ),
+                          ),
+                          child: InkWell(
+                            onTap: () => onEdit(o),
+                            child: Row(
+                              children: isCompact
+                                  ? [
+                                      _cell(
+                                        Column(
+                                          mainAxisAlignment: MainAxisAlignment.center,
+                                          crossAxisAlignment: CrossAxisAlignment.start,
+                                          children: [
+                                            Text(
+                                              '${o.numeroOrdine ?? ''}',
+                                              style: theme.textTheme.bodyMedium?.copyWith(
+                                                fontWeight: FontWeight.bold,
+                                                fontFamily: 'monospace',
+                                              ),
+                                            ),
+                                            const SizedBox(height: 4),
+                                            Text(
+                                              o.dataOrdine != null
+                                                  ? dateFormat.format(
+                                                      DateTime.parse(
+                                                        o.dataOrdine!,
+                                                      ),
+                                                    )
+                                                  : '',
+                                              style: theme.textTheme.bodySmall?.copyWith(
+                                                color: cs.onSurfaceVariant,
+                                              ),
+                                            ),
+                                          ],
+                                        ),
+                                        flex: 3,
+                                      ),
+                                      _cell(
+                                        Text(
+                                          '${o.filiale ?? ''} ${o.indirizzo ?? ''} ${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
+                                          style: theme.textTheme.bodyMedium?.copyWith(
+                                            color: cs.onSurfaceVariant,
+                                          ),
+                                          maxLines: 2,
+                                          overflow: TextOverflow.ellipsis,
+                                        ),
+                                        flex: 5,
+                                      ),
+                                      _cell(
+                                        Padding(
+                                          padding: const EdgeInsets.only(
+                                            right: 16,
+                                          ),
+                                          child: Text(
+                                            currencyFormat.format(
+                                              o.totale ?? 0,
+                                            ),
+                                            style: theme.textTheme.bodyMedium?.copyWith(
+                                              fontWeight: FontWeight.bold,
+                                            ),
+                                            textAlign: TextAlign.right,
+                                          ),
+                                        ),
+                                        flex: 2,
+                                      ),
+                                      _cell(
+                                        _StatoPill(stato: o.stato),
+                                        flex: 2,
+                                      ),
+                                      _cell(
+                                        OrderActions(
+                                          order: o,
+                                          onEdit: () => onEdit(o),
+                                          onDelete: () => onDelete(o),
+                                        ),
+                                        flex: 2,
+                                      ),
+                                    ]
+                                  : [
+                                      _cell(
+                                        Text(
+                                          '${o.numeroOrdine ?? ''}',
+                                          style: theme.textTheme.bodyMedium?.copyWith(
+                                            fontWeight: FontWeight.bold,
+                                            fontFamily: 'monospace',
+                                          ),
+                                        ),
+                                        flex: 1,
+                                      ),
+                                      _cell(
+                                        Text(
+                                          o.dataOrdine != null
+                                              ? dateFormat.format(
+                                                  DateTime.parse(
+                                                    o.dataOrdine!,
+                                                  ),
+                                                )
+                                              : '',
+                                          style: theme.textTheme.bodyMedium?.copyWith(
+                                            color: cs.onSurfaceVariant,
+                                          ),
+                                        ),
+                                        flex: 2,
+                                      ),
+                                      _cell(
+                                        Text(
+                                          '${o.filiale ?? ''} ${o.indirizzo ?? ''} ${o.citta ?? ''}${o.provincia != null ? ' (${o.provincia})' : ''}',
+                                          style: theme.textTheme.bodyMedium?.copyWith(
+                                            color: cs.onSurfaceVariant,
+                                          ),
+                                          maxLines: 2,
+                                          overflow: TextOverflow.ellipsis,
+                                        ),
+                                        flex: 5,
+                                      ),
+                                      _cell(
+                                        Padding(
+                                          padding: const EdgeInsets.only(
+                                            right: 16,
+                                          ),
+                                          child: Text(
+                                            currencyFormat.format(
+                                              o.totale ?? 0,
+                                            ),
+                                            style: theme.textTheme.bodyMedium?.copyWith(
+                                              fontWeight: FontWeight.bold,
+                                            ),
+                                            textAlign: TextAlign.right,
+                                          ),
+                                        ),
+                                        flex: 2,
+                                      ),
+                                      _cell(
+                                        _StatoPill(stato: o.stato),
+                                        flex: 1,
+                                      ),
+                                      _cell(
+                                        OrderActions(
+                                          order: o,
+                                          onEdit: () => onEdit(o),
+                                          onDelete: () => onDelete(o),
+                                        ),
+                                        flex: 2,
+                                      ),
+                                    ],
+                            ),
+                          ),
+                        );
+                      }).toList(),
+                    ),
+                  ),
+                ),
+              ],
+            ),
+          ),
+        );
+      },
+    );
+  }
+
+  Widget _headerCell(BuildContext context, String label, {int flex = 1}) {
+    return Expanded(
+      flex: flex,
+      child: Text(
+        label,
+        style: TextStyle(
+          fontSize: 12,
+          fontWeight: FontWeight.w600,
+          color: Theme.of(context).colorScheme.onSurfaceVariant,
+        ),
       ),
     );
   }
+
+  Widget _cell(Widget child, {int flex = 1}) {
+    return Expanded(flex: flex, child: child);
+  }
 }

+ 16 - 87
lib/ui/pages/orders/order_list_page.dart

@@ -9,6 +9,7 @@ import '../../../providers/database_provider.dart';
 import '../../../database/database.dart';
 import '../../widgets/search_bar.dart' as sw;
 import '../../widgets/empty_state.dart';
+import '../../widgets/order_actions.dart';
 import '../../../core/constants.dart';
 
 String _statoLabel(String? stato) {
@@ -301,35 +302,13 @@ class _OrderCard extends StatelessWidget {
                 ),
               ),
               const SizedBox(height: 8),
-              Row(
-                mainAxisAlignment: MainAxisAlignment.end,
-                children: [
-                  if (order.stato == AppConstants.kStatusNew) ...[
-                    IconButton(
-                      icon: const Icon(Icons.edit, size: 20),
-                      onPressed: onEdit,
-                      visualDensity: VisualDensity.compact,
-                    ),
-                    IconButton(
-                      icon: Icon(
-                        Icons.delete_outline,
-                        size: 20,
-                        color: cs.error,
-                      ),
-                      onPressed: onDelete,
-                      visualDensity: VisualDensity.compact,
-                    ),
-                  ] else
-                    IconButton(
-                      icon: Icon(
-                        Icons.visibility,
-                        size: 20,
-                        color: cs.secondary,
-                      ),
-                      onPressed: onEdit,
-                      visualDensity: VisualDensity.compact,
-                    ),
-                ],
+              Align(
+                alignment: Alignment.centerRight,
+                child: OrderActions(
+                  order: order,
+                  onEdit: onEdit,
+                  onDelete: onDelete,
+                ),
               ),
             ],
           ),
@@ -513,35 +492,10 @@ class _OrderTable extends StatelessWidget {
                                           flex: 1,
                                         ),
                                         _cell(
-                                          Row(
-                                            mainAxisSize: MainAxisSize.min,
-                                            children: [
-                                              if (o.stato == AppConstants.kStatusNew) ...[
-                                                IconButton(
-                                                  icon: const Icon(Icons.edit, size: 20),
-                                                  onPressed: () => onEdit(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                                IconButton(
-                                                  icon: Icon(
-                                                    Icons.delete_outline,
-                                                    size: 20,
-                                                    color: cs.error,
-                                                  ),
-                                                  onPressed: () => onDelete(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                              ] else
-                                                IconButton(
-                                                  icon: Icon(
-                                                    Icons.visibility,
-                                                    size: 20,
-                                                    color: cs.secondary,
-                                                  ),
-                                                  onPressed: () => onEdit(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                            ],
+                                          OrderActions(
+                                            order: o,
+                                            onEdit: () => onEdit(o),
+                                            onDelete: () => onDelete(o),
                                           ),
                                           flex: 2,
                                         ),
@@ -618,35 +572,10 @@ class _OrderTable extends StatelessWidget {
                                           flex: 1,
                                         ),
                                         _cell(
-                                          Row(
-                                            mainAxisSize: MainAxisSize.min,
-                                            children: [
-                                              if (o.stato == AppConstants.kStatusNew) ...[
-                                                IconButton(
-                                                  icon: const Icon(Icons.edit, size: 20),
-                                                  onPressed: () => onEdit(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                                IconButton(
-                                                  icon: Icon(
-                                                    Icons.delete_outline,
-                                                    size: 20,
-                                                    color: cs.error,
-                                                  ),
-                                                  onPressed: () => onDelete(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                              ] else
-                                                IconButton(
-                                                  icon: Icon(
-                                                    Icons.visibility,
-                                                    size: 20,
-                                                    color: cs.secondary,
-                                                  ),
-                                                  onPressed: () => onEdit(o),
-                                                  visualDensity: VisualDensity.compact,
-                                                ),
-                                            ],
+                                          OrderActions(
+                                            order: o,
+                                            onEdit: () => onEdit(o),
+                                            onDelete: () => onDelete(o),
                                           ),
                                           flex: 2,
                                         ),

+ 57 - 21
lib/ui/widgets/customer_card.dart

@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:go_router/go_router.dart';
+import 'package:ristoris/core/constants.dart';
 import 'package:ristoris/core/credit_score_color.dart';
 import 'package:ristoris/database/database.dart';
 
@@ -51,8 +52,7 @@ class CustomerCard extends StatelessWidget {
                               vertical: 4,
                             ),
                             decoration: BoxDecoration(
-                              color: creditScoreBg(cliente.creditScoreColor) ??
-                                  cs.surfaceContainerHighest,
+                              color: creditScoreBg(cliente.creditScoreColor) ?? cs.surfaceContainerHighest,
                               borderRadius: BorderRadius.circular(4),
                             ),
                             child: Text(
@@ -61,11 +61,7 @@ class CustomerCard extends StatelessWidget {
                                 fontSize: 12,
                                 height: 16 / 12,
                                 fontWeight: FontWeight.w500,
-                                color:
-                                    creditScoreBg(cliente.creditScoreColor) !=
-                                            null
-                                        ? Colors.white
-                                        : cs.onSurfaceVariant,
+                                color: creditScoreBg(cliente.creditScoreColor) != null ? Colors.white : cs.onSurfaceVariant,
                               ),
                             ),
                           ),
@@ -131,10 +127,8 @@ class CustomerCard extends StatelessWidget {
                         Expanded(
                           child: Text(
                             [
-                              if ((cliente.citta ?? '').isNotEmpty)
-                                cliente.citta,
-                              if ((cliente.provincia ?? '').isNotEmpty)
-                                cliente.provincia,
+                              if ((cliente.citta ?? '').isNotEmpty) cliente.citta,
+                              if ((cliente.provincia ?? '').isNotEmpty) cliente.provincia,
                             ].join(', '),
                             style: theme.textTheme.bodyMedium?.copyWith(
                               color: cs.onSurfaceVariant,
@@ -169,16 +163,7 @@ class CustomerCard extends StatelessWidget {
                   ),
                   const SizedBox(width: 8),
                   Expanded(
-                    child: FilledButton.icon(
-                      onPressed: () => context.go(
-                        '/dashboard/orders/new?cliente=${cliente.idCliente}',
-                      ),
-                      icon: const Icon(
-                        Icons.add_shopping_cart_outlined,
-                        size: 18,
-                      ),
-                      label: const Text('Ordine'),
-                    ),
+                    child: _buildOrdineButton(context),
                   ),
                 ],
               ),
@@ -188,4 +173,55 @@ class CustomerCard extends StatelessWidget {
       ),
     );
   }
+
+  Widget _buildOrdineButton(BuildContext context) {
+    final cs = Theme.of(context).colorScheme;
+    final blocco = cliente.codBlocco;
+    final isBloccato = blocco == '001';
+    final hasWarning = blocco != null && blocco.isNotEmpty && blocco != '001';
+
+    if (isBloccato) {
+      return FilledButton.icon(
+        onPressed: null,
+        icon: const Icon(Icons.block, size: 18),
+        label: const Text('Ordine'),
+        style: FilledButton.styleFrom(
+          backgroundColor: cs.surfaceContainerHighest,
+          foregroundColor: cs.onSurfaceVariant,
+        ),
+      );
+    }
+
+    return FilledButton.icon(
+      onPressed: () {
+        if (hasWarning) {
+          ScaffoldMessenger.of(context).showSnackBar(
+            SnackBar(
+              content: Text('Attenzione: cliente con blocco $blocco'),
+              backgroundColor: Colors.amber.shade800,
+            ),
+          );
+        }
+        context.go('/dashboard/orders/new?cliente=${cliente.idCliente}');
+      },
+      icon: hasWarning ? const Icon(Icons.warning_amber_rounded, size: 18) : const Icon(Icons.add_shopping_cart_outlined, size: 18),
+      label: const Text('Ordine'),
+      style: getBloccoColors(blocco),
+    );
+  }
+
+  ButtonStyle? getBloccoColors(String? codBlocco) {
+    if (codBlocco == AppConstants.kBlocco) {
+      return FilledButton.styleFrom(
+        backgroundColor: Colors.deepOrange,
+        foregroundColor: Colors.black87,
+      );
+    } else if (codBlocco != null && codBlocco.isNotEmpty) {
+      return FilledButton.styleFrom(
+        backgroundColor: Colors.amber,
+        foregroundColor: Colors.black87,
+      );
+    }
+    return null;
+  }
 }

+ 75 - 0
lib/ui/widgets/order_actions.dart

@@ -0,0 +1,75 @@
+import 'package:flutter/material.dart';
+import 'package:ristoris/core/constants.dart';
+import 'package:ristoris/database/database.dart';
+
+class OrderActions extends StatelessWidget {
+  final VOrdiniData order;
+  final VoidCallback onEdit;
+  final VoidCallback onDelete;
+
+  const OrderActions({
+    super.key,
+    required this.order,
+    required this.onEdit,
+    required this.onDelete,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final cs = Theme.of(context).colorScheme;
+
+    if (order.stato == AppConstants.kStatusNew) {
+      return Row(
+        mainAxisSize: MainAxisSize.min,
+        children: [
+          IconButton(
+            icon: const Icon(Icons.edit, size: 20),
+            onPressed: onEdit,
+            visualDensity: VisualDensity.compact,
+          ),
+          IconButton(
+            icon: Icon(Icons.delete_outline, size: 20, color: cs.error),
+            onPressed: () => _confirmDelete(context),
+            visualDensity: VisualDensity.compact,
+          ),
+        ],
+      );
+    }
+
+    return Row(
+      mainAxisSize: MainAxisSize.min,
+      children: [
+        IconButton(
+          icon: Icon(Icons.visibility, size: 20, color: cs.secondary),
+          onPressed: onEdit,
+          visualDensity: VisualDensity.compact,
+        ),
+      ],
+    );
+  }
+
+  Future<void> _confirmDelete(BuildContext context) async {
+    final confirmed = await showDialog<bool>(
+      context: context,
+      builder: (ctx) => AlertDialog(
+        title: const Text('Elimina ordine'),
+        content: Text(
+          'Vuoi eliminare l\'ordine n. ${order.numeroOrdine ?? order.idOrdine}?',
+        ),
+        actions: [
+          TextButton(
+            onPressed: () => Navigator.pop(ctx, false),
+            child: const Text('Annulla'),
+          ),
+          FilledButton(
+            onPressed: () => Navigator.pop(ctx, true),
+            child: const Text('Elimina'),
+          ),
+        ],
+      ),
+    );
+    if (confirmed == true && context.mounted) {
+      onDelete();
+    }
+  }
+}