import 'dart:async'; import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:kmobile/api/services/neft_service.dart'; import 'package:kmobile/api/services/rtgs_service.dart'; import 'package:kmobile/data/models/beneficiary.dart'; import 'package:kmobile/data/models/neft_transaction.dart'; import 'package:kmobile/data/models/payment_response.dart'; import 'package:kmobile/data/models/rtgs_transaction.dart'; import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import '../../../l10n/app_localizations.dart'; enum TransactionMode { neft, rtgs } class FundTransferAmountScreen extends StatefulWidget { final String debitAccountNo; final Beneficiary creditBeneficiary; final String remitterName; const FundTransferAmountScreen({ super.key, required this.debitAccountNo, required this.creditBeneficiary, required this.remitterName, }); @override State createState() => _FundTransferAmountScreenState(); } class _FundTransferAmountScreenState extends State { final _amountController = TextEditingController(); final _formKey = GlobalKey(); TransactionMode _selectedMode = TransactionMode.neft; @override void dispose() { _amountController.dispose(); super.dispose(); } Widget _getBankLogo(String? bankName) { if (bankName != null && bankName.toLowerCase().contains('state bank of india')) { return Image.asset( 'assets/images/sbi_logo.png', width: 40, height: 40, ); } else { return const Icon( Icons.account_balance, size: 40, color: Colors.grey, ); } } void _onProceed() { if (_formKey.currentState!.validate()) { final amount = double.tryParse(_amountController.text) ?? 0; if (_selectedMode == TransactionMode.rtgs && amount < 200000) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Invalid Amount for RTGS'), content: const Text( 'RTGS transactions require a minimum amount of 200,000. Please enter a higher amount or select NEFT as the transaction mode.'), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('OK'), ), ], ), ); return; // Stop further execution } Navigator.push( context, MaterialPageRoute( builder: (context) => TransactionPinScreen( onPinCompleted: (pinScreenContext, tpin) async { if (_selectedMode == TransactionMode.neft) { final neftTx = NeftTransaction( fromAccount: widget.debitAccountNo, toAccount: widget.creditBeneficiary.accountNo, amount: _amountController.text, ifscCode: widget.creditBeneficiary.ifscCode, remitterName: widget.remitterName, beneficiaryName: widget.creditBeneficiary.name, tpin: tpin, ); final neftService = getIt(); final completer = Completer(); Navigator.of(pinScreenContext).pushReplacement( MaterialPageRoute( builder: (_) => PaymentAnimationScreen( paymentResponse: completer.future), ), ); try { final neftResponse = await neftService.processNeftTransaction(neftTx); final paymentResponse = PaymentResponse( isSuccess: neftResponse.message.toUpperCase() == 'SUCCESS', date: DateTime.now(), creditedAccount: neftTx.toAccount, amount: neftTx.amount, currency: 'INR', utr: neftResponse.utr, ); completer.complete(paymentResponse); } on DioException catch(e) { print('dio exception'); print(e.toString()); final error = jsonDecode(e.response.toString())['error']; var errorMessage = { "INCORRECT_TPIN" : "Please Enter the correct TPIN", "INSUFFICIENT_FUNDS": "Your account does not have sufficient balance" }[error] ?? "Something Went Wrong"; final paymentResponse = PaymentResponse( isSuccess: false, errorMessage: errorMessage, ); completer.complete(paymentResponse); } catch (e) { print('generic exception'); print(e.toString()); final paymentResponse = PaymentResponse( isSuccess: false, errorMessage: "Something went Wrong", ); completer.complete(paymentResponse); } } else { final rtgsTx = RtgsTransaction( fromAccount: widget.debitAccountNo, toAccount: widget.creditBeneficiary.accountNo, amount: _amountController.text, ifscCode: widget.creditBeneficiary.ifscCode, remitterName: widget.remitterName, beneficiaryName: widget.creditBeneficiary.name, tpin: tpin, ); final rtgsService = getIt(); final completer = Completer(); Navigator.of(pinScreenContext).pushReplacement( MaterialPageRoute( builder: (_) => PaymentAnimationScreen( paymentResponse: completer.future), ), ); try { final rtgsResponse = await rtgsService.processRtgsTransaction(rtgsTx); final paymentResponse = PaymentResponse( isSuccess: rtgsResponse.message.toUpperCase() == 'SUCCESS', date: DateTime.now(), creditedAccount: rtgsTx.toAccount, amount: rtgsTx.amount, currency: 'INR', utr: rtgsResponse.utr, ); completer.complete(paymentResponse); } on DioException catch(e) { print('dio exception'); print(e.toString()); final error = jsonDecode(e.response.toString())['error']; var errorMessage = { "INCORRECT_TPIN" : "Please Enter the correct TPIN", "INSUFFICIENT_FUNDS": "Your account does not have sufficient balance" }[error] ?? "Something Went Wrong"; final paymentResponse = PaymentResponse( isSuccess: false, errorMessage: errorMessage, ); completer.complete(paymentResponse); } catch (e) { print('generic exception'); print(e.toString()); final paymentResponse = PaymentResponse( isSuccess: false, errorMessage: "Something went Wrong", ); completer.complete(paymentResponse); } } }, ), ), ); } } @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context); return Scaffold( appBar: AppBar( title: Text(loc.fundTransfer), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Debit Account (User) Text( loc.debitFrom, style: Theme.of(context).textTheme.titleSmall, ), Card( elevation: 0, margin: const EdgeInsets.symmetric(vertical: 8.0), child: ListTile( leading: Image.asset( 'assets/images/logo.png', width: 40, height: 40, ), title: Text(widget.remitterName), subtitle: Text(widget.debitAccountNo), ), ), const SizedBox(height: 24), // Credit Account (Beneficiary) Text( "Credit To", style: Theme.of(context).textTheme.titleSmall, ), Card( elevation: 0, margin: const EdgeInsets.symmetric(vertical: 8.0), child: ListTile( leading: _getBankLogo(widget.creditBeneficiary.bankName), title: Text(widget.creditBeneficiary.name), subtitle: Text(widget.creditBeneficiary.accountNo), ), ), const SizedBox(height: 24), // Transaction Mode Selection Text( "Select Transaction Mode", style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 12), Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: ToggleButtons( isSelected: [ _selectedMode == TransactionMode.neft, _selectedMode == TransactionMode.rtgs ], onPressed: (index) { setState(() { _selectedMode = TransactionMode.values[index]; }); }, borderRadius: BorderRadius.circular(10), selectedColor: Theme.of(context).colorScheme.onPrimary, fillColor: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.onSurface, borderColor: Colors.transparent, selectedBorderColor: Colors.transparent, splashColor: Theme.of(context).primaryColor.withOpacity(0.1), highlightColor: Theme.of(context).primaryColor.withOpacity(0.05), children: const [ Padding( padding: EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), child: Text('NEFT'), ), Padding( padding: EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), child: Text('RTGS'), ), ], ), ), const SizedBox(height: 24), // Amount TextFormField( controller: _amountController, keyboardType: TextInputType.number, decoration: InputDecoration( labelText: loc.amount, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.currency_rupee), ), validator: (value) { if (value == null || value.isEmpty) { return loc.amountRequired; } if (double.tryParse(value) == null || double.parse(value) <= 0) { return loc.validAmount; } return null; }, ), const Spacer(), // Proceed Button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _onProceed, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), child: const Text("Proceed"), ), ), ], ), ), ), ); } }