223 lines
8.6 KiB
Dart
223 lines
8.6 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
|
|
import 'package:flux/features/customers/blocs/customers_cubit.dart';
|
||
|
|
import 'package:flux/features/customers/ui/quick_customer_dialog.dart';
|
||
|
|
import 'package:flux/features/operations/blocs/operations_cubit.dart';
|
||
|
|
import 'package:flux/features/operations/models/operation_model.dart';
|
||
|
|
|
||
|
|
class CustomerSection extends StatelessWidget {
|
||
|
|
final OperationModel? currentOp;
|
||
|
|
const CustomerSection({super.key, required this.currentOp});
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final hasCustomer =
|
||
|
|
currentOp?.customerId != null && currentOp!.customerId!.isNotEmpty;
|
||
|
|
final theme = Theme.of(context);
|
||
|
|
return Column(
|
||
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
|
children: [
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.only(bottom: 12.0),
|
||
|
|
child: Text(
|
||
|
|
'Cliente',
|
||
|
|
style: theme.textTheme.titleLarge?.copyWith(
|
||
|
|
fontWeight: FontWeight.bold,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
InkWell(
|
||
|
|
onTap: () => _showCustomerModal(context), // Passiamo il context!
|
||
|
|
child: Container(
|
||
|
|
padding: const EdgeInsets.all(16),
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
border: Border.all(color: theme.colorScheme.primary),
|
||
|
|
borderRadius: BorderRadius.circular(8),
|
||
|
|
color: theme.colorScheme.primaryContainer.withValues(alpha: 0.2),
|
||
|
|
),
|
||
|
|
child: Row(
|
||
|
|
children: [
|
||
|
|
const Icon(Icons.person),
|
||
|
|
const SizedBox(width: 12),
|
||
|
|
Expanded(
|
||
|
|
child: Text(
|
||
|
|
hasCustomer
|
||
|
|
? currentOp!.customerDisplayName!
|
||
|
|
: 'Seleziona Cliente *',
|
||
|
|
style: TextStyle(
|
||
|
|
fontWeight: hasCustomer
|
||
|
|
? FontWeight.bold
|
||
|
|
: FontWeight.normal,
|
||
|
|
color: hasCustomer ? null : Colors.grey,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
const Icon(Icons.search),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- MODALE SELEZIONE CLIENTE ---
|
||
|
|
void _showCustomerModal(BuildContext context) {
|
||
|
|
String currentSearchQuery = '';
|
||
|
|
|
||
|
|
showModalBottomSheet(
|
||
|
|
context: context,
|
||
|
|
isScrollControlled: true,
|
||
|
|
shape: const RoundedRectangleBorder(
|
||
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||
|
|
),
|
||
|
|
builder: (modalContext) {
|
||
|
|
return DraggableScrollableSheet(
|
||
|
|
initialChildSize: 0.8,
|
||
|
|
minChildSize: 0.5,
|
||
|
|
maxChildSize: 0.95,
|
||
|
|
expand: false,
|
||
|
|
builder: (_, scrollController) {
|
||
|
|
return Column(
|
||
|
|
children: [
|
||
|
|
// Header
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.all(16.0),
|
||
|
|
child: Row(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
|
|
children: [
|
||
|
|
Text(
|
||
|
|
'Seleziona Cliente',
|
||
|
|
style: Theme.of(context).textTheme.titleLarge,
|
||
|
|
),
|
||
|
|
IconButton(
|
||
|
|
icon: const Icon(Icons.close),
|
||
|
|
onPressed: () => Navigator.pop(modalContext),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
// Barra di Ricerca
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||
|
|
child: TextField(
|
||
|
|
autofocus: true,
|
||
|
|
decoration: InputDecoration(
|
||
|
|
hintText: 'Cerca per nome, telefono o email...',
|
||
|
|
prefixIcon: const Icon(Icons.search),
|
||
|
|
border: OutlineInputBorder(
|
||
|
|
borderRadius: BorderRadius.circular(8),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
onChanged: (query) {
|
||
|
|
currentSearchQuery = query;
|
||
|
|
context.read<CustomersCubit>().searchCustomers(query);
|
||
|
|
},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
// Pulsante Nuovo Cliente
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.all(16.0),
|
||
|
|
child: ElevatedButton.icon(
|
||
|
|
style: ElevatedButton.styleFrom(
|
||
|
|
minimumSize: const Size.fromHeight(48),
|
||
|
|
),
|
||
|
|
icon: const Icon(Icons.person_add),
|
||
|
|
label: const Text('Crea Nuovo Cliente'),
|
||
|
|
onPressed: () async {
|
||
|
|
final OperationsCubit operationsCubit = context
|
||
|
|
.read<OperationsCubit>();
|
||
|
|
|
||
|
|
// APRIAMO LA DIALOG RAPIDA CON LA MAGIA DEL BLOC PROVIDER
|
||
|
|
final newCustomer = await showDialog(
|
||
|
|
context: context,
|
||
|
|
builder: (dialogContext) {
|
||
|
|
return BlocProvider.value(
|
||
|
|
value: context.read<CustomersCubit>(),
|
||
|
|
child: QuickCustomerDialog(
|
||
|
|
initialQuery:
|
||
|
|
currentSearchQuery, // <-- Passiamo quello che ha digitato!
|
||
|
|
),
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
// Se l'ha creato davvero (e non ha premuto annulla)...
|
||
|
|
if (newCustomer != null) {
|
||
|
|
// 1. Aggiorniamo il form delle operazioni
|
||
|
|
operationsCubit.updateOperationFields(
|
||
|
|
customerId: newCustomer.id,
|
||
|
|
customerDisplayName: newCustomer.name,
|
||
|
|
);
|
||
|
|
|
||
|
|
// 2. Chiudiamo la BottomSheet dei clienti per tornare alla form!
|
||
|
|
if (context.mounted) {
|
||
|
|
Navigator.pop(modalContext);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
const Divider(),
|
||
|
|
// Lista Clienti dal Bloc
|
||
|
|
Expanded(
|
||
|
|
child: BlocBuilder<CustomersCubit, CustomersState>(
|
||
|
|
builder: (context, state) {
|
||
|
|
if (state.status == CustomersStatus.loading) {
|
||
|
|
return const Center(child: CircularProgressIndicator());
|
||
|
|
}
|
||
|
|
if (state.customers.isEmpty) {
|
||
|
|
return const Center(
|
||
|
|
child: Text(
|
||
|
|
'Nessun cliente trovato.',
|
||
|
|
style: TextStyle(color: Colors.grey),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ListView.builder(
|
||
|
|
controller: scrollController,
|
||
|
|
itemCount: state.customers.length,
|
||
|
|
itemBuilder: (context, index) {
|
||
|
|
final customer = state.customers[index];
|
||
|
|
return ListTile(
|
||
|
|
leading: CircleAvatar(
|
||
|
|
child: Text(
|
||
|
|
customer.name.substring(0, 1).toUpperCase(),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
title: Text(
|
||
|
|
customer.name,
|
||
|
|
style: const TextStyle(
|
||
|
|
fontWeight: FontWeight.bold,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
subtitle: Text(
|
||
|
|
'${customer.phoneNumber} • ${customer.email}',
|
||
|
|
),
|
||
|
|
onTap: () {
|
||
|
|
// Aggiorniamo il form tramite il Cubit delle operazioni
|
||
|
|
context
|
||
|
|
.read<OperationsCubit>()
|
||
|
|
.updateOperationFields(
|
||
|
|
customerId: customer.id, // customer.id
|
||
|
|
customerDisplayName:
|
||
|
|
customer.name, // customer.name
|
||
|
|
);
|
||
|
|
Navigator.pop(modalContext);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
},
|
||
|
|
),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|