| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- 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 '../../../database/database.dart';
- import '../../../providers/auth_provider.dart';
- import '../../../providers/database_provider.dart';
- import '../../../providers/customer_provider.dart';
- import '../../../database/tables/clienti.dart';
- import '../../../database/tables/filiali.dart';
- import '../../../database/tables/scadenze.dart';
- import '../../../core/responsive.dart';
- class CustomerDetailPage extends ConsumerWidget {
- final int id;
- const CustomerDetailPage({super.key, required this.id});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final clientiDao = ref.read(clientiDaoProvider);
- final clienteAsync = clientiDao.getById(id);
- final theme = Theme.of(context);
- return DefaultTabController(
- length: 4,
- child: Scaffold(
- appBar: AppBar(
- title: FutureBuilder<Cliente?>(
- future: clienteAsync,
- builder: (_, snap) => Text(snap.data?.ragioneSociale ?? 'Cliente'),
- ),
- bottom: const TabBar(
- tabs: [
- Tab(text: 'Info', icon: Icon(Icons.info_outline)),
- Tab(text: 'Ordini', icon: Icon(Icons.receipt_long_outlined)),
- Tab(text: 'Destinazioni', icon: Icon(Icons.location_on_outlined)),
- Tab(
- text: 'Scadenze',
- icon: Icon(Icons.account_balance_wallet_outlined),
- ),
- ],
- ),
- ),
- body: FutureBuilder<Cliente?>(
- future: clienteAsync,
- builder: (_, snap) {
- final cliente = snap.data;
- if (cliente == null)
- return const Center(child: CircularProgressIndicator());
- return TabBarView(
- children: [
- _InfoTab(cliente: cliente, theme: theme),
- _OrdersTab(idCliente: id, theme: theme),
- _DestinationsTab(idCliente: id, theme: theme),
- _PaymentsTab(
- idCliente: cliente.idClienteRemoto ?? 0,
- theme: theme,
- ),
- ],
- );
- },
- ),
- ),
- );
- }
- }
- class _InfoTab extends StatelessWidget {
- final Cliente cliente;
- final ThemeData theme;
- const _InfoTab({required this.cliente, required this.theme});
- @override
- Widget build(BuildContext context) {
- return SingleChildScrollView(
- padding: const EdgeInsets.all(16),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _infoRow('Codice', cliente.codCliente ?? '-'),
- _infoRow('Ragione Sociale', cliente.ragioneSociale ?? '-'),
- _infoRow('Indirizzo', cliente.indirizzo ?? '-'),
- _infoRow(
- 'Città',
- '${cliente.citta ?? ""} ${cliente.provincia ?? ""} ${cliente.cap ?? ""}',
- ),
- _infoRow('Telefono', cliente.telefono ?? '-'),
- _infoRow('Cellulare', cliente.cellulare ?? '-'),
- _infoRow('Email', cliente.email ?? '-'),
- _infoRow('Partita IVA', cliente.partitaIva ?? '-'),
- _infoRow('Codice Fiscale', cliente.codiceFiscale ?? '-'),
- if (cliente.sdi != null && cliente.sdi!.isNotEmpty)
- _infoRow('SDI', cliente.sdi!),
- if (cliente.pec != null && cliente.pec!.isNotEmpty)
- _infoRow('PEC', cliente.pec!),
- if (cliente.note != null && cliente.note!.isNotEmpty)
- _infoRow('Note', cliente.note!),
- if (cliente.codBlocco != null && cliente.codBlocco!.isNotEmpty)
- Card(
- color: Colors.red.shade50,
- child: Padding(
- padding: const EdgeInsets.all(12),
- child: Row(
- children: [
- Icon(Icons.block, color: Colors.red),
- const SizedBox(width: 8),
- Text('Blocco: ${cliente.codBlocco}'),
- ],
- ),
- ),
- ),
- ],
- ),
- );
- }
- Widget _infoRow(String label, String value) {
- return Padding(
- padding: const EdgeInsets.symmetric(vertical: 4),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(
- width: 120,
- child: Text(
- label,
- style: theme.textTheme.bodySmall?.copyWith(
- color: theme.colorScheme.outline,
- ),
- ),
- ),
- Expanded(child: Text(value)),
- ],
- ),
- );
- }
- }
- class _OrdersTab extends ConsumerWidget {
- final int idCliente;
- final ThemeData theme;
- const _OrdersTab({required this.idCliente, required this.theme});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final ordiniDao = ref.read(ordiniDaoProvider);
- return Scaffold(
- body: FutureBuilder(
- future: ordiniDao.customerOrders(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(orders[i].dataOrdine ?? ''),
- onTap: () => context.push('/dashboard/orders/${orders[i].idOrdine}'),
- ),
- );
- },
- ),
- floatingActionButton: FloatingActionButton(
- heroTag: 'addOrder',
- child: const Icon(Icons.add),
- onPressed: () => context.push('/dashboard/orders/new?cliente=$idCliente'),
- ),
- );
- }
- }
- class _DestinationsTab extends ConsumerWidget {
- final int idCliente;
- final ThemeData theme;
- const _DestinationsTab({required this.idCliente, required this.theme});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final destsAsync = ref.watch(customerDestinationsProvider(idCliente));
- return destsAsync.when(
- data: (dests) {
- if (dests.isEmpty)
- return const Center(child: Text('Nessuna destinazione'));
- return ListView.builder(
- itemCount: dests.length,
- itemBuilder: (_, i) => ListTile(
- leading: const Icon(Icons.location_on_outlined),
- title: Text(dests[i].descrizione ?? ''),
- subtitle: Text(
- '${dests[i].indirizzo ?? ""} ${dests[i].citta ?? ""}',
- ),
- ),
- );
- },
- loading: () => const Center(child: CircularProgressIndicator()),
- error: (e, _) => Center(child: Text('Errore: $e')),
- );
- }
- }
- class _PaymentsTab extends ConsumerWidget {
- final int idCliente;
- final ThemeData theme;
- const _PaymentsTab({required this.idCliente, required this.theme});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final paysAsync = ref.watch(customerPaymentsProvider(idCliente));
- return paysAsync.when(
- data: (pays) {
- if (pays.isEmpty) return const Center(child: Text('Nessuna scadenza'));
- return ListView.builder(
- padding: const EdgeInsets.all(8),
- itemCount: pays.length,
- itemBuilder: (_, i) {
- final p = pays[i];
- return Card(
- margin: const EdgeInsets.symmetric(vertical: 4),
- child: Padding(
- padding: const EdgeInsets.all(12),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _row('Fattura N.', p.numDoc ?? '-'),
- _row('Data fatt.', _formatDate(p.dataDoc)),
- _row('Data scad', _formatDate(p.dataScadenza)),
- _row('Totale fattura', _formatAmount(p.importoFattura)),
- _row('Totale scad.', _formatAmount(p.importoScadenza)),
- _row('Saldo', _formatAmount(p.saldo)),
- ],
- ),
- ),
- );
- },
- );
- },
- loading: () => const Center(child: CircularProgressIndicator()),
- error: (e, _) => Center(child: Text('Errore: $e')),
- );
- }
- String _formatDate(String? dateStr) {
- if (dateStr == null) return '-';
- try {
- final dt = DateTime.parse(dateStr);
- return DateFormat('dd/MM/yyyy').format(dt);
- } catch (_) {
- return dateStr;
- }
- }
- String _formatAmount(double? amount) {
- if (amount == null) return '-';
- final fmt = NumberFormat('#,##0.00', 'it');
- return '€ ${fmt.format(amount)}';
- }
- Widget _row(String label, String value) {
- return Padding(
- padding: const EdgeInsets.symmetric(vertical: 2),
- child: Row(
- children: [
- SizedBox(
- width: 110,
- child: Text(
- label,
- style: theme.textTheme.bodySmall?.copyWith(
- color: theme.colorScheme.outline,
- ),
- ),
- ),
- Expanded(
- child: Text(value, style: theme.textTheme.bodyMedium),
- ),
- ],
- ),
- );
- }
- }
|