| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- import 'package:flutter/material.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:go_router/go_router.dart';
- import 'package:intl/intl.dart';
- import 'package:ristoris/providers/database_provider.dart';
- import '../../../providers/auth_provider.dart';
- import '../../../providers/dashboard_provider.dart';
- import '../../../core/responsive.dart';
- import '../../widgets/app_drawer.dart';
- class DashboardPage extends ConsumerWidget {
- const DashboardPage({super.key});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final authState = ref.watch(authProvider);
- final agente = authState.agente;
- final dashboardAsync =
- agente != null ? ref.watch(dashboardProvider(agente.idAgente)) : null;
- final agentiAsync = ref.watch(agentiListProvider);
- final theme = Theme.of(context);
- return Scaffold(
- appBar: AppBar(title: Text('Benvenuto, ${agente?.ragioneSociale ?? ''}')),
- drawer: AppDrawer(
- agente: agente,
- onDashboard: () => context.go('/dashboard'),
- onOrders: () => context.go('/dashboard/orders'),
- onCustomers: () => context.go('/dashboard/customers'),
- onCatalog: () => context.go('/dashboard/catalog'),
- onPromotions: () => context.go('/dashboard/promotions'),
- onPayments: () => context.go('/dashboard/payments'),
- onStatistics: () => context.go('/dashboard/statistics'),
- onSync: () => context.go('/dashboard/sync'),
- onSwitchAgent: () => context.go('/dashboard/switch-agent'),
- onLogout: () => ref.read(authProvider.notifier).logout(),
- ),
- body: SafeArea(
- child: dashboardAsync?.when(
- data: (data) {
- final agentiList = agentiAsync.asData?.value;
- final hasMultipleAgents =
- agentiList != null && agentiList.length > 1;
- return _DashboardContent(
- data: data,
- theme: theme,
- hasMultipleAgents: hasMultipleAgents,
- );
- },
- loading: () => const Center(child: CircularProgressIndicator()),
- error: (e, _) => Center(child: Text('Errore: $e')),
- ) ??
- const Center(child: CircularProgressIndicator()),
- ),
- );
- }
- }
- class _DashboardContent extends StatelessWidget {
- final DashboardData data;
- final ThemeData theme;
- final bool hasMultipleAgents;
- const _DashboardContent({
- required this.data,
- required this.theme,
- this.hasMultipleAgents = false,
- });
- @override
- Widget build(BuildContext context) {
- return SingleChildScrollView(
- padding: ResponsiveBreakpoints.padding(context),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- // Quick action cards
- Wrap(
- spacing: 12,
- runSpacing: 12,
- children: [
- _ActionCard(
- icon: Icons.receipt_long,
- label: 'Nuovo Ordine',
- color: theme.colorScheme.primary,
- onTap: () => context.go('/dashboard/orders/new'),
- ),
- _ActionCard(
- icon: Icons.people,
- label: 'Clienti',
- color: theme.colorScheme.tertiary,
- onTap: () => context.go('/dashboard/customers'),
- ),
- _ActionCard(
- icon: Icons.inventory_2,
- label: 'Catalogo',
- color: theme.colorScheme.secondary,
- onTap: () => context.go('/dashboard/catalog'),
- ),
- _ActionCard(
- icon: Icons.sync,
- label: 'Sincronizza',
- color: theme.colorScheme.error,
- onTap: () => context.go('/dashboard/sync'),
- ),
- ],
- ),
- const SizedBox(height: 24),
- // Stats cards
- Wrap(
- spacing: 12,
- runSpacing: 12,
- children: [
- _StatCard(
- label: 'Ordini',
- value: data.newOrdersCount.toString(),
- icon: Icons.receipt_long,
- color: theme.colorScheme.primary,
- onTap: () => context.go('/dashboard/orders'),
- ),
- _StatCard(
- label: 'Ordini in Sospeso',
- value: data.ordersOnHoldCount.toString(),
- icon: Icons.pause_circle,
- color: theme.colorScheme.tertiary,
- ),
- _StatCard(
- label: 'Nuovi Clienti',
- value: data.newCustomersCount.toString(),
- icon: Icons.person_add,
- color: theme.colorScheme.secondary,
- ),
- ],
- ),
- const SizedBox(height: 24),
- // Top items
- if (data.topItems.isNotEmpty) ...[
- Text(
- 'Articoli Più Venduti',
- style: theme.textTheme.titleMedium?.copyWith(
- fontWeight: FontWeight.bold,
- ),
- ),
- const SizedBox(height: 8),
- Card(
- child: Column(
- children: data.topItems
- .map(
- (item) => ListTile(
- leading: CircleAvatar(
- child: Text(
- item.codArticolo?.substring(0, 2) ?? '??',
- ),
- ),
- title: Text(item.descrizione ?? ''),
- trailing: Text(
- NumberFormat.currency(
- locale: 'it',
- symbol: '€',
- ).format(item.totale ?? 0),
- ),
- ),
- )
- .toList(),
- ),
- ),
- ],
- // Top customers
- if (data.topCustomers.isNotEmpty) ...[
- const SizedBox(height: 16),
- Text(
- 'Top Clienti',
- style: theme.textTheme.titleMedium?.copyWith(
- fontWeight: FontWeight.bold,
- ),
- ),
- const SizedBox(height: 8),
- Card(
- child: Column(
- children: data.topCustomers
- .map(
- (c) => ListTile(
- leading: CircleAvatar(
- child: Text(c.codCliente?.substring(0, 2) ?? '??'),
- ),
- title: Text(c.ragioneSociale ?? ''),
- trailing: Text(
- NumberFormat.currency(
- locale: 'it',
- symbol: '€',
- ).format(c.totale ?? 0),
- ),
- ),
- )
- .toList(),
- ),
- ),
- ],
- if (hasMultipleAgents) ...[
- const SizedBox(height: 24),
- SizedBox(
- width: double.infinity,
- child: OutlinedButton.icon(
- onPressed: () => context.go('/dashboard/switch-agent'),
- icon: const Icon(Icons.swap_horiz),
- label: const Text('Cambia agente'),
- ),
- ),
- const SizedBox(height: 16),
- ],
- ],
- ),
- );
- }
- }
- class _ActionCard extends StatelessWidget {
- final IconData icon;
- final String label;
- final Color color;
- final VoidCallback onTap;
- const _ActionCard({
- required this.icon,
- required this.label,
- required this.color,
- required this.onTap,
- });
- @override
- Widget build(BuildContext context) {
- return SizedBox(
- width: ResponsiveBreakpoints.isPhone(context)
- ? (MediaQuery.of(context).size.width - 48) / 2
- : 160,
- child: Card(
- child: InkWell(
- borderRadius: BorderRadius.circular(12),
- onTap: onTap,
- child: Padding(
- padding: const EdgeInsets.all(16),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Icon(icon, size: 32, color: color),
- const SizedBox(height: 8),
- Text(
- label,
- textAlign: TextAlign.center,
- style: Theme.of(context).textTheme.labelLarge,
- ),
- ],
- ),
- ),
- ),
- ),
- );
- }
- }
- class _StatCard extends StatelessWidget {
- final String label;
- final String value;
- final IconData icon;
- final Color color;
- final VoidCallback? onTap;
- const _StatCard({
- required this.label,
- required this.value,
- required this.icon,
- required this.color,
- this.onTap,
- });
- @override
- Widget build(BuildContext context) {
- return Card(
- child: InkWell(
- borderRadius: BorderRadius.circular(12),
- onTap: onTap,
- child: Padding(
- padding: const EdgeInsets.all(16),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Icon(icon, color: color),
- const SizedBox(width: 12),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- value,
- style: Theme.of(context).textTheme.headlineSmall?.copyWith(
- fontWeight: FontWeight.bold,
- ),
- ),
- Text(label, style: Theme.of(context).textTheme.bodySmall),
- ],
- ),
- ],
- ),
- ),
- ),
- );
- }
- }
|