diff --git a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart index c9dc8f1..5b4b109 100644 --- a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart +++ b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart @@ -1,17 +1,23 @@ -// ignore_for_file: prefer_final_fields, unused_field - import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:kmobile/api/services/beneficiary_service.dart'; import 'package:kmobile/data/models/ifsc.dart'; import 'package:kmobile/data/models/beneficiary.dart'; +import 'package:kmobile/data/models/user.dart'; import 'beneficiary_result_page.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import '../../../di/injection.dart'; import '../../../l10n/app_localizations.dart'; class AddBeneficiaryScreen extends StatefulWidget { - const AddBeneficiaryScreen({super.key}); + final List? users; + final int? selectedIndex; + + const AddBeneficiaryScreen({ + super.key, + this.users, + this.selectedIndex, + }); @override State createState() => _AddBeneficiaryScreen(); @@ -20,6 +26,7 @@ class AddBeneficiaryScreen extends StatefulWidget { class _AddBeneficiaryScreen extends State { final _formKey = GlobalKey(); + late User selectedUser = (widget.users ?? [])[widget.selectedIndex!]; final TextEditingController accountNumberController = TextEditingController(); final TextEditingController confirmAccountNumberController = TextEditingController(); @@ -82,28 +89,83 @@ bool _isLoading = false; //for validateIFSC() Future _validateBeneficiary() async { - var beneficiaryService = getIt(); - setState(() { - _isValidating = true; - _validationError = null; - }); - try { - final name = await beneficiaryService - .validateBeneficiaryWithinBank(accountNumberController.text); + // start spinner / disable button + setState(() { + _isValidating = true; + _validationError = null; + _isBeneficiaryValidated = false; + nameController.text = ''; // clear previous name + }); + + final String accountNo = accountNumberController.text.trim(); + final String ifsc = ifscController.text.trim(); + final String remitter = selectedUser.name ?? ''; + + final service = getIt(); + try { + // Step 1: call validate API -> get refNo + final String? refNo = await service.validateBeneficiary( + accountNo: accountNo, + ifscCode: ifsc, + remitterName: remitter, + ); + + if (refNo == null || refNo.isEmpty) { setState(() { - _beneficiaryName = name; - _isBeneficiaryValidated = true; - _isValidating = false; - }); - } catch (e) { - setState(() { - _validationError = "Account Number not from KCCB"; - _isValidating = false; + _validationError = 'Validation request failed. Please check details.'; _isBeneficiaryValidated = false; - _beneficiaryName = null; + }); + return; + } + + // Step 2: poll checkValidationStatus for up to 30 seconds + const int timeoutSeconds = 30; + const int intervalSeconds = 2; + int elapsed = 0; + String? foundName; + + while (elapsed < timeoutSeconds) { + final String? name = await service.checkValidationStatus(refNo); + + if (name != null && name.trim().isNotEmpty) { + foundName = name.trim(); + break; + } + + await Future.delayed(const Duration(seconds: intervalSeconds)); + elapsed += intervalSeconds; + } + + if (foundName != null) { + setState(() { + nameController.text = foundName!; + _isBeneficiaryValidated = true; + _validationError = null; + }); + } else { + setState(() { + _validationError = 'Beneficiary not found within timeout.'; + _isBeneficiaryValidated = false; + }); + } + } catch (e, st) { + // handle unexpected errors + // print or log if you want + debugPrint('Error validating beneficiary: $e\n$st'); + setState(() { + _validationError = 'Something went wrong. Please try again.'; + _isBeneficiaryValidated = false; + }); + } finally { + if (mounted) { + setState(() { + _isValidating = false; }); } } +} + + String _selectedAccountType = 'Savings'; // default value @@ -361,67 +423,59 @@ void validateAndAddBeneficiary() async { ), ), ), - - //validate Beneficiary Button - if (!_isBeneficiaryValidated) - Padding( - padding: const EdgeInsets.only(top: 12.0), - child: SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: _isValidating - ? null - : () { - if (accountNumberController.text.length == 11 && - confirmAccountNumberController.text == - accountNumberController.text) { - _validateBeneficiary(); - } else { - setState(() { - _validationError = - 'Please enter a valid and matching account number.'; - }); - } - }, - child: _isValidating - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - - ) - : const Text('Validate Beneficiary'), - ), - ), - ), +//Validate Beneficiary Name +if (!_isBeneficiaryValidated) + Padding( + padding: const EdgeInsets.only(top: 12.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isValidating + ? null + : () { + if ( + confirmAccountNumberController.text == + accountNumberController.text) { + _validateBeneficiary(); + } else { + setState(() { + _validationError = + 'Please enter a valid and matching account number.'; + }); + } + }, + child: _isValidating + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Validate Beneficiary'), + ), + ), + ), //Beneficiary Name (Disabled) - const SizedBox(height: 24), TextFormField( - controller: nameController, - enabled: false, - decoration: InputDecoration( - labelText: AppLocalizations.of(context).beneficiaryName, - // prefixIcon: Icon(Icons.person), - border: const OutlineInputBorder(), - isDense: true, - filled: true, - fillColor: Theme.of(context).dialogBackgroundColor, - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.black), - ), - focusedBorder: const OutlineInputBorder( - borderSide: BorderSide( - color: Colors.black, - width: 2, - ), - ), - ), - textInputAction: TextInputAction.next, - validator: (value) => value == null || value.isEmpty - ? AppLocalizations.of(context).nameRequired - : null, - ), - + controller: nameController, + enabled: false, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).beneficiaryName, + border: const OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Theme.of(context).dialogBackgroundColor, + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2), + ), + ), + textInputAction: TextInputAction.next, + validator: (value) => value == null || value.isEmpty + ? AppLocalizations.of(context).nameRequired + : null, +), const SizedBox(height: 24), // 🔹 Account Type Dropdown DropdownButtonFormField( diff --git a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart index 2f64cd0..942699d 100644 --- a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart +++ b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart @@ -1,13 +1,17 @@ import 'package:flutter/material.dart'; import 'package:kmobile/data/models/beneficiary.dart'; import 'package:kmobile/features/beneficiaries/screens/add_beneficiary_screen.dart'; +import '../../../data/models/user.dart'; import '../../../l10n/app_localizations.dart'; import '../../../di/injection.dart'; import 'package:kmobile/api/services/beneficiary_service.dart'; import 'package:shimmer/shimmer.dart'; - +//import 'package:kmobile/data/models/user.dart'; class ManageBeneficiariesScreen extends StatefulWidget { + // final List users; + // final int selectedIndex; + const ManageBeneficiariesScreen({super.key}); @override @@ -17,9 +21,12 @@ class ManageBeneficiariesScreen extends StatefulWidget { class _ManageBeneficiariesScreen extends State { var service = getIt(); +// late User selectedUser = widget.users[widget.selectedIndex]; //final BeneficiaryService _service = BeneficiaryService(); bool _isLoading = true; + int selectedAccountIndex = 0; List _beneficiaries = []; + @override void initState() { @@ -101,7 +108,7 @@ class _ManageBeneficiariesScreen extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const AddBeneficiaryScreen(), + builder: (context) => AddBeneficiaryScreen(), ), ); },