739 lines
24 KiB
Dart
739 lines
24 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:flux/core/blocs/session/session_cubit.dart';
|
|
import 'package:flux/core/widgets/shared_forms/attachments_section.dart';
|
|
import 'package:flux/features/attachments/blocs/attachments_bloc.dart';
|
|
import 'package:flux/features/master_data/providers/blocs/provider_list_cubit.dart';
|
|
import 'package:flux/features/operations/blocs/operation_form_cubit.dart';
|
|
import 'package:flux/features/operations/models/operation_model.dart';
|
|
import 'package:flux/core/widgets/shared_forms/customer_section.dart';
|
|
import 'package:flux/features/operations/ui/widgets/details_section.dart';
|
|
|
|
class OperationFormScreen extends StatefulWidget {
|
|
final String? operationId;
|
|
final OperationModel? existingOperation;
|
|
|
|
const OperationFormScreen({
|
|
super.key,
|
|
this.operationId,
|
|
this.existingOperation,
|
|
});
|
|
|
|
@override
|
|
State<OperationFormScreen> createState() => _OperationFormScreenState();
|
|
}
|
|
|
|
class _OperationFormScreenState extends State<OperationFormScreen> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
// 🥷 IL NUOVO FLAG: Ci ricorderà se vogliamo davvero uscire!
|
|
bool _isClosingIntent = false;
|
|
|
|
final _referenceController = TextEditingController();
|
|
final _noteController = TextEditingController();
|
|
final _freeTextSubtypeController = TextEditingController();
|
|
final _freeTextDescriptionController = TextEditingController();
|
|
|
|
final List<String> _availableTypes = [
|
|
'AL',
|
|
'MNP',
|
|
'NIP',
|
|
'UNICA',
|
|
'FWA',
|
|
'TELEPASS',
|
|
'Energy',
|
|
'Fin',
|
|
'Entertainment',
|
|
'Altro',
|
|
];
|
|
|
|
bool _isInitialized = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// 1. Lanciamo l'inizializzazione sincrona/asincrona
|
|
context.read<OperationFormCubit>().initForm(
|
|
existingOperation: widget.existingOperation,
|
|
operationId: widget.operationId,
|
|
);
|
|
|
|
// 2. Lettura immediata dello stato (come fatto per il customer!)
|
|
final currentState = context.read<OperationFormCubit>().state;
|
|
if (currentState.status == OperationFormStatus.ready && !_isInitialized) {
|
|
_syncTextControllers(currentState.operation);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_referenceController.dispose();
|
|
_noteController.dispose();
|
|
_freeTextSubtypeController.dispose();
|
|
_freeTextDescriptionController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _syncTextControllers(OperationModel model) {
|
|
if (_referenceController.text.isEmpty) {
|
|
_referenceController.text = model.reference;
|
|
}
|
|
if (_noteController.text.isEmpty) {
|
|
_noteController.text = model.note;
|
|
}
|
|
if (_freeTextSubtypeController.text.isEmpty) {
|
|
_freeTextSubtypeController.text = model.subType ?? '';
|
|
}
|
|
if (_freeTextDescriptionController.text.isEmpty) {
|
|
_freeTextDescriptionController.text = model.description ?? '';
|
|
}
|
|
_isInitialized = true;
|
|
}
|
|
|
|
void _flushControllersToCubit() {
|
|
context.read<OperationFormCubit>().updateFields(
|
|
reference: _referenceController.text,
|
|
note: _noteController.text,
|
|
subType: _freeTextSubtypeController.text,
|
|
description: _freeTextDescriptionController.text,
|
|
);
|
|
}
|
|
|
|
void _saveOperation({
|
|
required OperationStatus targetStatus,
|
|
required bool keepAdding,
|
|
}) {
|
|
if (_formKey.currentState!.validate()) {
|
|
// Se non stiamo facendo "Salva e Aggiungi Altro", il nostro intento è chiudere
|
|
_isClosingIntent = !keepAdding;
|
|
|
|
_flushControllersToCubit();
|
|
context.read<OperationFormCubit>().updateFields(status: targetStatus);
|
|
context.read<OperationFormCubit>().saveOperation(
|
|
targetStatus: targetStatus,
|
|
keepAdding: keepAdding,
|
|
);
|
|
}
|
|
}
|
|
|
|
// RINOMINATA E RESA SICURA
|
|
Future<String?> _ensureEntitySaved() async {
|
|
if (!_formKey.currentState!.validate()) return null;
|
|
|
|
// 🥷 Diciamo esplicitamente al sistema che NON vogliamo uscire dalla pagina
|
|
_isClosingIntent = false;
|
|
|
|
_flushControllersToCubit();
|
|
|
|
final attachmentsBloc = context.read<AttachmentsBloc>();
|
|
|
|
final newId = await context.read<OperationFormCubit>().saveOperationDraft();
|
|
if (newId != null && context.mounted) {
|
|
attachmentsBloc.add(ParentEntitySavedEvent(newId));
|
|
}
|
|
return newId;
|
|
}
|
|
|
|
Color _getStatusColor(OperationStatus status) {
|
|
switch (status) {
|
|
case OperationStatus.success:
|
|
return Colors.green;
|
|
case OperationStatus.waitingForAction:
|
|
return Colors.orange;
|
|
case OperationStatus.waitingForSupport:
|
|
return Colors.blue;
|
|
case OperationStatus.failure:
|
|
return Colors.red;
|
|
case OperationStatus.draft:
|
|
return Colors.grey;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
|
|
return BlocConsumer<OperationFormCubit, OperationFormState>(
|
|
listenWhen: (previous, current) => previous.status != current.status,
|
|
listener: (context, state) {
|
|
if (state.status == OperationFormStatus.ready && !_isInitialized) {
|
|
_syncTextControllers(state.operation);
|
|
}
|
|
|
|
// 🥷 ORA POPPA SOLO SE L'INTENTO ERA QUELLO DI USCIRE!
|
|
if (state.status == OperationFormStatus.success) {
|
|
if (_isClosingIntent) {
|
|
Navigator.of(context).pop();
|
|
} else {
|
|
// È stato un salvataggio background (Pick Files o QR).
|
|
// Non facciamo nulla, l'utente resta sulla pagina e i file vengono caricati!
|
|
}
|
|
} else if (state.status == OperationFormStatus.successAndAddAnother) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('Operazione salvata! Inserisci la prossima'),
|
|
),
|
|
);
|
|
_freeTextSubtypeController.clear();
|
|
_freeTextDescriptionController.clear();
|
|
_referenceController.clear();
|
|
} else if (state.status == OperationFormStatus.failure) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(state.errorMessage ?? 'Errore di salvataggio'),
|
|
backgroundColor: Colors.red,
|
|
),
|
|
);
|
|
}
|
|
},
|
|
builder: (context, state) {
|
|
if (!_isInitialized &&
|
|
(widget.operationId != null || widget.existingOperation != null) &&
|
|
state.status == OperationFormStatus.loading) {
|
|
return const Scaffold(
|
|
body: Center(child: CircularProgressIndicator()),
|
|
);
|
|
}
|
|
|
|
final displayStatus =
|
|
state.operation.status == OperationStatus.draft &&
|
|
state.operation.id == null
|
|
? OperationStatus.success
|
|
: state.operation.status;
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(
|
|
state.operation.id == null
|
|
? 'Nuova Pratica - Operatore: ${state.operation.staffDisplayName}'
|
|
: 'Modifica Pratica - Operatore: ${state.operation.staffDisplayName}',
|
|
),
|
|
actions:
|
|
displayStatus != OperationStatus.success &&
|
|
displayStatus != OperationStatus.draft
|
|
? [
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: 16.0),
|
|
child: Chip(
|
|
label: Text(
|
|
displayStatus.displayName,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
backgroundColor: _getStatusColor(displayStatus),
|
|
),
|
|
),
|
|
]
|
|
: null,
|
|
),
|
|
body: Form(
|
|
key: _formKey,
|
|
child: FocusTraversalGroup(
|
|
policy: WidgetOrderTraversalPolicy(),
|
|
child: LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
final isUltraWide = constraints.maxWidth > 1400;
|
|
final isDesktop = constraints.maxWidth > 900;
|
|
|
|
return SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Center(
|
|
child: ConstrainedBox(
|
|
constraints: BoxConstraints(
|
|
maxWidth: isUltraWide
|
|
? 1600
|
|
: (isDesktop ? 1200 : 800),
|
|
),
|
|
child: _buildResponsiveLayout(
|
|
isUltraWide,
|
|
isDesktop,
|
|
state,
|
|
displayStatus,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
bottomNavigationBar: SafeArea(
|
|
child: Container(
|
|
padding: const EdgeInsets.all(16.0),
|
|
decoration: BoxDecoration(
|
|
color: theme.scaffoldBackgroundColor,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withValues(alpha: 0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, -3),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
flex: 1,
|
|
child: ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor:
|
|
displayStatus != OperationStatus.success &&
|
|
displayStatus != OperationStatus.draft
|
|
? _getStatusColor(displayStatus)
|
|
: null,
|
|
foregroundColor:
|
|
displayStatus != OperationStatus.success &&
|
|
displayStatus != OperationStatus.draft
|
|
? Colors.white
|
|
: null,
|
|
),
|
|
onPressed: state.status == OperationFormStatus.saving
|
|
? null
|
|
: () => _saveOperation(
|
|
keepAdding: false,
|
|
targetStatus: displayStatus,
|
|
),
|
|
child: state.status == OperationFormStatus.saving
|
|
? const SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(
|
|
color: Colors.white,
|
|
strokeWidth: 2,
|
|
),
|
|
)
|
|
: const Text('Salva ed Esci'),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
flex: 1,
|
|
child: OutlinedButton(
|
|
onPressed: state.status == OperationFormStatus.saving
|
|
? null
|
|
: () => _saveOperation(
|
|
keepAdding: true,
|
|
targetStatus: displayStatus,
|
|
),
|
|
child: const Text(
|
|
'Salva e Aggiungi Altro',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
// --- LOGICA DI IMPAGINAZIONE RESPONSIVE ---
|
|
Widget _buildResponsiveLayout(
|
|
bool isUltraWide,
|
|
bool isDesktop,
|
|
OperationFormState state,
|
|
OperationStatus displayStatus,
|
|
) {
|
|
if (isUltraWide) {
|
|
// 3 COLONNE
|
|
return Column(
|
|
children: [
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
children: [_cardAnagrafica(state), _cardEsito(state)],
|
|
),
|
|
),
|
|
const SizedBox(width: 24),
|
|
Expanded(child: Column(children: [_cardDettagli(state)])),
|
|
const SizedBox(width: 24),
|
|
Expanded(child: Column(children: [_cardNote(state)])),
|
|
],
|
|
),
|
|
_cardAllegati(state),
|
|
],
|
|
);
|
|
} else if (isDesktop) {
|
|
// 2 COLONNE
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
children: [
|
|
_cardAnagrafica(state),
|
|
_cardEsito(state),
|
|
_cardAllegati(state),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(width: 24),
|
|
Expanded(
|
|
child: Column(children: [_cardDettagli(state), _cardNote(state)]),
|
|
),
|
|
],
|
|
);
|
|
} else {
|
|
// 1 COLONNA (Mobile)
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
_cardAnagrafica(state),
|
|
_cardEsito(state),
|
|
_cardDettagli(state),
|
|
_cardNote(state),
|
|
_cardAllegati(state),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
// --- LE CARD MODULARIZZATE E COLORATE ---
|
|
|
|
Widget _cardAnagrafica(OperationFormState state) {
|
|
return _buildCard(
|
|
title: 'Cliente e Riferimento',
|
|
icon: Icons.person,
|
|
themeColor: Colors.indigo,
|
|
children: [
|
|
SharedCustomerSection(
|
|
customer: state.operation.customer,
|
|
onCustomerSelected: (customer) =>
|
|
context.read<OperationFormCubit>().updateCustomer(customer),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextFormField(
|
|
controller: _referenceController,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Riferimento (es. Telefono, Targa...)',
|
|
prefixIcon: Icon(Icons.tag),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _cardEsito(OperationFormState state) {
|
|
return _buildCard(
|
|
title: 'Esito Pratica',
|
|
icon: Icons.fact_check,
|
|
themeColor: _getStatusColor(state.operation.status),
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: _getStatusColor(
|
|
state.operation.status,
|
|
).withValues(alpha: 0.1),
|
|
border: Border.all(
|
|
color: _getStatusColor(
|
|
state.operation.status,
|
|
).withValues(alpha: 0.3),
|
|
),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: DropdownButtonHideUnderline(
|
|
child: DropdownButton<OperationStatus>(
|
|
isExpanded: true,
|
|
value: state.operation.status,
|
|
icon: Icon(
|
|
Icons.arrow_drop_down,
|
|
color: _getStatusColor(state.operation.status),
|
|
),
|
|
items: OperationStatus.values.map((status) {
|
|
return DropdownMenuItem(
|
|
value: status,
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
status == OperationStatus.success
|
|
? Icons.check_circle
|
|
: Icons.error_outline,
|
|
color: _getStatusColor(status),
|
|
size: 20,
|
|
),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
status.displayName,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w600,
|
|
color: _getStatusColor(status),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
onChanged: (newStatus) {
|
|
if (newStatus != null) {
|
|
context.read<OperationFormCubit>().updateFields(
|
|
status: newStatus,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
state.operation.status == OperationStatus.success
|
|
? 'Lascia OK se caricata con successo.'
|
|
: 'Attenzione: pratica salvata in stato anomalo.',
|
|
style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _cardDettagli(OperationFormState state) {
|
|
return _buildCard(
|
|
title: 'Dettagli Servizio',
|
|
icon: Icons.design_services,
|
|
themeColor: Colors.deepOrange,
|
|
children: [
|
|
SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
children: [
|
|
ChoiceChip(
|
|
label: const Text('Privato (Domestico)'),
|
|
selected: !state.operation.isBusiness,
|
|
selectedColor: Colors.blue.withValues(alpha: 0.2),
|
|
checkmarkColor: Colors.blue.shade700,
|
|
onSelected: (selected) {
|
|
if (selected) {
|
|
context.read<OperationFormCubit>().updateFields(
|
|
isBusiness: false,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
const SizedBox(width: 12),
|
|
ChoiceChip(
|
|
label: const Text('Business (P.IVA)'),
|
|
selected: state.operation.isBusiness,
|
|
selectedColor: Colors.orange.withValues(alpha: 0.2),
|
|
checkmarkColor: Colors.orange.shade700,
|
|
onSelected: (selected) {
|
|
if (selected) {
|
|
context.read<OperationFormCubit>().updateFields(
|
|
isBusiness: true,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const Divider(height: 32),
|
|
Wrap(
|
|
spacing: 8.0,
|
|
runSpacing: 8.0,
|
|
children: _availableTypes.map((type) {
|
|
return ChoiceChip(
|
|
label: Text(type),
|
|
selected: state.operation.type == type,
|
|
onSelected: (selected) {
|
|
if (selected) {
|
|
// 1. Recuperiamo i provider caricati in memoria
|
|
final allProviders = context
|
|
.read<ProviderListCubit>()
|
|
.state
|
|
.providers;
|
|
|
|
// 2. Recuperiamo il provider di default del negozio dalla sessione
|
|
final defaultProviderId = context
|
|
.read<SessionCubit>()
|
|
.state
|
|
.currentStore
|
|
?.defaultProviderId;
|
|
|
|
// 3. Spariamo tutto nel metodo "tuttofare"
|
|
context.read<OperationFormCubit>().setTypeWithSmartDefaults(
|
|
newType: type,
|
|
allProviders: allProviders,
|
|
defaultProviderId: defaultProviderId,
|
|
);
|
|
}
|
|
},
|
|
);
|
|
}).toList(),
|
|
),
|
|
const Divider(height: 32),
|
|
Row(
|
|
children: [
|
|
const Text(
|
|
'Quantità:',
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
const Spacer(),
|
|
IconButton(
|
|
icon: const Icon(Icons.remove_circle_outline),
|
|
onPressed: state.operation.quantity > 1
|
|
? () => context.read<OperationFormCubit>().updateFields(
|
|
quantity: state.operation.quantity - 1,
|
|
)
|
|
: null,
|
|
),
|
|
Text(
|
|
'${state.operation.quantity}',
|
|
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.add_circle_outline),
|
|
onPressed: () => context.read<OperationFormCubit>().updateFields(
|
|
quantity: state.operation.quantity + 1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(height: 32),
|
|
OperationDetailsSection(
|
|
currentOp: state.operation,
|
|
currentType: state.operation.type,
|
|
freeTextSubtypeController: _freeTextSubtypeController,
|
|
freeTextDescriptionController: _freeTextDescriptionController,
|
|
durationQuickPicks: _buildDurationQuickPicks(),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _cardNote(OperationFormState state) {
|
|
return _buildCard(
|
|
title: 'Note Interne',
|
|
icon: Icons.notes,
|
|
themeColor: Colors.teal,
|
|
children: [
|
|
TextFormField(
|
|
controller: _noteController,
|
|
minLines: 14,
|
|
maxLines: 500,
|
|
decoration: InputDecoration(
|
|
hintText: 'Incolla seriali, ICCID, IBAN...',
|
|
alignLabelWithHint: true,
|
|
fillColor: Colors.teal.withValues(alpha: 0.05),
|
|
filled: true,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide.none,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _cardAllegati(OperationFormState state) {
|
|
return _buildCard(
|
|
title: 'Allegati e Documenti',
|
|
icon: Icons.attach_file,
|
|
themeColor: Colors.deepPurple,
|
|
children: [
|
|
SharedAttachmentsSection(
|
|
parentType: AttachmentParentType.operation,
|
|
parentId: state.operation.id,
|
|
titleForUpload: state.operation.customer?.name ?? 'Nuova Pratica',
|
|
onEnsureEntitySaved: _ensureEntitySaved, // 🥷 Il nuovo nome!
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// --- WIDGET BASE PER LA CARD ---
|
|
Widget _buildCard({
|
|
required String title,
|
|
required IconData icon,
|
|
required Color themeColor,
|
|
required List<Widget> children,
|
|
}) {
|
|
return Card(
|
|
margin: const EdgeInsets.only(bottom: 24),
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
side: BorderSide(color: themeColor.withValues(alpha: 0.3), width: 1),
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: themeColor.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(icon, color: themeColor),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
title,
|
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
color: themeColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Divider(height: 32),
|
|
...children,
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildDurationQuickPicks() {
|
|
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<OperationFormCubit>().updateFields(
|
|
expirationDate: DateTime(
|
|
now.year,
|
|
now.month + months,
|
|
now.day,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|