import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:kmobile/api/services/deposit_service.dart'; import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:kmobile/l10n/app_localizations.dart'; class CreateDepositScreen extends StatefulWidget { final User selectedAccount; final Map? initialData; const CreateDepositScreen({ super.key, required this.selectedAccount, this.initialData, }); @override State createState() => _CreateDepositScreenState(); } class _CreateDepositScreenState extends State { final _formKey = GlobalKey(); bool _isLoading = false; // Controllers late final _fromAcctNoController = TextEditingController(text: widget.selectedAccount.accountNo.toString()); late final _cifNoController = TextEditingController( text: widget.initialData?['cifNo']?.toString()); late final _idNoController = TextEditingController( text: widget.initialData?['idno']?.toString()); late final _customerNameController = TextEditingController( text: widget.initialData?['customername']?.toString()); late final _nationalityController = TextEditingController( text: widget.initialData?['nationality']?.toString()); late final _addressLine1Controller = TextEditingController( text: widget.initialData?['addressline1']?.toString()); late final _addressLine2Controller = TextEditingController( text: widget.initialData?['addressline2']?.toString()); late final _pincodeController = TextEditingController( text: widget.initialData?['pincode']?.toString()); late final _productController = TextEditingController(); late final _typeController = TextEditingController(); late final _customerCategoryController = TextEditingController(); late final _termLocationController = TextEditingController(); late final _currencyController = TextEditingController(); late final _acctSgmtCodeController = TextEditingController(); late final _interestPaymentMethodController = TextEditingController(); late final _taxFileNumberIndicatorController = TextEditingController(); late final _termLengthController = TextEditingController(); late final _termBasisController = TextEditingController(); late final _termValueDepositedController = TextEditingController(); late final _interestFrequencyController = TextEditingController(); late final _termDaysController = TextEditingController(); late final _termMonthsController = TextEditingController(); late final _termYearsController = TextEditingController(); late final _nominationRequiredController = TextEditingController(); late final _printNomineeNameController = TextEditingController(); // RD specific controllers late final _rdInstallmentValueController = TextEditingController(); late final _monthlyRDInstallmentDueDayController = TextEditingController(); late final _rdInstlFreqController = TextEditingController(); final Map _productOptions = { '20': 'Term Deposit', '25': 'Fixed Deposit', '28': 'Recurring Deposit', }; final Map _typeOptions = { '01': 'Member', '02': 'Non-Member', '03': 'Staff', '04': 'Govt', '05': 'School', '06': 'Panchayat', '07': 'Trusts', '08': 'Municipal Council', '09': 'NRO', '10': 'Bank', '11': 'No Frill', '12': 'Special Schemes', '13': 'Minor', }; final Map _customerCategoryOptions = { '1': 'Public Individual', '2': 'Societies', '3': 'Senior Citizen', '5': 'Government', '6': 'Local Bodies', '7': 'Other', }; final Map _termLocationOptions = { '10': 'SB/CA', '13': '46–90 Days', '14': '91–180 Days', '15': '180 Days–1 Year', '16': '1 Year–<18 Months', '20': '18 Months–<2 Years', '17': '2–3 Years', '18': '3–10 Years', '22': 'Above 10 Years', '24': 'Dev Kanya Yojna 9+1', '25': 'Hazar Dain Lakh Ley Jayain', }; final Map _currencyOptions = { '1': 'INR', }; final Map _acctSgmtCodeOptions = { '0706': 'Public Individual', '5002': 'Societies', '5005': 'Government', '5050': 'GL Others', }; final Map _interestPaymentMethodOptions = { 'R': 'Re-invest', }; final Map _termBasisOptions = { 'D': 'Days', 'M': 'Months', }; final Map _interestFrequencyOptions = { 'M': 'On Maturity / Roll Over', '1M': 'Monthly', '3M': 'Quarterly', '1A': 'Anniversary Monthly', '3A': 'Anniversary Quarterly', }; final Map _rdInstlFreqOptions = { 'M': 'Monthly', }; @override void dispose() { _fromAcctNoController.dispose(); _cifNoController.dispose(); _idNoController.dispose(); _customerNameController.dispose(); _nationalityController.dispose(); _addressLine1Controller.dispose(); _addressLine2Controller.dispose(); _pincodeController.dispose(); _productController.dispose(); _typeController.dispose(); _customerCategoryController.dispose(); _termLocationController.dispose(); _currencyController.dispose(); _acctSgmtCodeController.dispose(); _interestPaymentMethodController.dispose(); _taxFileNumberIndicatorController.dispose(); _termLengthController.dispose(); _termBasisController.dispose(); _termValueDepositedController.dispose(); _interestFrequencyController.dispose(); _termDaysController.dispose(); _termMonthsController.dispose(); _termYearsController.dispose(); _nominationRequiredController.dispose(); _printNomineeNameController.dispose(); _rdInstallmentValueController.dispose(); _monthlyRDInstallmentDueDayController.dispose(); _rdInstlFreqController.dispose(); super.dispose(); } void _handleCreate() { if (_formKey.currentState!.validate()) { Navigator.push( context, MaterialPageRoute( builder: (context) => TransactionPinScreen( onPinCompleted: (ctx, pin) async { Navigator.pop(context); _executeCreation(pin); }, ), ), ); } } void _executeCreation(String pin) async { setState(() { _isLoading = true; }); try { final product = _productController.text; dynamic response; if (product == '20' || product == '25') { response = await getIt().createFdTd( fromacctno: _fromAcctNoController.text, cifNo: _cifNoController.text, idno: _idNoController.text, customername: _customerNameController.text, nationality: _nationalityController.text, addressline1: _addressLine1Controller.text, addressline2: _addressLine2Controller.text, pincode: _pincodeController.text, product: _productController.text, type: _typeController.text, customercategory: _customerCategoryController.text, termlocation: _termLocationController.text, currency: _currencyController.text, acctsgmtcode: _acctSgmtCodeController.text, interestpaymentmethod: _interestPaymentMethodController.text, taxfilenumberindicator: _taxFileNumberIndicatorController.text, termlenght: _termLengthController.text, termbasis: _termBasisController.text, termvaluedeposited: _termValueDepositedController.text, interestfrequency: _interestFrequencyController.text, termdays: _termDaysController.text, termmonths: _termMonthsController.text, termyears: _termYearsController.text, nominationRequired: _nominationRequiredController.text, printNomineename: _printNomineeNameController.text, tpin: pin, ); } else if (product == '28') { response = await getIt().createRd( fromacctno: _fromAcctNoController.text, cifNo: _cifNoController.text, idno: _idNoController.text, customername: _customerNameController.text, nationality: _nationalityController.text, addressline1: _addressLine1Controller.text, addressline2: _addressLine2Controller.text, pincode: _pincodeController.text, product: _productController.text, type: _typeController.text, customercategory: _customerCategoryController.text, termlocation: _termLocationController.text, currency: _currencyController.text, acctsgmtcode: _acctSgmtCodeController.text, interestpaymentmethod: _interestPaymentMethodController.text, taxfilenumberindicator: _taxFileNumberIndicatorController.text, termlenght: _termLengthController.text, termbasis: _termBasisController.text, termvaluedeposited: _termValueDepositedController.text, interestfrequency: _interestFrequencyController.text, termdays: _termDaysController.text, termmonths: _termMonthsController.text, termyears: _termYearsController.text, nominationRequired: _nominationRequiredController.text, printNomineename: _printNomineeNameController.text, rdinstallmentvalue: _rdInstallmentValueController.text, monthlyRDInstallmentdueday: _monthlyRDInstallmentDueDayController.text, rdInstlFreq: _rdInstlFreqController.text, tpin: pin, ); } if (response != null && response is Map) { if (mounted) { if (response['error'] == 'INCORRECT_TPIN' || response['message'] == 'INCORRECT_TPIN') { _showSimpleDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.'); } else if (response['status'] == 'FAILED') { _showFailureDialog(response['message']?.toString()); } else if (response.containsKey('accountno')) { _showResponseDialog(response); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Unexpected response from server")), ); } } } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Failed to create deposit")), ); } } } on DioException catch (e) { if (mounted) { try { final errorBody = e.response?.data; if (errorBody is Map && (errorBody['error'] == 'INCORRECT_TPIN' || errorBody['message'] == 'INCORRECT_TPIN')) { _showSimpleDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.'); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Error: ${e.message}")), ); } } catch (_) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Internal Server Error")), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Error: $e")), ); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } Future _showSimpleDialog(String title, String message) async { return showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text(title), content: SingleChildScrollView( child: ListBody( children: [ Text(message), ], ), ), actions: [ TextButton( child: const Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } void _showFailureDialog(String? apiMessage) { showDialog( context: context, builder: (context) => AlertDialog( title: Row( children: [ Icon(Icons.error_outline, color: Theme.of(context).colorScheme.error), const SizedBox(width: 8), const Text("Creation Failed"), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Account creation could not be completed at this time.", style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 12), if (apiMessage != null) ...[ Text("Reason: $apiMessage"), const SizedBox(height: 12), ], const Text( "Please ensure that the provided details (term length, basis, interest frequency, etc.) are correct and compatible with the selected product. If the issue persists, please contact the branch.", ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text("OK"), ), ], ), ); } void _showResponseDialog(Map response) { final accountNo = response['accountno']?.toString() ?? 'N/A'; final accountTypeRaw = response['accounttype']?.toString() ?? ''; final accountTypeText = _productOptions[accountTypeRaw] ?? accountTypeRaw; final amount = response['amount']?.toString() ?? '0.0'; showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: const Text("Deposit Created Successfully"), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Account No: $accountNo"), const SizedBox(height: 8), Text("Account Type: $accountTypeText"), const SizedBox(height: 8), Text("Amount: $amount"), ], ), actions: [ TextButton( onPressed: () { Navigator.of(context).popUntil((route) => route.isFirst); }, child: const Text("OK"), ), ], ), ); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); return Scaffold( appBar: AppBar( title: const Text("Create Deposit"), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Tile 1: Customer Info Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Customer Information", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildTextField(_fromAcctNoController, "From Account No", mandatory: true, readOnly: true), _buildTextField(_cifNoController, "CIF No"), _buildTextField(_idNoController, "ID No"), _buildTextField(_customerNameController, "Customer Name"), _buildTextField(_nationalityController, "Nationality"), _buildTextField(_addressLine1Controller, "Address Line 1"), _buildTextField(_addressLine2Controller, "Address Line 2"), _buildTextField(_pincodeController, "Pincode", keyboardType: TextInputType.number), ], ), ), ), const SizedBox(height: 16), // Tile 2: Deposit Details Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Deposit Details", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildDropdownField( _productController, "Product", _productOptions, mandatory: true, onChanged: (val) { setState(() { _productController.text = val ?? ''; }); }), _buildDropdownField(_typeController, "Type", _typeOptions, mandatory: true), _buildDropdownField(_customerCategoryController, "Customer Category", _customerCategoryOptions, mandatory: true), _buildDropdownField(_termLocationController, "Term Location", _termLocationOptions, mandatory: true), _buildDropdownField( _currencyController, "Currency", _currencyOptions, mandatory: true), _buildDropdownField(_acctSgmtCodeController, "Account Segment Code", _acctSgmtCodeOptions, mandatory: true), ], ), ), ), const SizedBox(height: 16), // Tile 3: Interest & Term Settings Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Interest & Term Settings", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildDropdownField(_interestPaymentMethodController, "Interest Payment Method", _interestPaymentMethodOptions, mandatory: true), _buildTextField(_taxFileNumberIndicatorController, "Tax File Number Indicator"), _buildTextField(_termLengthController, "Term Length"), _buildDropdownField( _termBasisController, "Term Basis", _termBasisOptions, mandatory: true), _buildTextField(_termValueDepositedController, "Term Value Deposited", keyboardType: TextInputType.number, mandatory: _productController.text != '28'), _buildDropdownField(_interestFrequencyController, "Interest Frequency", _interestFrequencyOptions), _buildTextField(_termDaysController, "Term Days", keyboardType: TextInputType.number), _buildTextField(_termMonthsController, "Term Months", keyboardType: TextInputType.number), _buildTextField(_termYearsController, "Term Years", keyboardType: TextInputType.number, mandatory: true), _buildTextField( _nominationRequiredController, "Nomination Required"), _buildTextField( _printNomineeNameController, "Print Nominee Name"), ], ), ), ), const SizedBox(height: 16), // Tile 4: RD Specific Fields (Conditional) if (_productController.text == '28') Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Recurring Deposit Settings", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildTextField(_rdInstallmentValueController, "RD Installment Value", keyboardType: TextInputType.number), _buildTextField(_monthlyRDInstallmentDueDayController, "Monthly RD Installment Due Day", keyboardType: TextInputType.number), _buildDropdownField(_rdInstlFreqController, "RD Installment Frequency", _rdInstlFreqOptions), ], ), ), ), const SizedBox(height: 24), ElevatedButton( onPressed: _isLoading ? null : _handleCreate, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primaryContainer, foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer, padding: const EdgeInsets.symmetric(vertical: 16), elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text( "Proceed", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 32), ], ), ), ), ); } Widget _buildDropdownField(TextEditingController controller, String label, Map options, {bool readOnly = false, bool mandatory = false, void Function(String?)? onChanged}) { String? currentValue = options.containsKey(controller.text) ? controller.text : null; return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: DropdownButtonFormField( value: currentValue, onChanged: readOnly || _isLoading ? null : (newValue) { if (newValue != null) { setState(() { controller.text = newValue; }); } if (onChanged != null) { onChanged(newValue); } }, decoration: InputDecoration( labelText: mandatory ? '$label *' : label, border: const OutlineInputBorder(), contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), validator: (value) { if (mandatory && (value == null || value.isEmpty)) { return 'This field is required'; } return null; }, items: options.entries.map((entry) { return DropdownMenuItem( value: entry.key, child: Text(entry.value), ); }).toList(), ), ); } Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false, bool mandatory = false, VoidCallback? onTap}) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: TextFormField( controller: controller, readOnly: readOnly || onTap != null || _isLoading, onTap: _isLoading ? null : onTap, decoration: InputDecoration( labelText: mandatory ? '$label *' : label, border: const OutlineInputBorder(), suffixIcon: onTap != null ? const Icon(Icons.calendar_today) : null, contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), keyboardType: keyboardType, validator: (value) { if (mandatory && (value == null || value.isEmpty)) { return 'This field is required'; } return null; }, ), ); } }