import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/features/operations/blocs/operations_cubit.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:flux/features/operations/ui/widgets/customer_section.dart'; import 'package:flux/features/operations/ui/widgets/details_section.dart'; import 'package:flux/features/operations/ui/widgets/staff_section.dart'; import 'package:get_it/get_it.dart'; // ASSICURATI DEL PATH // import 'package:flux/features/attachments/ui/operation_files_section.dart'; class OperationFormScreen extends StatefulWidget { final String? operationId; final OperationModel? existingOperation; const OperationFormScreen({ super.key, this.operationId, this.existingOperation, }); @override State createState() => _OperationFormScreenState(); } class _OperationFormScreenState extends State { final _formKey = GlobalKey(); final _referenceController = TextEditingController(); final _noteController = TextEditingController(); final _freeTextSubtypeController = TextEditingController(); final List _availableTypes = [ 'AL', 'MNP', 'NIP', 'UNICA', 'TELEPASS', 'Energy', 'Fin', 'Entertainment', 'Custom', ]; bool _isInitialized = false; @override void initState() { super.initState(); final cubit = context.read(); final currentLoggedStaff = GetIt.I .get() .state .currentStaffMember!; // 1. Diciamo al Cubit di prepararsi cubit.initOperationForm( existingOperation: widget.existingOperation, operationId: widget.operationId, staffId: currentLoggedStaff.id, staffDisplayName: currentLoggedStaff.name, ); // 2. IL TRUCCO MAGICO: // Se abbiamo passato existingOperation, il Cubit si è appena aggiornato. // Lo stato è già pronto, quindi sincronizziamo i controller SUBITO! if (cubit.state.currentOperation != null) { _syncTextControllers(cubit.state.currentOperation!); } } @override void dispose() { _referenceController.dispose(); _noteController.dispose(); _freeTextSubtypeController.dispose(); super.dispose(); } void _syncTextControllers(OperationModel model) { if (_referenceController.text.isEmpty && model.reference.isNotEmpty) { _referenceController.text = model.reference; } if (_noteController.text.isEmpty && model.note.isNotEmpty) { _noteController.text = model.note; } if (_freeTextSubtypeController.text.isEmpty && model.subtype != null && model.subtype!.isNotEmpty) { _freeTextSubtypeController.text = model.subtype!; } _isInitialized = true; } void _saveOperation({required bool keepAdding}) { if (_formKey.currentState!.validate()) { final cubit = context.read(); final currentOperation = cubit.state.currentOperation!; final operationToSave = currentOperation.copyWith( reference: _referenceController.text, note: _noteController.text, subtype: ['Entertainment', 'Custom'].contains(currentOperation.type) ? _freeTextSubtypeController.text : currentOperation.subtype, ); cubit.initOperationForm(existingOperation: operationToSave); cubit.saveCurrentOperation( targetStatus: OperationStatus.ok, shouldPop: !keepAdding, ); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); return BlocConsumer( listenWhen: (previous, current) => previous.status != current.status || previous.currentOperation?.id != current.currentOperation?.id, listener: (context, state) { if (state.status == OperationsStatus.ready && state.currentOperation != null && !_isInitialized) { _syncTextControllers(state.currentOperation!); } if (state.status == OperationsStatus.saved) { Navigator.of(context).pop(); } else if (state.status == OperationsStatus.savedNoPop) { context.read().prepareNextOperationInBatch(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Servizio aggiunto! Inserisci il prossimo.'), ), ); _freeTextSubtypeController.clear(); } else if (state.status == OperationsStatus.failure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.errorMessage ?? 'Errore'), backgroundColor: theme.colorScheme.error, ), ); } }, builder: (context, state) { if (!_isInitialized && (widget.operationId != null || widget.existingOperation != null) && state.status == OperationsStatus.loading) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( appBar: AppBar( title: Text( state.currentOperation?.id == null ? 'Nuova Pratica' : 'Modifica Pratica', ), ), body: Form( key: _formKey, child: LayoutBuilder( builder: (context, constraints) { final isDesktop = constraints.maxWidth > 900; if (isDesktop) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 7, child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: _buildMainFormContent(theme, state), ), ), VerticalDivider(width: 1, color: theme.dividerColor), Expanded( flex: 3, child: Padding( padding: const EdgeInsets.all(16.0), child: _buildNotesSection(isDesktop: true), ), ), ], ); } else { return SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildMainFormContent(theme, state), const Divider(height: 32), _buildNotesSection(isDesktop: false), const SizedBox(height: 80), ], ), ); } }, ), ), bottomNavigationBar: SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Expanded( flex: 1, child: OutlinedButton( onPressed: state.status == OperationsStatus.saving ? null : () => _saveOperation(keepAdding: true), child: const Text( 'Salva e Aggiungi Altro', textAlign: TextAlign.center, ), ), ), const SizedBox(width: 12), Expanded( flex: 1, child: ElevatedButton( onPressed: state.status == OperationsStatus.saving ? null : () => _saveOperation(keepAdding: false), child: state.status == OperationsStatus.saving ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Text('Salva ed Esci'), ), ), ], ), ), ), ); }, ); } Widget _buildMainFormContent(ThemeData theme, OperationsState state) { final currentOp = state.currentOperation; final currentType = currentOp?.type ?? 'AL'; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ StaffSection(currentOp: currentOp), const Divider(height: 50), _buildSectionTitle('Cliente & Riferimento'), CustomerSection(currentOp: currentOp), const SizedBox(height: 16), TextFormField( controller: _referenceController, decoration: const InputDecoration( labelText: 'Riferimento (es. numero di telefono, targa...)', prefixIcon: Icon(Icons.tag), ), ), const Divider(height: 32), _buildSectionTitle('Cosa stiamo facendo?'), Wrap( spacing: 8.0, runSpacing: 8.0, children: _availableTypes.map((type) { return ChoiceChip( label: Text(type), selected: currentType == type, onSelected: (selected) { if (selected) { context.read().setTypeWithSmartDefault(type); } }, ); }).toList(), ), const Divider(height: 32), _buildSectionTitle('Dettagli Servizio'), DetailsSection( currentOp: currentOp, currentType: currentType, freeTextSubtypeController: _freeTextSubtypeController, durationQuickPicks: _buildDurationQuickPicks(currentOp), ), // QUANTITÀ Row( children: [ const Text('Quantità: '), IconButton( icon: const Icon(Icons.remove), onPressed: () { final q = currentOp?.quantity ?? 1; if (q > 1) { context.read().updateOperationFields( quantity: q - 1, ); } }, ), Text( '${currentOp?.quantity ?? 1}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.add), onPressed: () { final q = currentOp?.quantity ?? 1; context.read().updateOperationFields( quantity: q + 1, ); }, ), ], ), const Divider(height: 32), _buildSectionTitle('Documenti & Foto'), const Center( child: Text( "Widget File in arrivo...", style: TextStyle(color: Colors.grey), ), ), ], ); } Widget _buildDurationQuickPicks(OperationModel? currentOp) { final durations = [3, 6, 12, 24, 30, 36, 48]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Imposta durata rapida (mesi):", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.grey, ), ), const SizedBox(height: 8), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: durations.map((months) { return Padding( padding: const EdgeInsets.only(right: 8.0), child: ActionChip( label: Text("$months m"), backgroundColor: Colors.blue.withValues(alpha: 0.05), onPressed: () { final now = DateTime.now(); context.read().updateOperationFields( expirationDate: DateTime( now.year, now.month + months, now.day, ), ); }, ), ); }).toList(), ), ), ], ); } Widget _buildNotesSection({required bool isDesktop}) { final title = _buildSectionTitle('Note Interne'); final noteField = TextFormField( controller: _noteController, keyboardType: TextInputType.multiline, minLines: isDesktop ? null : 5, maxLines: null, expands: isDesktop, textAlignVertical: TextAlignVertical.top, decoration: const InputDecoration( hintText: 'Incolla qui seriali, ICCID, IBAN, indirizzi...', alignLabelWithHint: true, border: OutlineInputBorder(), ), ); return isDesktop ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ title, const SizedBox(height: 8), Expanded(child: noteField), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [title, const SizedBox(height: 8), noteField], ); } Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 12.0), child: Text( title, style: Theme.of( context, ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), ); } }