customer_card.dart 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import 'package:flutter/material.dart';
  2. import 'package:go_router/go_router.dart';
  3. import 'package:ristoris/core/constants.dart';
  4. import 'package:ristoris/core/credit_score_color.dart';
  5. import 'package:ristoris/database/database.dart';
  6. class CustomerCard extends StatelessWidget {
  7. final Cliente cliente;
  8. const CustomerCard({super.key, required this.cliente});
  9. @override
  10. Widget build(BuildContext context) {
  11. final theme = Theme.of(context);
  12. final cs = theme.colorScheme;
  13. return Card(
  14. elevation: 0,
  15. color: Colors.white,
  16. clipBehavior: Clip.antiAlias,
  17. shape: RoundedRectangleBorder(
  18. borderRadius: BorderRadius.circular(12),
  19. side: BorderSide(color: cs.outlineVariant),
  20. ),
  21. child: InkWell(
  22. onTap: () => context.push('/dashboard/customers/${cliente.idCliente}'),
  23. child: Padding(
  24. padding: const EdgeInsets.all(16),
  25. child: Column(
  26. children: [
  27. Expanded(
  28. child: Column(
  29. crossAxisAlignment: CrossAxisAlignment.start,
  30. children: [
  31. Row(
  32. crossAxisAlignment: CrossAxisAlignment.start,
  33. children: [
  34. Expanded(
  35. child: Text(
  36. cliente.ragioneSociale ?? '',
  37. style: theme.textTheme.bodyMedium?.copyWith(
  38. color: cs.primary,
  39. ),
  40. maxLines: 2,
  41. overflow: TextOverflow.ellipsis,
  42. ),
  43. ),
  44. if ((cliente.codCliente ?? '').isNotEmpty) ...[
  45. const SizedBox(width: 8),
  46. Container(
  47. padding: const EdgeInsets.symmetric(
  48. horizontal: 8,
  49. vertical: 4,
  50. ),
  51. decoration: BoxDecoration(
  52. color: creditScoreBg(cliente.creditScoreColor) ?? cs.surfaceContainerHighest,
  53. borderRadius: BorderRadius.circular(4),
  54. ),
  55. child: Text(
  56. cliente.codCliente ?? '',
  57. style: TextStyle(
  58. fontSize: 12,
  59. height: 16 / 12,
  60. fontWeight: FontWeight.w500,
  61. color: creditScoreBg(cliente.creditScoreColor) != null ? Colors.white : cs.onSurfaceVariant,
  62. ),
  63. ),
  64. ),
  65. ],
  66. ],
  67. ),
  68. const SizedBox(height: 4),
  69. Text(
  70. cliente.email ?? '',
  71. style: theme.textTheme.bodyMedium?.copyWith(
  72. color: cs.onSurfaceVariant,
  73. ),
  74. maxLines: 1,
  75. overflow: TextOverflow.ellipsis,
  76. ),
  77. const SizedBox(height: 16),
  78. Row(
  79. children: [
  80. Icon(Icons.phone, size: 20, color: cs.onSurfaceVariant),
  81. const SizedBox(width: 8),
  82. Expanded(
  83. child: Text(
  84. cliente.telefono ?? '',
  85. style: theme.textTheme.bodyMedium?.copyWith(
  86. color: cs.onSurfaceVariant,
  87. ),
  88. maxLines: 1,
  89. overflow: TextOverflow.ellipsis,
  90. ),
  91. ),
  92. ],
  93. ),
  94. const SizedBox(height: 4),
  95. Row(
  96. children: [
  97. Icon(
  98. Icons.business,
  99. size: 20,
  100. color: cs.onSurfaceVariant,
  101. ),
  102. const SizedBox(width: 8),
  103. Expanded(
  104. child: Text(
  105. cliente.indirizzo ?? '',
  106. style: theme.textTheme.bodyMedium?.copyWith(
  107. color: cs.onSurfaceVariant,
  108. ),
  109. maxLines: 1,
  110. overflow: TextOverflow.ellipsis,
  111. ),
  112. ),
  113. ],
  114. ),
  115. const SizedBox(height: 8),
  116. Row(
  117. children: [
  118. Icon(
  119. Icons.location_on,
  120. size: 20,
  121. color: cs.onSurfaceVariant,
  122. ),
  123. const SizedBox(width: 8),
  124. Expanded(
  125. child: Text(
  126. [
  127. if ((cliente.citta ?? '').isNotEmpty) cliente.citta,
  128. if ((cliente.provincia ?? '').isNotEmpty) cliente.provincia,
  129. ].join(', '),
  130. style: theme.textTheme.bodyMedium?.copyWith(
  131. color: cs.onSurfaceVariant,
  132. ),
  133. maxLines: 1,
  134. overflow: TextOverflow.ellipsis,
  135. ),
  136. ),
  137. ],
  138. ),
  139. ],
  140. ),
  141. ),
  142. Divider(height: 1, color: cs.outlineVariant),
  143. const SizedBox(height: 16),
  144. Row(
  145. children: [
  146. Expanded(
  147. child: OutlinedButton.icon(
  148. onPressed: () {
  149. context.go('/dashboard/customers/${cliente.idCliente}');
  150. },
  151. icon: const Icon(Icons.info_outline, size: 18),
  152. label: const Text('Dettagli'),
  153. style: OutlinedButton.styleFrom(
  154. foregroundColor: cs.secondary,
  155. side: BorderSide(
  156. color: cs.secondary.withValues(alpha: 0.3),
  157. ),
  158. ),
  159. ),
  160. ),
  161. const SizedBox(width: 8),
  162. Expanded(
  163. child: _buildOrdineButton(context),
  164. ),
  165. ],
  166. ),
  167. ],
  168. ),
  169. ),
  170. ),
  171. );
  172. }
  173. Widget _buildOrdineButton(BuildContext context) {
  174. final cs = Theme.of(context).colorScheme;
  175. final blocco = cliente.codBlocco;
  176. final isBloccato = blocco == '001';
  177. final hasWarning = blocco != null && blocco.isNotEmpty && blocco != '001';
  178. if (isBloccato) {
  179. return FilledButton.icon(
  180. onPressed: null,
  181. icon: const Icon(Icons.block, size: 18),
  182. label: const Text('Ordine'),
  183. style: FilledButton.styleFrom(
  184. backgroundColor: cs.surfaceContainerHighest,
  185. foregroundColor: cs.onSurfaceVariant,
  186. ),
  187. );
  188. }
  189. return FilledButton.icon(
  190. onPressed: () {
  191. if (hasWarning) {
  192. ScaffoldMessenger.of(context).showSnackBar(
  193. SnackBar(
  194. content: Text('Attenzione: cliente con blocco $blocco'),
  195. backgroundColor: Colors.amber.shade800,
  196. ),
  197. );
  198. }
  199. context.go('/dashboard/orders/new?cliente=${cliente.idCliente}');
  200. },
  201. icon: hasWarning ? const Icon(Icons.warning_amber_rounded, size: 18) : const Icon(Icons.add_shopping_cart_outlined, size: 18),
  202. label: const Text('Ordine'),
  203. style: getBloccoColors(blocco),
  204. );
  205. }
  206. ButtonStyle? getBloccoColors(String? codBlocco) {
  207. if (codBlocco == AppConstants.kBlocco) {
  208. return FilledButton.styleFrom(
  209. backgroundColor: Colors.deepOrange,
  210. foregroundColor: Colors.black87,
  211. );
  212. } else if (codBlocco != null && codBlocco.isNotEmpty) {
  213. return FilledButton.styleFrom(
  214. backgroundColor: Colors.amber,
  215. foregroundColor: Colors.black87,
  216. );
  217. }
  218. return null;
  219. }
  220. }