diff --git a/lib/api/services/imps_service.dart b/lib/api/services/imps_service.dart index 2491f4a..937696b 100644 --- a/lib/api/services/imps_service.dart +++ b/lib/api/services/imps_service.dart @@ -12,7 +12,7 @@ class ImpsService { try { await Future.delayed(const Duration(seconds: 3)); final response = await _dio.post( - '/api/payment/rtgs', + '/api/payment/imps', data: transaction.toJson(), ); @@ -20,7 +20,7 @@ class ImpsService { return ImpsResponse.fromJson(response.data); } else { throw Exception( - 'RTGS transaction failed with status code: ${response.statusCode}'); + 'IMPS transaction failed with status code: ${response.statusCode}'); } } on DioException { rethrow; diff --git a/lib/app.dart b/lib/app.dart index 5714d85..99a2633 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -98,7 +98,7 @@ class _KMobileState extends State { ], title: 'kMobile', theme: themeState.getThemeData(), - darkTheme: themeState.getThemeData(), + //darkTheme: themeState.getThemeData(), themeMode: ThemeMode.system, onGenerateRoute: AppRoutes.generateRoute, initialRoute: AppRoutes.splash, @@ -472,3 +472,4 @@ class BiometricPromptScreen extends StatelessWidget { } } } + diff --git a/lib/config/themes.dart b/lib/config/themes.dart index ed41c1b..e6d45df 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -16,17 +16,17 @@ class AppThemes { } } - static ThemeData getDarkTheme(ThemeType type) { - switch (type) { - case ThemeType.green: - return ThemeData.dark().copyWith(primaryColor: Colors.green); - case ThemeType.orange: - return ThemeData.dark().copyWith(primaryColor: Colors.orange); - case ThemeType.blue: - return ThemeData.dark().copyWith(primaryColor: Colors.blue); - case ThemeType.violet: - default: - return ThemeData.dark().copyWith(primaryColor: Colors.deepPurple); - } - } + // static ThemeData getDarkTheme(ThemeType type) { + // switch (type) { + // case ThemeType.green: + // return ThemeData.dark().copyWith(primaryColor: Colors.green); + // case ThemeType.orange: + // return ThemeData.dark().copyWith(primaryColor: Colors.orange); + // case ThemeType.blue: + // return ThemeData.dark().copyWith(primaryColor: Colors.blue); + // case ThemeType.violet: + // default: + // return ThemeData.dark().copyWith(primaryColor: Colors.deepPurple); + // } + // } } diff --git a/lib/data/models/imps_transaction.dart b/lib/data/models/imps_transaction.dart index 76e64c7..d731e17 100644 --- a/lib/data/models/imps_transaction.dart +++ b/lib/data/models/imps_transaction.dart @@ -19,13 +19,12 @@ class ImpsTransaction { Map toJson() { return { - 'stFromAccDetails': fromAccount, - 'stBenAccNo': toAccount, - 'stTransferAmount': amount, - 'stBenIFSC': ifscCode, - //'remitterName': remitterName, - 'stBeneName': beneficiaryName, - 'stRemarks': "Check", + 'fromAccount': fromAccount, + 'toAccount': toAccount, + 'amount': amount, + 'ifscCode': ifscCode, + 'remitterName': remitterName, + 'beneficiaryName': beneficiaryName, 'tpin': tpin, }; } diff --git a/lib/data/models/rtgs_response.dart b/lib/data/models/rtgs_response.dart index b572690..d9ae867 100644 --- a/lib/data/models/rtgs_response.dart +++ b/lib/data/models/rtgs_response.dart @@ -14,3 +14,6 @@ class RtgsResponse { ); } } + + + diff --git a/lib/di/injection.dart b/lib/di/injection.dart index 1fc3682..9fd64e5 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -1,5 +1,6 @@ import 'package:kmobile/api/services/rtgs_service.dart'; import 'package:kmobile/api/services/neft_service.dart'; +import 'package:kmobile/api/services/imps_service.dart'; import 'package:get_it/get_it.dart'; import 'package:dio/dio.dart'; import 'package:kmobile/api/services/beneficiary_service.dart'; @@ -44,6 +45,7 @@ Future setupDependencies() async { getIt.registerSingleton(BeneficiaryService(getIt())); getIt.registerSingleton(NeftService(getIt())); getIt.registerSingleton(RtgsService(getIt())); + getIt.registerSingleton(ImpsService(getIt())); // Add auth interceptor after repository is available getIt().interceptors.add( @@ -59,8 +61,8 @@ Dio _createDioClient() { final dio = Dio( BaseOptions( baseUrl: - 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', - //'http://localhost:8081', + //'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', + 'http://localhost:8081', connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 10), headers: { diff --git a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart index da8c8ec..3d0eff6 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart @@ -1,10 +1,12 @@ -// ignore_for_file: avoid_print +// ignore_for_file: avoid_print, use_build_context_synchronously, duplicate_ignore 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/api/services/imps_service.dart'; +import 'package:kmobile/data/models/imps_transaction.dart'; import 'package:kmobile/widgets/bank_logos.dart'; import 'package:kmobile/data/models/beneficiary.dart'; import 'package:kmobile/data/models/neft_transaction.dart'; @@ -15,7 +17,7 @@ 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 } +enum TransactionMode { neft, rtgs, imps } class FundTransferAmountScreen extends StatefulWidget { final String debitAccountNo; @@ -133,64 +135,66 @@ class _FundTransferAmountScreenState extends State { completer.complete(paymentResponse); } } - // else if (_selectedMode == TransactionMode.imps){ - // 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(); + + //IMPS transaction + else if (_selectedMode == TransactionMode.imps){ + final impsTx = ImpsTransaction( + fromAccount: widget.debitAccountNo, + toAccount: widget.creditBeneficiary.accountNo, + amount: _amountController.text, + ifscCode: widget.creditBeneficiary.ifscCode, + remitterName: widget.remitterName, + beneficiaryName: widget.creditBeneficiary.name, + tpin: tpin, + ); + final impsService = getIt(); + final completer = Completer(); - // Navigator.of(pinScreenContext).pushReplacement( - // MaterialPageRoute( - // builder: (_) => PaymentAnimationScreen( - // paymentResponse: completer.future), - // ), - // ); + 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()); + try { + final impsResponse = + await impsService.processImpsTransaction(impsTx); + final paymentResponse = PaymentResponse( + isSuccess: impsResponse.message.toUpperCase() == 'SUCCESS', + date: DateTime.now(), + creditedAccount: impsTx.toAccount, + amount: impsTx.amount, + currency: 'INR', + utr: impsResponse.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 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); - // } - // } + 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, @@ -325,7 +329,9 @@ class _FundTransferAmountScreenState extends State { child: ToggleButtons( isSelected: [ _selectedMode == TransactionMode.neft, - _selectedMode == TransactionMode.rtgs + _selectedMode == TransactionMode.rtgs, + _selectedMode == TransactionMode.imps, + ], onPressed: (index) { setState(() { @@ -352,10 +358,10 @@ class _FundTransferAmountScreenState extends State { horizontal: 24.0, vertical: 12.0), child: Text(AppLocalizations.of(context).rtgs), ), - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), - // child: Text(AppLocalizations.of(context).imps), - // ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), + child: Text(AppLocalizations.of(context).imps), + ), ], ), ), diff --git a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart index 10c30aa..269b776 100644 --- a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart +++ b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart @@ -1,7 +1,11 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:async'; import 'package:flutter/services.dart'; +import 'package:kmobile/api/services/imps_service.dart'; import 'package:kmobile/api/services/neft_service.dart'; import 'package:kmobile/api/services/rtgs_service.dart'; +import 'package:kmobile/data/models/imps_transaction.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'; @@ -118,6 +122,7 @@ class _QuickPayOutsideBankScreen extends State { return [ AppLocalizations.of(context).neft, AppLocalizations.of(context).rtgs, + AppLocalizations.of(context).imps, ]; } @@ -151,6 +156,8 @@ class _QuickPayOutsideBankScreen extends State { final amount = double.tryParse(amountController.text) ?? 0; final selectedMode = transactionModes(context)[selectedTransactionIndex]; final isRtgs = selectedMode == AppLocalizations.of(context).rtgs; + final isNeft = selectedMode == AppLocalizations.of(context).neft; + final isImps = selectedMode == AppLocalizations.of(context).imps; if (isRtgs && amount < 200000) { showDialog( @@ -174,14 +181,14 @@ class _QuickPayOutsideBankScreen extends State { MaterialPageRoute( builder: (context) => TransactionPinScreen( onPinCompleted: (pinScreenContext, tpin) async { - if (!isRtgs) { + if (isNeft) { // NEFT final neftTx = NeftTransaction( fromAccount: widget.debitAccount, toAccount: accountNumberController.text, amount: amountController.text, ifscCode: ifscController.text, - remitterName: "Unknown", // TODO: Get actual remitter name + remitterName: "Unknown", beneficiaryName: nameController.text, tpin: tpin, ); @@ -214,14 +221,58 @@ class _QuickPayOutsideBankScreen extends State { ); completer.complete(paymentResponse); } - } else { + } + + if (isImps) { + // IMPS + final impsTx = ImpsTransaction( + fromAccount: widget.debitAccount, + toAccount: accountNumberController.text, + amount: amountController.text, + ifscCode: ifscController.text, + remitterName: "Unknown", + beneficiaryName: nameController.text, + tpin: tpin, + ); + final impsService = getIt(); + final completer = Completer(); + + Navigator.of(pinScreenContext).pushReplacement( + MaterialPageRoute( + builder: (_) => PaymentAnimationScreen( + paymentResponse: completer.future), + ), + ); + + try { + final neftResponse = + await impsService.processImpsTransaction(impsTx); + final paymentResponse = PaymentResponse( + isSuccess: neftResponse.message.toUpperCase() == 'SUCCESS', + date: DateTime.now(), + creditedAccount: impsTx.toAccount, + amount: impsTx.amount, + currency: 'INR', + utr: neftResponse.utr, + ); + completer.complete(paymentResponse); + } catch (e) { + final paymentResponse = PaymentResponse( + isSuccess: false, + errorMessage: e.toString(), + ); + completer.complete(paymentResponse); + } + } + + if(isRtgs) { // RTGS final rtgsTx = RtgsTransaction( fromAccount: widget.debitAccount, toAccount: accountNumberController.text, amount: amountController.text, ifscCode: ifscController.text, - remitterName: "Unknown", // TODO: Get actual remitter name + remitterName: "Unknown", beneficiaryName: nameController.text, tpin: tpin, ); diff --git a/lib/features/service/screens/branch_locator_screen.dart b/lib/features/service/screens/branch_locator_screen.dart index 651f477..c9353a8 100644 --- a/lib/features/service/screens/branch_locator_screen.dart +++ b/lib/features/service/screens/branch_locator_screen.dart @@ -1,43 +1,148 @@ import '../../../l10n/app_localizations.dart'; import 'package:flutter/material.dart'; -class BranchLocatorScreen extends StatelessWidget { +class Branch { + final String name; + final String code; + final String ifsc; + final String address; + + Branch({required this.name, required this.code, required this.ifsc, required this.address,}); +} + +class BranchLocatorScreen extends StatefulWidget { const BranchLocatorScreen({super.key}); - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context).branchLocator), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.location_on, - size: 80, - color: Theme.of(context).primaryColor, - ), - const SizedBox(height: 16), - Text( - AppLocalizations.of(context).findnearbybranched, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 24), - ElevatedButton.icon( - icon: const Icon(Icons.search), - label: Text( AppLocalizations.of(context).searchbranch), - onPressed: () { - // Place API here - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text( AppLocalizations.of(context).branchsearchsoon)), - ); - }, - ), - ], - ), - ), - ); - } -} \ No newline at end of file +@override +State createState() => _BranchLocatorScreenState(); +} + +class _BranchLocatorScreenState extends State { +final TextEditingController _searchController = TextEditingController(); + +// Static list of 5 branches +final List _branches = [ +Branch(name: "Dharamsala - Head Office", code: "002", ifsc: "KACE0000002", address: "Civil Lines Dharmashala, Kangra, HP - 176215"), +Branch(name: "Kangra", code: "033", ifsc: "KACE0000033", address: "Rajput Bhawankangrapo Kangra, Kangra, HP "), +]; + +List _filteredBranches = []; + +@override +void initState() { +super.initState(); +_filteredBranches = _branches; // Initially show all branches +} + +void _filterBranches(String query) { +setState(() { +if (query.isEmpty) { +_filteredBranches = _branches; +} else { +_filteredBranches = _branches.where((branch) { +final lowerQuery = query.toLowerCase(); +return branch.name.toLowerCase().contains(lowerQuery) || +branch.code.toLowerCase().contains(lowerQuery) || +branch.ifsc.toLowerCase().contains(lowerQuery) || +branch.address.toLowerCase().contains(lowerQuery); +}).toList(); +} +}); +} + + + +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// appBar: AppBar( +// title: Text(AppLocalizations.of(context).branchLocator), +// ), +// body: Center( +// child: Column( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Icon( +// Icons.location_on, +// size: 80, +// color: Theme.of(context).primaryColor, +// ), +// const SizedBox(height: 16), +// Text( +// AppLocalizations.of(context).findnearbybranched, +// style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), +// ), +// const SizedBox(height: 24), +// ElevatedButton.icon( +// icon: const Icon(Icons.search), +// label: Text( AppLocalizations.of(context).searchbranch), +// onPressed: () { +// // Place API here + +// // ScaffoldMessenger.of(context).showSnackBar( +// // SnackBar(content: Text( AppLocalizations.of(context).branchsearchsoon)), +// // ); +// }, +// ), +// ], +// ), +// ), +// ); +// } +// } + +@override +Widget build(BuildContext context) { +return Scaffold( +appBar: AppBar( +title: Text(AppLocalizations.of(context).branchLocator), +), +body: Column( +children: [ +// Search bar +Padding( +padding: const EdgeInsets.all(12.0), +child: TextField( +controller: _searchController, +onChanged: _filterBranches, +decoration: InputDecoration( +hintText: AppLocalizations.of(context).searchbranchby, +prefixIcon: const Icon(Icons.search), +border: OutlineInputBorder( +borderRadius: BorderRadius.circular(12), +), +), +), +), + +// List of branches +Expanded( +child: _filteredBranches.isEmpty +? const Center(child: Text("No matching branches found")) +: ListView.builder( +itemCount: _filteredBranches.length, +itemBuilder: (context, index) { +final branch = _filteredBranches[index]; +return Card( +margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), +child: ListTile( +leading: Icon(Icons.location_city, color: Theme.of(context).primaryColor), +title: Text(branch.name, style: const TextStyle(fontWeight: FontWeight.bold)), +subtitle: Text("Code: ${branch.code} | IFSC: ${branch.ifsc} \nBranch Address: ${branch.address}"), +onTap: () { +ScaffoldMessenger.of(context).showSnackBar( +SnackBar(content: Text("Selected ${branch.name}")), +); +}, +), +); +}, +), +), +], +), +); +} +} + + diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f0b46c4..462d3b5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -249,6 +249,7 @@ "validateBeneficiaryproceeding": "Please validate beneficiary before proceeding", "findnearbybranched": "Find nearby branches", "searchbranch": "Search Branch", + "searchbranchby": "Search by Branch Name / Code / IFSC", "branchsearchsoon": "Branch search coming soon..." } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index e084093..0c36772 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -249,5 +249,6 @@ "validateBeneficiaryproceeding": "कृपया आगे बढ़ने से पहले लाभार्थी को पट्टे पर मान्य करें", "findnearbybranched": "आस-पास की शाखाएँ खोजें", "searchbranch": "शाखा खोजें", + "searchbranchby": "शाखा खोजें नाम / बैंक कोड / आईएफएससी द्वारा", "branchsearchsoon": "शाखा खोज सुविधा जल्द ही आ रही है..." } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 763f13a..85a3b5a 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1517,6 +1517,12 @@ abstract class AppLocalizations { /// **'Search Branch'** String get searchbranch; + /// No description provided for @searchbranchby. + /// + /// In en, this message translates to: + /// **'Search by Branch Name / Code / IFSC'** + String get searchbranchby; + /// No description provided for @branchsearchsoon. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index ceba208..2a68236 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -719,6 +719,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get searchbranch => 'Search Branch'; + @override + String get searchbranchby => 'Search by Branch Name / Code / IFSC'; + @override String get branchsearchsoon => 'Branch search coming soon...'; } diff --git a/lib/l10n/app_localizations_hi.dart b/lib/l10n/app_localizations_hi.dart index 75a9f5e..5f4b61c 100644 --- a/lib/l10n/app_localizations_hi.dart +++ b/lib/l10n/app_localizations_hi.dart @@ -719,6 +719,9 @@ class AppLocalizationsHi extends AppLocalizations { @override String get searchbranch => 'शाखा खोजें'; + @override + String get searchbranchby => 'शाखा खोजें नाम / बैंक कोड / आईएफएससी द्वारा'; + @override String get branchsearchsoon => 'शाखा खोज सुविधा जल्द ही आ रही है...'; }