diff --git a/lib/core/widgets/shared_forms/shared_customer_section.dart b/lib/core/widgets/shared_forms/shared_customer_section.dart index 9a2afcc..d2d75ad 100644 --- a/lib/core/widgets/shared_forms/shared_customer_section.dart +++ b/lib/core/widgets/shared_forms/shared_customer_section.dart @@ -3,22 +3,22 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/features/customers/blocs/customers_cubit.dart'; import 'package:flux/features/customers/models/customer_model.dart'; import 'package:flux/features/customers/ui/quick_customer_dialog.dart'; -import 'package:flux/features/operations/models/operation_model.dart'; class SharedCustomerSection extends StatelessWidget { - final OperationModel? currentOp; + final String? customerId; + final String? customerName; final ValueChanged onCustomerSelected; const SharedCustomerSection({ super.key, - required this.currentOp, + this.customerId, + this.customerName, required this.onCustomerSelected, }); @override Widget build(BuildContext context) { - final hasCustomer = - currentOp?.customerId != null && currentOp!.customerId!.isNotEmpty; + final hasCustomer = customerId != null && customerId!.isNotEmpty; final theme = Theme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -47,9 +47,7 @@ class SharedCustomerSection extends StatelessWidget { const SizedBox(width: 12), Expanded( child: Text( - hasCustomer - ? currentOp!.customerDisplayName! - : 'Seleziona Cliente *', + hasCustomer ? customerName! : 'Seleziona Cliente *', style: TextStyle( fontWeight: hasCustomer ? FontWeight.bold diff --git a/lib/core/widgets/shared_forms/shared_staff_section.dart b/lib/core/widgets/shared_forms/shared_staff_section.dart index ed8b37f..0aa8b86 100644 --- a/lib/core/widgets/shared_forms/shared_staff_section.dart +++ b/lib/core/widgets/shared_forms/shared_staff_section.dart @@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/master_data/staff/models/staff_member_model.dart'; -import 'package:flux/features/operations/models/operation_model.dart'; import 'package:get_it/get_it.dart'; class StaffSection extends StatelessWidget { @@ -24,8 +23,7 @@ class StaffSection extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final selectedStaffId = - currentOp?.staffId ?? - GetIt.I.get().state.currentStaffMember?.id; + staffId ?? GetIt.I.get().state.currentStaffMember?.id; return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/features/operations/ui/operation_form_screen.dart b/lib/features/operations/ui/operation_form_screen.dart index 1271cc8..cf58ad5 100644 --- a/lib/features/operations/ui/operation_form_screen.dart +++ b/lib/features/operations/ui/operation_form_screen.dart @@ -319,7 +319,8 @@ class _OperationFormScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ StaffSection( - currentOp: currentOp, + staffId: currentOp?.staffId, + staffName: currentOp?.staffDisplayName, onStaffSelected: (staff) => { context.read().updateOperationFields( staffId: staff.id, @@ -330,7 +331,8 @@ class _OperationFormScreenState extends State { const Divider(height: 50), _buildSectionTitle('Cliente & Riferimento'), SharedCustomerSection( - currentOp: currentOp, + customerId: currentOp?.customerId, + customerName: currentOp?.customerDisplayName, onCustomerSelected: (customer) { context.read().updateOperationFields( customerId: customer.id, diff --git a/lib/features/tickets/blocs/ticket_form_cubit.dart b/lib/features/tickets/blocs/ticket_form_cubit.dart index e4e7782..abe4479 100644 --- a/lib/features/tickets/blocs/ticket_form_cubit.dart +++ b/lib/features/tickets/blocs/ticket_form_cubit.dart @@ -34,7 +34,7 @@ class TicketFormCubit extends Cubit { createdById: currentUser?.id, createdByName: currentUser?.name, // Impostiamo lo stato iniziale - status: TicketStatus.open, + ticketStatus: TicketStatus.open, ticketType: TicketType.repair, // Default ); @@ -98,7 +98,7 @@ class TicketFormCubit extends Cubit { state.copyWith( ticket: state.ticket.copyWith( ticketType: ticketType ?? state.ticket.ticketType, - status: status ?? state.ticket.status, + ticketStatus: status ?? state.ticket.ticketStatus, request: request ?? state.ticket.request, targetSn: targetSn ?? state.ticket.targetSn, alternativePhoneNumber: @@ -143,7 +143,7 @@ class TicketFormCubit extends Cubit { createdById: ticketToSave .createdById, // Manteniamo quello selezionato nella tendina! createdByName: ticketToSave.createdByName, - status: TicketStatus.open, + ticketStatus: TicketStatus.open, ticketType: TicketType.repair, ), ), diff --git a/lib/features/tickets/data/ticket_repository.dart b/lib/features/tickets/data/ticket_repository.dart index df30905..d274e22 100644 --- a/lib/features/tickets/data/ticket_repository.dart +++ b/lib/features/tickets/data/ticket_repository.dart @@ -27,7 +27,8 @@ class TicketRepository { .select(''' *, customer (*), - staff_member (*), + created_by:staff_member!ticket_staff_id_fkey (*), + assigned_to:staff_member!ticket_assigned_to_id_fkey (*), target_model:model!ticket_model_id_1_fkey (*), source_model:model!ticket_model_id_2_fkey (*) ''') @@ -83,7 +84,8 @@ class TicketRepository { .select(''' *, customer (*), - staff_member (*), + created_by:staff_member!ticket_staff_id_fkey (*), + assigned_to:staff_member!ticket_assigned_to_id_fkey (*), target_model:model!ticket_model_id_1_fkey (*), source_model:model!ticket_model_id_2_fkey (*) ''') @@ -144,8 +146,8 @@ class TicketRepository { // 2. Filtriamo in memoria! final urgentTickets = allStoreTickets.where((ticket) { // Escludiamo quelli giĆ  chiusi o consegnati - if (ticket.status == TicketStatus.closed || - ticket.status == TicketStatus.ready) { + if (ticket.ticketStatus == TicketStatus.closed || + ticket.ticketStatus == TicketStatus.ready) { return false; } @@ -178,7 +180,8 @@ class TicketRepository { customer (*), target_model:model!ticket_model_id_1_fkey (*), source_model:model!ticket_model_id_2_fkey (*), - staff:staff_member!ticket_staff_id_fkey (*) + created_by:staff_member!ticket_staff_id_fkey (*), + assigned_to:staff_member!ticket_assigned_to_id_fkey (*), ''') .eq('id', ticketId) .single(); diff --git a/lib/features/tickets/models/ticket_model.dart b/lib/features/tickets/models/ticket_model.dart index 6fe89ef..6880772 100644 --- a/lib/features/tickets/models/ticket_model.dart +++ b/lib/features/tickets/models/ticket_model.dart @@ -35,8 +35,7 @@ enum TicketStatus { final String displayValue; const TicketStatus(this.value, this.displayValue); - static TicketStatus? fromString(String? val) { - if (val == null) return null; + static TicketStatus fromString(String? val) { return TicketStatus.values.firstWhere( (e) => e.value == val, orElse: () => TicketStatus.open, @@ -103,9 +102,9 @@ class TicketModel extends Equatable { final String? alternativePhoneNumber; final bool hasCourtesyDevice; final TicketType ticketType; - final TicketStatus? status; + final TicketStatus ticketStatus; final DateTime? estimatedDeliveryAt; - final TicketResult? result; + final TicketResult? ticketResult; final String? resolutionNotes; final String? legacyId; final String? customerName; @@ -139,9 +138,9 @@ class TicketModel extends Equatable { this.alternativePhoneNumber, this.hasCourtesyDevice = false, required this.ticketType, - this.status, + this.ticketStatus = TicketStatus.closed, this.estimatedDeliveryAt, - this.result, + this.ticketResult, this.resolutionNotes, this.legacyId, this.customerName, @@ -160,7 +159,7 @@ class TicketModel extends Equatable { companyId: companyId ?? '', storeId: storeId, ticketType: TicketType.repair, // Valore di default - status: TicketStatus.open, + ticketStatus: TicketStatus.open, customerPrice: 0.0, internalCost: 0.0, hasCourtesyDevice: false, @@ -190,9 +189,9 @@ class TicketModel extends Equatable { String? alternativePhoneNumber, bool? hasCourtesyDevice, TicketType? ticketType, - TicketStatus? status, + TicketStatus? ticketStatus, DateTime? estimatedDeliveryAt, - TicketResult? result, + TicketResult? ticketResult, String? resolutionNotes, String? legacyId, String? customerName, @@ -227,9 +226,9 @@ class TicketModel extends Equatable { alternativePhoneNumber ?? this.alternativePhoneNumber, hasCourtesyDevice: hasCourtesyDevice ?? this.hasCourtesyDevice, ticketType: ticketType ?? this.ticketType, - status: status ?? this.status, + ticketStatus: ticketStatus ?? this.ticketStatus, estimatedDeliveryAt: estimatedDeliveryAt ?? this.estimatedDeliveryAt, - result: result ?? this.result, + ticketResult: ticketResult ?? this.ticketResult, resolutionNotes: resolutionNotes ?? this.resolutionNotes, legacyId: legacyId ?? this.legacyId, customerName: customerName ?? this.customerName, @@ -274,11 +273,11 @@ class TicketModel extends Equatable { alternativePhoneNumber: map['alternative_phone_number'] as String?, hasCourtesyDevice: map['has_courtesy_device'] as bool? ?? false, ticketType: TicketType.fromString(map['ticket_type'] as String), - status: TicketStatus.fromString(map['status'] as String?), + ticketStatus: TicketStatus.fromString(map['ticket_status'] as String), estimatedDeliveryAt: map['estimated_delivery_at'] != null ? DateTime.parse(map['estimated_delivery_at']).toLocal() : null, - result: TicketResult.fromString(map['result'] as String?), + ticketResult: TicketResult.fromString(map['ticket_result'] as String?), resolutionNotes: map['resolution_notes'] as String?, legacyId: map['legacy_id'] as String?, customerName: (map['customer']?['name'] as String?).myFormat(), @@ -318,10 +317,10 @@ class TicketModel extends Equatable { 'alternative_phone_number': alternativePhoneNumber, 'has_courtesy_device': hasCourtesyDevice, 'ticket_type': ticketType.value, - if (status != null) 'status': status!.value, + 'ticket_status': ticketStatus.value, if (estimatedDeliveryAt != null) 'estimated_delivery_at': estimatedDeliveryAt!.toUtc().toIso8601String(), - if (result != null) 'result': result!.value, + if (ticketResult != null) 'ticket_result': ticketResult!.value, 'resolution_notes': resolutionNotes, 'legacy_id': legacyId, 'included_accessories': includedAccessories, @@ -351,9 +350,9 @@ class TicketModel extends Equatable { alternativePhoneNumber, hasCourtesyDevice, ticketType, - status, + ticketStatus, estimatedDeliveryAt, - result, + ticketResult, resolutionNotes, legacyId, includedAccessories, diff --git a/lib/features/tickets/ui/ticket_form_screen.dart b/lib/features/tickets/ui/ticket_form_screen.dart index 355d3a2..42f2321 100644 --- a/lib/features/tickets/ui/ticket_form_screen.dart +++ b/lib/features/tickets/ui/ticket_form_screen.dart @@ -5,7 +5,8 @@ import 'package:flux/features/tickets/blocs/ticket_form_state.dart'; import 'package:flux/features/tickets/models/ticket_model.dart'; import 'package:flux/core/widgets/shared_forms/shared_customer_section.dart'; import 'package:flux/core/widgets/shared_forms/shared_model_section.dart'; -import 'package:flux/core/widgets/shared_forms/shared_staff_section.dart'; // Il tuo widget agnostico dello staff +import 'package:flux/core/widgets/shared_forms/shared_staff_section.dart'; +import 'package:flux/features/tickets/models/ticket_status_extension.dart'; // Il tuo widget agnostico dello staff class TicketFormScreen extends StatefulWidget { final TicketModel? existingTicket; @@ -53,20 +54,26 @@ class _TicketFormScreenState extends State { // Sincronizza i controller con lo stato iniziale senza sovrascrivere se l'utente sta digitando void _syncTextControllers(TicketModel model) { - if (_altPhoneCtrl.text.isEmpty) + if (_altPhoneCtrl.text.isEmpty) { _altPhoneCtrl.text = model.alternativePhoneNumber ?? ''; + } if (_serialCtrl.text.isEmpty) _serialCtrl.text = model.targetSn ?? ''; - if (_requestCtrl.text.isEmpty) _requestCtrl.text = model.request ?? ''; - if (_accessoriesCtrl.text.isEmpty) + if (_requestCtrl.text.isEmpty) _requestCtrl.text = model.request; + if (_accessoriesCtrl.text.isEmpty) { _accessoriesCtrl.text = model.includedAccessories ?? ''; - if (_publicNotesCtrl.text.isEmpty) + } + if (_publicNotesCtrl.text.isEmpty) { _publicNotesCtrl.text = model.publicNotes ?? ''; - if (_internalNotesCtrl.text.isEmpty) + } + if (_internalNotesCtrl.text.isEmpty) { _internalNotesCtrl.text = model.internalNotes ?? ''; - if (_priceCtrl.text.isEmpty && model.customerPrice > 0) + } + if (_priceCtrl.text.isEmpty && model.customerPrice > 0) { _priceCtrl.text = model.customerPrice.toString(); - if (_costCtrl.text.isEmpty && model.internalCost > 0) + } + if (_costCtrl.text.isEmpty && model.internalCost > 0) { _costCtrl.text = model.internalCost.toString(); + } _isInitialized = true; } @@ -143,10 +150,10 @@ class _TicketFormScreenState extends State { padding: const EdgeInsets.only(right: 16.0), child: Chip( label: Text( - ticket.status.name.toUpperCase(), + ticket.ticketStatus!.name.toUpperCase(), style: const TextStyle(color: Colors.white, fontSize: 10), ), - backgroundColor: ticket.status.color, + backgroundColor: ticket.ticketStatus.color, ), ), ], @@ -174,7 +181,7 @@ class _TicketFormScreenState extends State { staffName: ticket.createdByName, onStaffSelected: (staff) => context.read().updateCreator( - staffId: staff.id, + staffId: staff.id!, staffName: staff.name, ), ), @@ -254,7 +261,7 @@ class _TicketFormScreenState extends State { const SizedBox(width: 16), Expanded( child: DropdownButtonFormField( - value: ticket.status, + value: ticket.ticketStatus, decoration: const InputDecoration( labelText: 'Stato Attuale', ), diff --git a/lib/features/tickets/ui/ticket_list_screen.dart b/lib/features/tickets/ui/ticket_list_screen.dart index 43a0503..30751ce 100644 --- a/lib/features/tickets/ui/ticket_list_screen.dart +++ b/lib/features/tickets/ui/ticket_list_screen.dart @@ -192,8 +192,8 @@ class _TicketCard extends StatelessWidget { @override Widget build(BuildContext context) { - final statusColor = ticket.status?.color ?? Colors.grey; - final statusIcon = ticket.status?.icon ?? Icons.help_outline; + final statusColor = ticket.ticketStatus.color; + final statusIcon = ticket.ticketStatus.icon; return Card( margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), @@ -244,7 +244,7 @@ class _TicketCard extends StatelessWidget { Icon(statusIcon, size: 14, color: statusColor), const SizedBox(width: 4), Text( - ticket.status?.displayValue ?? 'N/D', + ticket.ticketStatus.displayValue, style: TextStyle( fontSize: 12, color: statusColor,