diff --git a/lib/api/services/yojna_service.dart b/lib/api/services/yojna_service.dart index 9440048..0f8e7ee 100644 --- a/lib/api/services/yojna_service.dart +++ b/lib/api/services/yojna_service.dart @@ -210,4 +210,125 @@ String? policystatus, return null; } } + + Future fetchpapydetails({ + required String accountno, + }) async { + try { + final response = await _dio.post( + "/api/apy/req/APY", + data: { + 'accountNo': accountno, + }, + options: Options( + headers: { + "Content-Type": "application/json", + }, + ), + ); + + log("PMY Details Response: ${response.data}"); + + if (response.statusCode == 200) { + return response.data; + } else { + throw Exception("INTERNAL SERVER ERROR"); + } + } catch (e) { + log("Error fetching APY details: $e"); + return null; + } + } + + Future registerAPY({ +String? accountno, +String? customerfirstname, +String? customermiddlename, +String? customerlastname, +String? availablebalance, +String? customerdob, +String? emailid, +String? gender, +String? married, +String? nomineename, +String? relationwithsubscriber, +String? mobilenumber, +String? nomineeminor, +String? customerno, +String? beneficaryofothersociatysecurityschemes, +String? whetherincometaxpayer, +String? customertitle, +String? aadharno, +String? nameofspouse, +String? ageofjoining, +String? pensionamtoptedfor, +String? montlycontributioncalculate, +String? collectionchannel, +String? subsequentContributionDebitDate, +String? secondnomineeminor, +String? secondnomineename, +String? secondrelationshipwithsubscriber, +String? pincode, +String? fatcacrsapplicable, +String? countryofbirth, +String? countryofcitizenship, +String? countryofresidencefortaxpurpose, +String? uspersonflag, +String? fatcadeclarationcount, +String? documentevidencingcitizenshipflag, +String? reasonfornoevidence, +String? nameofdocumentforcitizenshipevidence, +String? modeofcollection, +String? contributionType, + }) async { + final response = await _dio.post( + '/api/apy/create/APY', + options: Options( + validateStatus: (int? status) => true, + receiveDataWhenStatusError: true, + ), + data: { + 'accountno':accountno, +'customerfirstname':customerfirstname, +'customermiddlename':customermiddlename, +'customerlastname':customerlastname, +'availablebalance':availablebalance, +'customerdob':customerdob, +'emailid':emailid, +'gender':gender, +'married':married, +'nomineename':nomineename, +'relationwithsubscriber':relationwithsubscriber, +'mobilenumber':mobilenumber, +'nomineeminor':nomineeminor, +'customerno':customerno, +'beneficaryofothersociatysecurityschemes':beneficaryofothersociatysecurityschemes, +'whetherincometaxpayer':whetherincometaxpayer, +'customertitle':customertitle, +'aadharno':aadharno, +'nameofspouse':nameofspouse, +'ageofjoining':ageofjoining, +'pensionamtoptedfor':pensionamtoptedfor, +'montlycontributioncalculate':montlycontributioncalculate, +'collectionchannel':collectionchannel, +'subsequentContributionDebitDate':subsequentContributionDebitDate, +'secondnomineeminor':secondnomineeminor, +'secondnomineename':secondnomineename, +'secondrelationshipwithsubscriber':secondrelationshipwithsubscriber, +'pincode':pincode, +'fatcacrsapplicable':fatcacrsapplicable, +'countryofbirth':countryofbirth, +'countryofcitizenship':countryofcitizenship, +'countryofresidencefortaxpurpose':countryofresidencefortaxpurpose, +'uspersonflag':uspersonflag, +'fatcadeclarationcount':fatcadeclarationcount, +'documentevidencingcitizenshipflag':documentevidencingcitizenshipflag, +'reasonfornoevidence':reasonfornoevidence, +'nameofdocumentforcitizenshipevidence':nameofdocumentforcitizenshipevidence, +'modeofcollection':modeofcollection, +'contributionType':contributionType, + }, + ); + return response.toString(); + } } \ No newline at end of file diff --git a/lib/di/injection.dart b/lib/di/injection.dart index 09a249c..9a78c06 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -78,7 +78,7 @@ Dio _createDioClient() { final dio = Dio( BaseOptions( baseUrl: - 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com', //test + 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com', //test //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod //'https://kccbmbnk.net', //prod small connectTimeout: const Duration(seconds: 60), diff --git a/lib/features/account_opening/screens/account_opening_screen.dart b/lib/features/account_opening/screens/account_opening_screen.dart index 4fb0b4d..45a746f 100644 --- a/lib/features/account_opening/screens/account_opening_screen.dart +++ b/lib/features/account_opening/screens/account_opening_screen.dart @@ -16,7 +16,6 @@ class AccountOpeningScreen extends StatefulWidget { } class _AccountOpeningScreenState extends State { - @override Widget build(BuildContext context) { return Scaffold( @@ -41,8 +40,7 @@ class _AccountOpeningScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const FdScreen( - ), + builder: (context) => const FdScreen(), ), ); }, @@ -56,8 +54,7 @@ class _AccountOpeningScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const TermDepositScreen() - ), + builder: (context) => const TermDepositScreen()), ); }, ), @@ -70,7 +67,8 @@ class _AccountOpeningScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const RecurringDepositScreen() ), + builder: (context) => + const RecurringDepositScreen()), ); }, ), @@ -83,8 +81,7 @@ class _AccountOpeningScreenState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => const LoanScreen() - ), + builder: (context) => const LoanScreen()), ); }, ), @@ -136,8 +133,7 @@ class AccountOpeningCardTile extends StatelessWidget { ), elevation: 4, child: InkWell( - onTap: - disable ? null : onTap, + onTap: disable ? null : onTap, borderRadius: BorderRadius.circular(12.0), child: Padding( padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0), @@ -172,4 +168,4 @@ class AccountOpeningCardTile extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/account_opening/screens/fd_screen.dart b/lib/features/account_opening/screens/fd_screen.dart index 107ff1d..96aa5a4 100644 --- a/lib/features/account_opening/screens/fd_screen.dart +++ b/lib/features/account_opening/screens/fd_screen.dart @@ -72,10 +72,9 @@ class _FdScreenState extends State { TextFormField( controller: _amountController, decoration: const InputDecoration( - labelText: 'Enter Amount', - border: OutlineInputBorder(), - prefixText: '₹ ' - ), + labelText: 'Enter Amount', + border: OutlineInputBorder(), + prefixText: '₹ '), keyboardType: TextInputType.number, ), const SizedBox(height: 20), @@ -96,10 +95,8 @@ class _FdScreenState extends State { builder: (context) => const InterestRatesScreen()), ); }, - child: Text( - 'Interest Rates', - style: Theme.of(context).textTheme.titleSmall - ), + child: Text('Interest Rates', + style: Theme.of(context).textTheme.titleSmall), ), ], ), @@ -228,7 +225,8 @@ class _FdScreenState extends State { // TODO: Implement proceed logic }, style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15), + padding: + const EdgeInsets.symmetric(horizontal: 40, vertical: 15), ), child: const Text( 'Proceed', @@ -241,4 +239,4 @@ class _FdScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/account_opening/screens/interest_rates_screen.dart b/lib/features/account_opening/screens/interest_rates_screen.dart index e886578..069d288 100644 --- a/lib/features/account_opening/screens/interest_rates_screen.dart +++ b/lib/features/account_opening/screens/interest_rates_screen.dart @@ -14,4 +14,4 @@ class InterestRatesScreen extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/account_opening/screens/loan_screen.dart b/lib/features/account_opening/screens/loan_screen.dart index 6b47f53..41eb1e6 100644 --- a/lib/features/account_opening/screens/loan_screen.dart +++ b/lib/features/account_opening/screens/loan_screen.dart @@ -12,7 +12,7 @@ class LoanScreen extends StatelessWidget { title: const Text("Request Loan"), ), body: const Center( - child: Text("Loan Account"), + child: Text("Loan Account"), ), ); } diff --git a/lib/features/account_opening/screens/rd_screen.dart b/lib/features/account_opening/screens/rd_screen.dart index 4febb94..022de28 100644 --- a/lib/features/account_opening/screens/rd_screen.dart +++ b/lib/features/account_opening/screens/rd_screen.dart @@ -12,7 +12,7 @@ class RecurringDepositScreen extends StatelessWidget { title: const Text("Recurring Deposit"), ), body: const Center( - child: Text("Recurring Deposit"), + child: Text("Recurring Deposit"), ), ); } diff --git a/lib/features/account_opening/screens/td_screen.dart b/lib/features/account_opening/screens/td_screen.dart index 57a8b25..cd2f509 100644 --- a/lib/features/account_opening/screens/td_screen.dart +++ b/lib/features/account_opening/screens/td_screen.dart @@ -16,4 +16,4 @@ class TermDepositScreen extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/beneficiaries/screens/beneficiary_details_screen.dart b/lib/features/beneficiaries/screens/beneficiary_details_screen.dart index 0cf320c..d67783f 100644 --- a/lib/features/beneficiaries/screens/beneficiary_details_screen.dart +++ b/lib/features/beneficiaries/screens/beneficiary_details_screen.dart @@ -187,7 +187,8 @@ class _BeneficiaryDetailsScreenState extends State { CircleAvatar( radius: 24, backgroundColor: Colors.transparent, - child: getBankLogo(widget.beneficiary.bankName, context), + child: + getBankLogo(widget.beneficiary.bankName, context), ), const SizedBox(width: 16), Text( @@ -274,4 +275,3 @@ class _BeneficiaryDetailsScreenState extends State { ); } } - diff --git a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart index d29b727..50ffe95 100644 --- a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart +++ b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart @@ -149,7 +149,6 @@ class _ManageBeneficiariesScreen extends State { decoration: InputDecoration( hintText: AppLocalizations.of(context).searchByNameOrAccountHint, - prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), diff --git a/lib/features/cheque/screens/cheque_management_screen.dart b/lib/features/cheque/screens/cheque_management_screen.dart index ada04a2..0a334a2 100644 --- a/lib/features/cheque/screens/cheque_management_screen.dart +++ b/lib/features/cheque/screens/cheque_management_screen.dart @@ -93,7 +93,8 @@ class _ChequeManagementScreen extends State { ), Expanded( child: ChequeManagementCardTile( - icon: Symbols.check_circle, // Using check_circle for Positive Pay + icon: Symbols + .check_circle, // Using check_circle for Positive Pay label: AppLocalizations.of(context).positivePayTitle, onTap: () { Navigator.push( @@ -191,4 +192,4 @@ class ChequeManagementCardTile extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/cheque/screens/positive_pay_screen.dart b/lib/features/cheque/screens/positive_pay_screen.dart index 0f8472b..0eb3f3c 100644 --- a/lib/features/cheque/screens/positive_pay_screen.dart +++ b/lib/features/cheque/screens/positive_pay_screen.dart @@ -36,7 +36,7 @@ class _PositivePayScreenState extends State { @override void initState() { super.initState(); - _filteredUsers = widget.users + _filteredUsers = widget.users .where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType)) .toList(); // Pre-fill the account number if possible @@ -113,7 +113,7 @@ class _PositivePayScreenState extends State { super.dispose(); } -Future _showResponseDialog(String title, String message) async { + Future _showResponseDialog(String title, String message) async { return showDialog( context: context, barrierDismissible: false, // user must tap button! @@ -145,7 +145,8 @@ Future _showResponseDialog(String title, String message) async { return Scaffold( appBar: AppBar( title: Text( - AppLocalizations.of(context).positivePay, // Will be replaced by localization + AppLocalizations.of(context) + .positivePay, // Will be replaced by localization ), centerTitle: false, ), @@ -199,12 +200,13 @@ Future _showResponseDialog(String title, String message) async { final fromCheque = int.tryParse(_ciFromCheque ?? ''); final toCheque = int.tryParse(_ciToCheque ?? ''); if (chequeNumber == null) { - return AppLocalizations.of(context).invalidChequeNumberFormatError; + return AppLocalizations.of(context) + .invalidChequeNumberFormatError; } if (fromCheque != null && toCheque != null) { if (chequeNumber < fromCheque || chequeNumber > toCheque) { - return AppLocalizations.of(context).chequeNumberRangeError( - _ciFromCheque!, _ciToCheque!); + return AppLocalizations.of(context) + .chequeNumberRangeError(_ciFromCheque!, _ciToCheque!); } } return null; @@ -228,13 +230,15 @@ Future _showResponseDialog(String title, String message) async { ); if (pickedDate != null) { // Format the date as you wish - String formattedDate = "${pickedDate.year}-${pickedDate.month.toString().padLeft(2, '0')}-${pickedDate.day.toString().padLeft(2, '0')}"; + String formattedDate = + "${pickedDate.year}-${pickedDate.month.toString().padLeft(2, '0')}-${pickedDate.day.toString().padLeft(2, '0')}"; _chequeDateController.text = formattedDate; } }, - validator: (value) { + validator: (value) { if (value == null || value.isEmpty) { - return AppLocalizations.of(context).pleaseSelectChequeIssuedDate; + return AppLocalizations.of(context) + .pleaseSelectChequeIssuedDate; } return null; }, @@ -255,7 +259,8 @@ Future _showResponseDialog(String title, String message) async { border: const OutlineInputBorder(), prefixText: '₹ ', ), - keyboardType: const TextInputType.numberWithOptions(decimal: true), + keyboardType: + const TextInputType.numberWithOptions(decimal: true), validator: (value) { if (value == null || value.isEmpty) { return AppLocalizations.of(context).pleaseEnterAmount; @@ -277,34 +282,34 @@ Future _showResponseDialog(String title, String message) async { try { final response = await _chequeService.registerPPS( cheque_no: _chequeNumberController.text, - account_number: - _selectedAccount!.accountNo!, - issue_date: - _chequeDateController.text, + account_number: _selectedAccount!.accountNo!, + issue_date: _chequeDateController.text, amount: _amountController.text, payee_name: _payeeController.text, tpin: pin, ); if (!mounted) return; String responseString = response.toString(); - if(responseString == 'PPS Registered Successfully'){ + if (responseString == + 'PPS Registered Successfully') { _showResponseDialog('REGISTRATION SUCCESFUL', - 'Your Positive Pay Request has been registered succesfully'); + 'Your Positive Pay Request has been registered succesfully'); } - if(responseString.contains('Cheque already registered')){ + if (responseString + .contains('Cheque already registered')) { _showResponseDialog('ERROR', - 'Your Request for the selected cheque number has already been registered'); + 'Your Request for the selected cheque number has already been registered'); } - if(responseString.contains('INCORRECT_TPIN')){ + if (responseString.contains('INCORRECT_TPIN')) { _showResponseDialog('Invalid TPIN', - 'The TPIN you entered is incorrect. Please try again.'); + 'The TPIN you entered is incorrect. Please try again.'); } } on DioException catch (e) { try { final errorBodyString = e.toString().split('Exception: ')[1]; - final errorBody = jsonDecode(errorBodyString); - if (errorBody.containsKey('error') && + final errorBody = jsonDecode(errorBodyString); + if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') { _showResponseDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.'); diff --git a/lib/features/cheque/screens/revoke _stop_multiple_screen.dart b/lib/features/cheque/screens/revoke _stop_multiple_screen.dart index a70f45f..2618a6e 100644 --- a/lib/features/cheque/screens/revoke _stop_multiple_screen.dart +++ b/lib/features/cheque/screens/revoke _stop_multiple_screen.dart @@ -27,7 +27,8 @@ class RevokeStopMultipleChequesScreen extends StatefulWidget { _RevokeStopMultipleChequesScreenState(); } -class _RevokeStopMultipleChequesScreenState extends State { +class _RevokeStopMultipleChequesScreenState + extends State { final _formKey = GlobalKey(); final _stopFromChequeNoController = TextEditingController(); final _stopToChequeNoController = TextEditingController(); @@ -275,7 +276,8 @@ class _RevokeStopMultipleChequesScreenState extends State users; final int selectedIndex; - const RevokeStopChequeScreen( - { - super.key, - required this.users, - required this.selectedIndex, - }); + const RevokeStopChequeScreen({ + super.key, + required this.users, + required this.selectedIndex, + }); @override State createState() => _RevokeStopChequeScreenState(); @@ -199,8 +198,10 @@ class _RevokeStopChequeScreenState extends State { selectedAccount: _selectedAccount!, date: _stCheques.first.Date!, instrType: _stCheques.first.InstrType!, - fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!, - toCheque: _ciToCheque ?? _stCheques.first.toCheque!, + fromCheque: _ciFromCheque ?? + _stCheques.first.fromCheque!, + toCheque: + _ciToCheque ?? _stCheques.first.toCheque!, ), ), ); @@ -216,7 +217,8 @@ class _RevokeStopChequeScreenState extends State { padding: const EdgeInsets.all(16.0), child: Center( child: Text( - AppLocalizations.of(context).revokeSingleStopTitle, + AppLocalizations.of(context) + .revokeSingleStopTitle, textAlign: TextAlign.center, style: TextStyle( fontSize: 16, @@ -248,8 +250,10 @@ class _RevokeStopChequeScreenState extends State { selectedAccount: _selectedAccount!, date: _stCheques.first.Date!, instrType: _stCheques.first.InstrType!, - fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!, - toCheque: _ciToCheque ?? _stCheques.first.toCheque!, + fromCheque: _ciFromCheque ?? + _stCheques.first.fromCheque!, + toCheque: + _ciToCheque ?? _stCheques.first.toCheque!, ), ), ); @@ -266,7 +270,7 @@ class _RevokeStopChequeScreenState extends State { padding: const EdgeInsets.all(16.0), child: Center( child: Text( - AppLocalizations.of(context).revokeMultipleStops, + AppLocalizations.of(context).revokeMultipleStops, textAlign: TextAlign.center, style: TextStyle( fontSize: 16, diff --git a/lib/features/cheque/screens/revoke_stop_single_screen.dart b/lib/features/cheque/screens/revoke_stop_single_screen.dart index df3c678..31ddc63 100644 --- a/lib/features/cheque/screens/revoke_stop_single_screen.dart +++ b/lib/features/cheque/screens/revoke_stop_single_screen.dart @@ -23,10 +23,12 @@ class RevokeStopSingleChequeScreen extends StatefulWidget { required this.toCheque}); @override - State createState() => _RevokeStopSingleChequeScreenState(); + State createState() => + _RevokeStopSingleChequeScreenState(); } -class _RevokeStopSingleChequeScreenState extends State { +class _RevokeStopSingleChequeScreenState + extends State { final _formKey = GlobalKey(); final _stopFromChequeNoController = TextEditingController(); final _stopIssueDateController = TextEditingController(); @@ -89,7 +91,7 @@ class _RevokeStopSingleChequeScreenState extends State { ); if (!mounted) return; final decodedResponse = jsonDecode(response); - String responseString = response.toString(); // used as the case only for incorrect TPIN + String responseString = response + .toString(); // used as the case only for incorrect TPIN final status = decodedResponse['status']; final message = decodedResponse['message']; final code = decodedResponse['code']; if (status == 'SUCCESS') { _showResponseDialog('Success', message); - } if (status == 'ERROR') { + } + if (status == 'ERROR') { String errMessage = "error"; - if(code == '0429') { - errMessage = 'The selected Cheque is already stopped'; - } else if(code == '0748') { - errMessage = 'The selected Cheque is already presented'; + if (code == '0429') { + errMessage = + 'The selected Cheque is already stopped'; + } else if (code == '0748') { + errMessage = + 'The selected Cheque is already presented'; } _showResponseDialog('Error', errMessage); } - if(responseString.contains('INCORRECT_TPIN')){ + if (responseString.contains('INCORRECT_TPIN')) { _showResponseDialog('Invalid TPIN', - 'The TPIN you entered is incorrect. Please try again.'); + 'The TPIN you entered is incorrect. Please try again.'); } } on Exception catch (e) { try { diff --git a/lib/features/cheque/screens/stop_single_cheque_screen.dart b/lib/features/cheque/screens/stop_single_cheque_screen.dart index 559a53c..24453ca 100644 --- a/lib/features/cheque/screens/stop_single_cheque_screen.dart +++ b/lib/features/cheque/screens/stop_single_cheque_screen.dart @@ -278,31 +278,35 @@ class _StopSingleChequeScreenState extends State { ); if (!mounted) return; final decodedResponse = jsonDecode(response); - String responseString = response.toString(); // used as the case only for incorrect TPIN + String responseString = response + .toString(); // used as the case only for incorrect TPIN final status = decodedResponse['status']; final message = decodedResponse['message']; final code = decodedResponse['code']; if (status == 'SUCCESS') { _showResponseDialog('Success', message); - } if (status == 'ERROR') { + } + if (status == 'ERROR') { String errMessage = "error"; - if(code == '0429') { - errMessage = 'The selected Cheque is already stopped'; - } else if(code == '0748') { - errMessage = 'The selected Cheque is already presented'; + if (code == '0429') { + errMessage = + 'The selected Cheque is already stopped'; + } else if (code == '0748') { + errMessage = + 'The selected Cheque is already presented'; } _showResponseDialog('Error', errMessage); } - if(responseString.contains('INCORRECT_TPIN')){ + if (responseString.contains('INCORRECT_TPIN')) { _showResponseDialog('Invalid TPIN', - 'The TPIN you entered is incorrect. Please try again.'); + 'The TPIN you entered is incorrect. Please try again.'); } } on DioException catch (e) { try { final errorBodyString = e.toString().split('Exception: ')[1]; - final errorBody = jsonDecode(errorBodyString); - if (errorBody.containsKey('error') && + final errorBody = jsonDecode(errorBodyString); + if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') { _showResponseDialog('Invalid TPIN', 'The TPIN you entered is incorrect. Please try again.'); diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 29fc9df..99b0d64 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -636,18 +636,20 @@ class _DashboardScreenState extends State ManageBeneficiariesScreen( customerName: currAccount.name!))); }, disable: false), - _buildQuickLink(Symbols.family_group, - AppLocalizations.of(context).governmentSchemes, () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => GovSchemeScreen( - users: users, - selectedIndex: selectedAccountIndex, - ))); - }, - disable: isPaymentDisabled, - ), + _buildQuickLink( + Symbols.family_group, + AppLocalizations.of(context).governmentSchemes, + () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GovSchemeScreen( + users: users, + selectedIndex: selectedAccountIndex, + ))); + }, + disable: isPaymentDisabled, + ), _buildQuickLink( Symbols.checkbook, AppLocalizations.of(context).chequeManagement, diff --git a/lib/features/service/screens/service_screen.dart b/lib/features/service/screens/service_screen.dart index 19c0a97..72a5ffb 100644 --- a/lib/features/service/screens/service_screen.dart +++ b/lib/features/service/screens/service_screen.dart @@ -78,7 +78,7 @@ class _ServiceScreen extends State { // label: "Account Opening", // onTap: () { // Navigator.push( - // context, + // context, // MaterialPageRoute( // builder: (context) => const AccountOpeningScreen())); // }, @@ -91,7 +91,7 @@ class _ServiceScreen extends State { // label: AppLocalizations.of(context).cardManagement, // onTap: () { // Navigator.push( - // context, + // context, // MaterialPageRoute( // builder: (context) => const CardManagementScreen())); // }, @@ -110,8 +110,8 @@ class _ServiceScreen extends State { }, disabled: false, ), - ), - // No Spacer() needed here as Expanded children will fill space + ), + // No Spacer() needed here as Expanded children will fill space ], ), ), @@ -162,33 +162,34 @@ class ServiceManagementTile extends StatelessWidget { onTap: disabled ? null : onTap, // Disable InkWell if the tile is disabled borderRadius: BorderRadius.circular(12.0), - child: Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - icon, - size: 48, // Make icon larger - color: - disabled ? theme.disabledColor : theme.colorScheme.primary, + child: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 48, // Make icon larger + color: disabled + ? theme.disabledColor + : theme.colorScheme.primary, + ), + const SizedBox(height: 12), + Text( + label, + textAlign: TextAlign.center, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + color: disabled + ? theme.disabledColor + : theme.colorScheme.onSurface, ), - const SizedBox(height: 12), - Text( - label, - textAlign: TextAlign.center, - style: theme.textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - color: disabled - ? theme.disabledColor - : theme.colorScheme.onSurface, - ), - ), - ], - ), + ), + ], ), ), ), + ), ); } } diff --git a/lib/features/yojna/screens/apy_register_screen.dart b/lib/features/yojna/screens/apy_register_screen.dart index 9b67b74..74d6369 100644 --- a/lib/features/yojna/screens/apy_register_screen.dart +++ b/lib/features/yojna/screens/apy_register_screen.dart @@ -1,4 +1,8 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:kmobile/api/services/yojna_service.dart'; +import 'package:kmobile/di/injection.dart'; import 'package:kmobile/l10n/app_localizations.dart'; class APYRegisterScreen extends StatefulWidget { @@ -12,42 +16,73 @@ class APYRegisterScreen extends StatefulWidget { class _APYRegisterScreenState extends State { final _formKey = GlobalKey(); - // Controllers - late final _titleController = TextEditingController(text: widget.initialData?['customertitle']?.toString()); - late final _firstNameController = TextEditingController(text: widget.initialData?['customerfirstname']?.toString()); - late final _middleNameController = TextEditingController(text: widget.initialData?['customermiddlename']?.toString()); - late final _lastNameController = TextEditingController(text: widget.initialData?['customerlastname']?.toString()); - late final _customerNoController = TextEditingController(text: widget.initialData?['customerno']?.toString()); - late final _accountNoController = TextEditingController(text: widget.initialData?['accountno']?.toString()); - late final _balanceController = TextEditingController(text: widget.initialData?['availablebalance']?.toString()); - late final _dobController = TextEditingController(text: widget.initialData?['customerdob']?.toString()); - late final _genderController = TextEditingController(text: widget.initialData?['gender']?.toString()); - late final _marriedController = TextEditingController(text: widget.initialData?['married']?.toString()); - late final _mobileController = TextEditingController(text: widget.initialData?['mobilenumber']?.toString()); - late final _emailController = TextEditingController(text: widget.initialData?['emailid']?.toString()); - late final _aadhaarController = TextEditingController(text: widget.initialData?['aadharno']?.toString()); - late final _pincodeController = TextEditingController(text: widget.initialData?['pincode']?.toString()); + // Helper to format initial date string (DDMMYYYY -> DD/MM/YYYY) + String _formatInitialDate(dynamic date) { + if (date == null) return ''; + String dateStr = date.toString(); + if (dateStr.length == 8) { + return "${dateStr.substring(0, 2)}/${dateStr.substring(2, 4)}/${dateStr.substring(4)}"; + } + return dateStr; + } - late final _pensionAmountController = TextEditingController(text: widget.initialData?['pensionamtoptedfor']?.toString() ?? '1000'); - late final _ageOfJoiningController = TextEditingController(text: widget.initialData?['ageofjoining']?.toString()); - late final _spouseNameController = TextEditingController(text: widget.initialData?['nameofspouse']?.toString()); - late final _incomeTaxPayerController = TextEditingController(text: widget.initialData?['whetherincometaxpayer']?.toString()); - late final _otherSchemeController = TextEditingController(text: widget.initialData?['beneficaryofothersociatysecurityschemes']?.toString()); - late final _collectionChannelController = TextEditingController(text: widget.initialData?['collectionchannel']?.toString() ?? '1'); - late final _contributionTypeController = TextEditingController(text: widget.initialData?['contributionType']?.toString() ?? 'C'); - late final _debitDateController = TextEditingController(text: widget.initialData?['subsequentContributionDebitDate']?.toString()); + // Controllers initialized strictly from initialData where available, otherwise empty. + late final _titleController = TextEditingController( + text: widget.initialData?['customertitle']?.toString()); + late final _firstNameController = TextEditingController( + text: widget.initialData?['customerfirstname']?.toString()); + late final _middleNameController = TextEditingController( + text: widget.initialData?['customermiddlename']?.toString()); + late final _lastNameController = TextEditingController( + text: widget.initialData?['customerlastname']?.toString()); + late final _customerNoController = TextEditingController( + text: widget.initialData?['customerno']?.toString()); + late final _accountNoController = TextEditingController( + text: widget.initialData?['accountno']?.toString()); + late final _balanceController = TextEditingController( + text: widget.initialData?['availablebalance']?.toString()); + late final _dobController = TextEditingController( + text: _formatInitialDate(widget.initialData?['customerdob'])); + late final _genderController = TextEditingController( + text: widget.initialData?['gender']?.toString()); + late final _aadhaarController = TextEditingController( + text: widget.initialData?['aadharno']?.toString()); + late final _ageOfJoiningController = TextEditingController( + text: widget.initialData?['ageofjoining']?.toString()); + late final _emailController = TextEditingController( + text: widget.initialData?['emailid']?.toString()); + late final _modeOfCollectionController = TextEditingController( + text: widget.initialData?['modeofcollection']?.toString()); - late final _nomineeNameController = TextEditingController(text: widget.initialData?['nomineename']?.toString()); - late final _nomineeRelationController = TextEditingController(text: widget.initialData?['relationwithsubscriber']?.toString()); - late final _nomineeMinorController = TextEditingController(text: widget.initialData?['nomineeminor']?.toString() ?? 'N'); + // Fields that must be filled by the user (no defaults) + late final _marriedController = TextEditingController(); + late final _mobileController = TextEditingController(); + late final _pincodeController = TextEditingController(); + late final _pensionAmountController = TextEditingController(); + late final _spouseNameController = TextEditingController(); + late final _incomeTaxPayerController = TextEditingController(); + late final _otherSchemeController = TextEditingController(); + late final _collectionChannelController = TextEditingController(); + late final _contributionTypeController = TextEditingController(); + late final _debitDateController = TextEditingController(); + late final _nomineeNameController = TextEditingController(); + late final _nomineeRelationController = TextEditingController(); + late final _nomineeMinorController = TextEditingController(); late final _nomineeDobController = TextEditingController(); late final _guardianNameController = TextEditingController(); + late final _fatcaController = TextEditingController(); + late final _birthCountryController = TextEditingController(); + late final _citizenshipCountryController = TextEditingController(); + late final _taxResidenceCountryController = TextEditingController(); + late final _usPersonController = TextEditingController(); - late final _fatcaController = TextEditingController(text: widget.initialData?['fatcacrsapplicable']?.toString()); - late final _birthCountryController = TextEditingController(text: widget.initialData?['countryofbirth']?.toString()); - late final _citizenshipCountryController = TextEditingController(text: widget.initialData?['countryofcitizenship']?.toString()); - late final _taxResidenceCountryController = TextEditingController(text: widget.initialData?['countryofresidencefortaxpurpose']?.toString()); - late final _usPersonController = TextEditingController(text: widget.initialData?['uspersonflag']?.toString()); + late final _secondNomineeNameController = TextEditingController(); + late final _secondNomineeMinorController = TextEditingController(); + late final _secondNomineeRelationController = TextEditingController(); + late final _fatcaCountController = TextEditingController(); + late final _docCitizenshipFlagController = TextEditingController(); + late final _reasonNoEvidenceController = TextEditingController(); + late final _docNameEvidenceController = TextEditingController(); final Map _yesNoOptions = { 'Y': 'Yes', @@ -60,6 +95,12 @@ class _APYRegisterScreenState extends State { '03': 'Miss', }; + final Map _genderOptions = { + 'M': 'Male', + 'F': 'Female', + 'O': 'Other', + }; + final Map _pensionOptions = { '1000': '₹1000', '2000': '₹2000', @@ -143,20 +184,121 @@ class _APYRegisterScreenState extends State { _citizenshipCountryController.dispose(); _taxResidenceCountryController.dispose(); _usPersonController.dispose(); + _secondNomineeNameController.dispose(); + _secondNomineeMinorController.dispose(); + _secondNomineeRelationController.dispose(); + _fatcaCountController.dispose(); + _docCitizenshipFlagController.dispose(); + _reasonNoEvidenceController.dispose(); + _docNameEvidenceController.dispose(); + _modeOfCollectionController.dispose(); super.dispose(); } - bool _isFetched(String key) { - return widget.initialData != null && - widget.initialData!.containsKey(key) && - widget.initialData![key]?.toString().isNotEmpty == true; + Future _selectDate(BuildContext context, TextEditingController controller) async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(1900), + lastDate: DateTime(2100), + ); + if (picked != null) { + setState(() { + // Display format: DD/MM/YYYY + controller.text = DateFormat('dd/MM/yyyy').format(picked); + }); + } } - void _handleRegister() { + void _handleRegister() async { if (_formKey.currentState!.validate()) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Registration logic to be implemented')), + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const Center(child: CircularProgressIndicator()), ); + + try { + final yojnaService = getIt(); + final response = await yojnaService.registerAPY( + accountno: _accountNoController.text, + customerfirstname: _firstNameController.text, + customermiddlename: _middleNameController.text, + customerlastname: _lastNameController.text, + availablebalance: _balanceController.text, + // Remove slashes for API (DD/MM/YYYY -> DDMMYYYY) + customerdob: _dobController.text.replaceAll('/', ''), + emailid: _emailController.text, + gender: _genderController.text, + married: _marriedController.text, + nomineename: _nomineeNameController.text, + relationwithsubscriber: _nomineeRelationController.text, + mobilenumber: _mobileController.text, + nomineeminor: _nomineeMinorController.text, + customerno: _customerNoController.text, + beneficaryofothersociatysecurityschemes: _otherSchemeController.text, + whetherincometaxpayer: _incomeTaxPayerController.text, + customertitle: _titleController.text, + aadharno: _aadhaarController.text, + nameofspouse: _spouseNameController.text, + ageofjoining: _ageOfJoiningController.text, + pensionamtoptedfor: _pensionAmountController.text, + montlycontributioncalculate: _calculatedContribution, + collectionchannel: _collectionChannelController.text, + // Remove slashes for API + subsequentContributionDebitDate: _debitDateController.text.replaceAll('/', ''), + secondnomineeminor: _secondNomineeMinorController.text, + secondnomineename: _secondNomineeNameController.text, + secondrelationshipwithsubscriber: _secondNomineeRelationController.text, + pincode: _pincodeController.text, + fatcacrsapplicable: _fatcaController.text, + countryofbirth: _birthCountryController.text, + countryofcitizenship: _citizenshipCountryController.text, + countryofresidencefortaxpurpose: _taxResidenceCountryController.text, + uspersonflag: _usPersonController.text, + fatcadeclarationcount: _fatcaCountController.text, + documentevidencingcitizenshipflag: _docCitizenshipFlagController.text, + reasonfornoevidence: _reasonNoEvidenceController.text, + nameofdocumentforcitizenshipevidence: _docNameEvidenceController.text, + modeofcollection: _modeOfCollectionController.text, + contributionType: _contributionTypeController.text, + ); + + if (!mounted) return; + Navigator.pop(context); // Close loading dialog + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Registration Result'), + content: SingleChildScrollView( + child: Text(response.toString()), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + } catch (e) { + if (!mounted) return; + Navigator.pop(context); // Close loading dialog + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Error'), + content: Text('Failed to register: $e'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + } } } @@ -174,7 +316,7 @@ class _APYRegisterScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - // Tile 1: Customer & APY Details + // Tile 1: Customer Details Card( elevation: 2, child: Padding( @@ -182,53 +324,104 @@ class _APYRegisterScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(l10n.details, + Text(l10n.personaldetails, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), - _buildDropdownField(_titleController, l10n.customerTitle, - _titleOptions, - readOnly: _isFetched('customertitle')), + _buildDropdownField( + _titleController, l10n.customerTitle, _titleOptions), _buildTextField( - _firstNameController, l10n.customerFirstName, - readOnly: _isFetched('customerfirstname')), + _firstNameController, l10n.customerFirstName), _buildTextField( - _middleNameController, l10n.customerMiddleName, - readOnly: _isFetched('customermiddlename')), + _middleNameController, l10n.customerMiddleName), _buildTextField( - _lastNameController, l10n.customerLastName, - readOnly: _isFetched('customerlastname')), + _lastNameController, l10n.customerLastName), + _buildTextField(_customerNoController, l10n.customerNo), _buildTextField(_accountNoController, l10n.accountNumber, - keyboardType: TextInputType.number, - readOnly: _isFetched('accountno')), - _buildTextField( - _balanceController, l10n.availableBalance, - keyboardType: TextInputType.number, - readOnly: _isFetched('availablebalance')), + keyboardType: TextInputType.number), + _buildTextField(_balanceController, l10n.availableBalance, + keyboardType: TextInputType.number), _buildTextField(_dobController, l10n.customerDobFormat, - mandatory: true, readOnly: _isFetched('customerdob')), + mandatory: true, onTap: () => _selectDate(context, _dobController)), + _buildDropdownField( + _genderController, l10n.gender, _genderOptions), + _buildTextField(_mobileController, l10n.mobileNumber, + keyboardType: TextInputType.phone), _buildTextField(_emailController, l10n.emailId, - keyboardType: TextInputType.emailAddress, - readOnly: _isFetched('emailid')), + keyboardType: TextInputType.emailAddress), + _buildTextField(_aadhaarController, l10n.aadhaarNo, + keyboardType: TextInputType.number), + _buildTextField(_pincodeController, l10n.pincode, + keyboardType: TextInputType.number), _buildDropdownField( _marriedController, l10n.marriedYesNo, _yesNoOptions, mandatory: true), + ], + ), + ), + ), + const SizedBox(height: 16), + // Tile 2: Nominee Details + Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(l10n.nomineeDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 16), + Text("Nominee 1", style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary)), + const SizedBox(height: 8), _buildTextField(_nomineeNameController, l10n.nomineeName, mandatory: true), + _buildTextField(_nomineeRelationController, l10n.relationWithSubscriber, + mandatory: true), _buildDropdownField(_nomineeMinorController, - l10n.nomineeMinor, _yesNoOptions, - mandatory: true, onChanged: (val) { + l10n.nomineeMinor, _yesNoOptions, mandatory: true, + onChanged: (val) { setState(() { - _nomineeMinorController.text = val ?? 'N'; + _nomineeMinorController.text = val ?? ''; }); }), if (_nomineeMinorController.text == 'Y') ...[ _buildTextField(_nomineeDobController, l10n.nomineeDob, - mandatory: true), + mandatory: true, onTap: () => _selectDate(context, _nomineeDobController)), _buildTextField( _guardianNameController, l10n.guardianName, mandatory: true), ], + const Divider(height: 32), + Text("Nominee 2", style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary)), + const SizedBox(height: 8), + _buildTextField(_secondNomineeNameController, l10n.secondNomineeName), + _buildTextField(_secondNomineeRelationController, l10n.secondNomineeRelationship), + _buildDropdownField(_secondNomineeMinorController, + l10n.secondNomineeMinor, _yesNoOptions, + onChanged: (val) { + setState(() { + _secondNomineeMinorController.text = val ?? ''; + }); + }), + ], + ), + ), + ), + const SizedBox(height: 16), + // Tile 3: Scheme & APY Details + Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(l10n.schemeDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 16), _buildDropdownField(_otherSchemeController, l10n.isBeneficiaryOtherScheme, _yesNoOptions, mandatory: true), @@ -242,40 +435,78 @@ class _APYRegisterScreenState extends State { _buildDropdownField(_collectionChannelController, l10n.collectionChannel, _collectionChannelOptions, mandatory: true), - _buildDropdownField( - _fatcaController, l10n.fatcaApplicable, _yesNoOptions), + _buildTextField(_modeOfCollectionController, l10n.modeOfCollection), + ], + ), + ), + ), + const SizedBox(height: 16), + // Tile 4: FATCA / CRS Details (KYC Details) + Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(l10n.kycdetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 16), + _buildDropdownField(_fatcaController, + l10n.fatcaApplicable, _yesNoOptions), _buildTextField( _birthCountryController, l10n.countryOfBirth), - _buildTextField( - _citizenshipCountryController, l10n.countryOfCitizenship), + _buildTextField(_citizenshipCountryController, + l10n.countryOfCitizenship), _buildTextField(_taxResidenceCountryController, l10n.countryOfTaxResidence), - _buildDropdownField( - _usPersonController, l10n.usPersonFlag, _yesNoOptions), - const Divider(height: 32), + _buildDropdownField(_usPersonController, + l10n.usPersonFlag, _yesNoOptions), + _buildTextField(_fatcaCountController, "FATCA Declaration Count"), + _buildTextField(_docCitizenshipFlagController, "Doc Evidencing Citizenship Flag"), + _buildTextField(_reasonNoEvidenceController, "Reason for No Evidence"), + _buildTextField(_docNameEvidenceController, "Doc Name for Citizenship Evidence"), + ], + ), + ), + ), + const SizedBox(height: 16), + // Tile 5: Pension & Contribution Settings + Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(l10n.contributionAmount, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), + const SizedBox(height: 16), _buildDropdownField(_pensionAmountController, - l10n.pensionAmount, _pensionOptions, - mandatory: true, onChanged: (val) { + l10n.pensionAmount, _pensionOptions, mandatory: true, + onChanged: (val) { setState(() { - _pensionAmountController.text = val ?? '1000'; + _pensionAmountController.text = val ?? ''; }); }), _buildDropdownField(_contributionTypeController, l10n.periodicity, _getPeriodicityOptions(l10n), mandatory: true, onChanged: (val) { setState(() { - _contributionTypeController.text = val ?? 'C'; + _contributionTypeController.text = val ?? ''; }); }), _buildTextField( _debitDateController, l10n.subsequentDebitDate, - mandatory: true), + mandatory: true, onTap: () => _selectDate(context, _debitDateController)), ], ), ), ), const SizedBox(height: 16), - // Tile 2: Contribution Amount + // Tile 6: Contribution Amount Summary Card( elevation: 2, color: Theme.of(context).colorScheme.secondaryContainer, @@ -306,8 +537,10 @@ class _APYRegisterScreenState extends State { ElevatedButton( onPressed: _handleRegister, style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.primaryContainer, - foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer, + backgroundColor: + Theme.of(context).colorScheme.primaryContainer, + foregroundColor: + Theme.of(context).colorScheme.onPrimaryContainer, padding: const EdgeInsets.symmetric(vertical: 16), elevation: 4, shape: RoundedRectangleBorder( @@ -316,7 +549,8 @@ class _APYRegisterScreenState extends State { ), child: Text( l10n.register, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 32), @@ -327,9 +561,11 @@ class _APYRegisterScreenState extends State { ); } - Widget _buildDropdownField( - TextEditingController controller, String label, Map options, - {bool readOnly = false, bool mandatory = false, void Function(String?)? onChanged}) { + 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; @@ -337,15 +573,18 @@ class _APYRegisterScreenState extends State { padding: const EdgeInsets.only(bottom: 16.0), child: DropdownButtonFormField( value: currentValue, - onChanged: readOnly ? null : (newValue) { - if (onChanged != null) { - onChanged(newValue); - } else { - setState(() { - controller.text = newValue ?? ''; - }); - } - }, + onChanged: readOnly + ? null + : (newValue) { + if (newValue != null) { + setState(() { + controller.text = newValue; + }); + } + if (onChanged != null) { + onChanged(newValue); + } + }, decoration: InputDecoration( labelText: mandatory ? '$label *' : label, border: const OutlineInputBorder(), @@ -371,15 +610,18 @@ class _APYRegisterScreenState extends State { Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false, - bool mandatory = false}) { + bool mandatory = false, + VoidCallback? onTap}) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: TextFormField( controller: controller, - readOnly: readOnly, + readOnly: readOnly || onTap != null, + onTap: 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), ), diff --git a/lib/features/yojna/screens/apy_screen.dart b/lib/features/yojna/screens/apy_screen.dart index d314b46..b31c53f 100644 --- a/lib/features/yojna/screens/apy_screen.dart +++ b/lib/features/yojna/screens/apy_screen.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:kmobile/api/services/yojna_service.dart'; import 'package:kmobile/data/models/user.dart'; +import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/yojna/screens/apy_register_screen.dart'; import 'package:kmobile/l10n/app_localizations.dart'; @@ -20,6 +22,7 @@ class _APYScreenState extends State { User? _selectedAccount; List _filteredUsers = []; final _formKey = GlobalKey(); + bool _isLoading = false; @override void initState() { @@ -27,7 +30,7 @@ class _APYScreenState extends State { _filteredUsers = widget.users .where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType)) .toList(); - + // Pre-fill the account number if possible if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) { if (_filteredUsers.isNotEmpty) { @@ -111,58 +114,51 @@ class _APYScreenState extends State { ), const SizedBox(height: 24), ElevatedButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - final mockData = { - "accountno": _selectedAccount?.accountNo ?? "50069506061", - "customerfirstname": "TAMANA", - "customermiddlename": "", - "customerlastname": "", - "availablebalance": "634000", - "customerdob": "06061998", - "emailid": "", - "gender": "F", - "married": "Y", - "nomineename": "shubham Kada", - "relationwithsubscriber": "S", - "mobilenumber": "", - "nomineeminor": "N", - "customerno": "30028309887", - "beneficaryofothersociatysecurityschemes": "N", - "whetherincometaxpayer": "N", - "customertitle": "02", - "aadharno": "", - "nameofspouse": "shubham kada", - "ageofjoining": "27", - "pensionamtoptedfor": "1000", - "montlycontributioncalculate": "90", - "collectionchannel": "1", - "subsequentContributionDebitDate": "02012026", - "secondnomineeminor": "N", - "secondnomineename": "shubham kad", - "secondrelationshipwithsubscriber": "", - "pincode": "176215", - "fatcacrsapplicable": "N", - "countryofbirth": "India", - "countryofcitizenship": "India", - "countryofresidencefortaxpurpose": "India", - "uspersonflag": "N", - "fatcadeclarationcount": "", - "documentevidencingcitizenshipflag": "", - "reasonfornoevidence": "", - "nameofdocumentforcitizenshipevidence": "", - "modeofcollection": "Transfer Voucher", - "contributionType": "C" - }; + onPressed: _isLoading + ? null + : () async { + if (_formKey.currentState!.validate()) { + setState(() { + _isLoading = true; + }); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => APYRegisterScreen(initialData: mockData), - ), - ); - } - }, + try { + final response = await getIt() + .fetchpapydetails( + accountno: _selectedAccount!.accountNo ?? ''); + + if (mounted) { + if (response != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => APYRegisterScreen( + initialData: response), + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + "Failed to fetch details. Please try again.")), + ); + } + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Error: ${e.toString()}")), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + }, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primaryContainer, @@ -174,11 +170,19 @@ class _APYScreenState extends State { borderRadius: BorderRadius.circular(8), ), ), - child: Text( - l10n.proceedButton, - style: const TextStyle( - fontSize: 16, fontWeight: FontWeight.bold), - ), + child: _isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + : Text( + l10n.proceedButton, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), ), ], ), @@ -187,3 +191,4 @@ class _APYScreenState extends State { ); } } + diff --git a/lib/features/yojna/screens/gov_scheme_screen.dart b/lib/features/yojna/screens/gov_scheme_screen.dart index 30340f6..aa0e22a 100644 --- a/lib/features/yojna/screens/gov_scheme_screen.dart +++ b/lib/features/yojna/screens/gov_scheme_screen.dart @@ -64,7 +64,7 @@ class _GovSchemeScreenState extends State { selectedIndex: widget.selectedIndex, ), ), - );// Action for APY will be added later + ); // Action for APY will be added later }, ), ), diff --git a/lib/features/yojna/screens/pm_main_screen.dart b/lib/features/yojna/screens/pm_main_screen.dart index 3f5c146..fe76790 100644 --- a/lib/features/yojna/screens/pm_main_screen.dart +++ b/lib/features/yojna/screens/pm_main_screen.dart @@ -27,9 +27,9 @@ class _PMMainScreenState extends State { String? _selectedScheme; List _getSchemes(AppLocalizations l10n) => [ - l10n.pmjjbyFull, - l10n.pmsbyFull, - ]; + l10n.pmjjbyFull, + l10n.pmsbyFull, + ]; @override void initState() { @@ -76,7 +76,8 @@ class _PMMainScreenState extends State { return; } - final String schemeCode = (_selectedScheme == l10n.pmjjbyFull) ? '02' : '01'; + final String schemeCode = + (_selectedScheme == l10n.pmjjbyFull) ? '02' : '01'; // Show loading ScaffoldMessenger.of(context).showSnackBar( @@ -103,7 +104,9 @@ class _PMMainScreenState extends State { Map? data; if (response is Map) { data = response; - } else if (response is List && response.isNotEmpty && response[0] is Map) { + } else if (response is List && + response.isNotEmpty && + response[0] is Map) { data = response[0] as Map; } @@ -169,15 +172,15 @@ class _PMMainScreenState extends State { Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final schemes = _getSchemes(l10n); - + // Ensure _selectedScheme is valid if it was set in a different language if (_selectedScheme != null && !schemes.contains(_selectedScheme)) { - // Try to find the corresponding scheme in the new language - // This is a bit tricky, but since we only have two: - // If it doesn't match, it might be from the other language. - // For simplicity, we can just reset it or try to guess. - // Better to use non-localized values for the state, but let's just reset for now if it doesn't match - _selectedScheme = null; + // Try to find the corresponding scheme in the new language + // This is a bit tricky, but since we only have two: + // If it doesn't match, it might be from the other language. + // For simplicity, we can just reset it or try to guess. + // Better to use non-localized values for the state, but let's just reset for now if it doesn't match + _selectedScheme = null; } return Scaffold( @@ -243,23 +246,23 @@ class _PMMainScreenState extends State { decoration: InputDecoration( labelText: l10n.selectScheme, border: const OutlineInputBorder(), - contentPadding: - const EdgeInsets.symmetric(vertical: 12, horizontal: 12), + contentPadding: const EdgeInsets.symmetric( + vertical: 12, horizontal: 12), ), - selectedItemBuilder: (BuildContext context) { - return schemes.map((String scheme) { - return Container( - alignment: Alignment.centerLeft, - child: Text( - scheme, - style: const TextStyle(fontSize: 14), - softWrap: true, - maxLines: 2, - overflow: TextOverflow.visible, - ), - ); - }).toList(); - }, + selectedItemBuilder: (BuildContext context) { + return schemes.map((String scheme) { + return Container( + alignment: Alignment.centerLeft, + child: Text( + scheme, + style: const TextStyle(fontSize: 14), + softWrap: true, + maxLines: 2, + overflow: TextOverflow.visible, + ), + ); + }).toList(); + }, items: schemes.map((String scheme) { return DropdownMenuItem( value: scheme, @@ -268,7 +271,6 @@ class _PMMainScreenState extends State { child: Text( scheme, style: const TextStyle(fontSize: 15), - softWrap: true, ), ), @@ -336,4 +338,3 @@ class _PMMainScreenState extends State { ); } } - diff --git a/lib/features/yojna/screens/pmjjby_enquiry_screen.dart b/lib/features/yojna/screens/pmjjby_enquiry_screen.dart index 0f54809..4af2dfb 100644 --- a/lib/features/yojna/screens/pmjjby_enquiry_screen.dart +++ b/lib/features/yojna/screens/pmjjby_enquiry_screen.dart @@ -119,7 +119,8 @@ class _PMJJBYEnquiryScreenState extends State { labelText: l10n.selectFinancialYear, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.calendar_today), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), ), items: _financialYears.map((String year) { return DropdownMenuItem( @@ -153,7 +154,9 @@ class _PMJJBYEnquiryScreenState extends State { padding: const EdgeInsets.all(16.0), child: Text( _errorMessage!, - style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold), + style: TextStyle( + color: Colors.red.shade700, + fontWeight: FontWeight.bold), //textAlign: Center, ), ), @@ -177,13 +180,20 @@ class _PMJJBYEnquiryScreenState extends State { ), ), const Divider(), - _buildDetailRow(l10n.customerName, _enquiryData!['customername']), - _buildDetailRow(l10n.policyNumber, _enquiryData!['policynumber']), - _buildDetailRow(l10n.accountNumber, _enquiryData!['accountno']), - _buildDetailRow(l10n.premiumAmount, _enquiryData!['preimiumamount']), - _buildDetailRow(l10n.nomineeName, _enquiryData!['nomineename']), - _buildDetailRow(l10n.date, _enquiryData!['transactiondate']), - _buildDetailRow(l10n.journalNo, _enquiryData!['journalno']), + _buildDetailRow( + l10n.customerName, _enquiryData!['customername']), + _buildDetailRow( + l10n.policyNumber, _enquiryData!['policynumber']), + _buildDetailRow( + l10n.accountNumber, _enquiryData!['accountno']), + _buildDetailRow( + l10n.premiumAmount, _enquiryData!['preimiumamount']), + _buildDetailRow( + l10n.nomineeName, _enquiryData!['nomineename']), + _buildDetailRow( + l10n.date, _enquiryData!['transactiondate']), + _buildDetailRow( + l10n.journalNo, _enquiryData!['journalno']), ], ), ), @@ -202,7 +212,8 @@ class _PMJJBYEnquiryScreenState extends State { children: [ Text( label, - style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey), + style: const TextStyle( + fontWeight: FontWeight.w500, color: Colors.grey), ), Flexible( child: Text( diff --git a/lib/features/yojna/screens/pmjjby_screen.dart b/lib/features/yojna/screens/pmjjby_screen.dart index 6049326..1fdf77a 100644 --- a/lib/features/yojna/screens/pmjjby_screen.dart +++ b/lib/features/yojna/screens/pmjjby_screen.dart @@ -15,26 +15,45 @@ class _PMJJBYScreenState extends State { final _formKey = GlobalKey(); // Controllers for all requested fields - late final _aadhaarController = TextEditingController(text: widget.initialData?['aadharno']?.toString()); - late final _accountNoController = TextEditingController(text: widget.initialData?['accountno']?.toString()); - late final _balanceController = TextEditingController(text: widget.initialData?['availablebalance']?.toString()); - late final _countryController = TextEditingController(text: widget.initialData?['country']?.toString() ?? 'IN'); - late final _dobController = TextEditingController(text: widget.initialData?['customerdob']?.toString()); - late final _nameController = TextEditingController(text: widget.initialData?['customername']?.toString()); - late final _customerNoController = TextEditingController(text: widget.initialData?['customerno']?.toString()); - late final _acctOpeningDateController = TextEditingController(text: widget.initialData?['dateofacctopening']?.toString()); - late final _emailController = TextEditingController(text: widget.initialData?['emailid']?.toString()); - late final _financialYearController = TextEditingController(text: widget.initialData?['financialyear']?.toString()); - late final _genderController = TextEditingController(text: widget.initialData?['gender']?.toString()); - late final _ifscController = TextEditingController(text: widget.initialData?['ifsccode']?.toString()); - late final _marriedController = TextEditingController(text: widget.initialData?['married']?.toString()); - late final _mobileController = TextEditingController(text: widget.initialData?['mobileno']?.toString()); - late final _panController = TextEditingController(text: widget.initialData?['pan']?.toString()); - late final _pincodeController = TextEditingController(text: widget.initialData?['pincode']?.toString()); - late final _policyNumberController = TextEditingController(text: widget.initialData?['policynumber']?.toString()); - late final _premiumAmountController = TextEditingController(text: widget.initialData?['premiumamount']?.toString()); - late final _stateController = TextEditingController(text: widget.initialData?['state']?.toString()); - + late final _aadhaarController = + TextEditingController(text: widget.initialData?['aadharno']?.toString()); + late final _accountNoController = + TextEditingController(text: widget.initialData?['accountno']?.toString()); + late final _balanceController = TextEditingController( + text: widget.initialData?['availablebalance']?.toString()); + late final _countryController = TextEditingController( + text: widget.initialData?['country']?.toString() ?? 'IN'); + late final _dobController = TextEditingController( + text: widget.initialData?['customerdob']?.toString()); + late final _nameController = TextEditingController( + text: widget.initialData?['customername']?.toString()); + late final _customerNoController = TextEditingController( + text: widget.initialData?['customerno']?.toString()); + late final _acctOpeningDateController = TextEditingController( + text: widget.initialData?['dateofacctopening']?.toString()); + late final _emailController = + TextEditingController(text: widget.initialData?['emailid']?.toString()); + late final _financialYearController = TextEditingController( + text: widget.initialData?['financialyear']?.toString()); + late final _genderController = + TextEditingController(text: widget.initialData?['gender']?.toString()); + late final _ifscController = + TextEditingController(text: widget.initialData?['ifsccode']?.toString()); + late final _marriedController = + TextEditingController(text: widget.initialData?['married']?.toString()); + late final _mobileController = + TextEditingController(text: widget.initialData?['mobileno']?.toString()); + late final _panController = + TextEditingController(text: widget.initialData?['pan']?.toString()); + late final _pincodeController = + TextEditingController(text: widget.initialData?['pincode']?.toString()); + late final _policyNumberController = TextEditingController( + text: widget.initialData?['policynumber']?.toString()); + late final _premiumAmountController = TextEditingController( + text: widget.initialData?['premiumamount']?.toString()); + late final _stateController = + TextEditingController(text: widget.initialData?['state']?.toString()); + // Mapping options final Map _healthStatusOptions = { '1': 'Excellent', @@ -90,16 +109,20 @@ class _PMJJBYScreenState extends State { // Initialize dropdown controllers if data exists in initialData if (widget.initialData != null) { if (widget.initialData!.containsKey('ruralcategory')) { - _ruralCategoryController.text = widget.initialData!['ruralcategory'].toString(); + _ruralCategoryController.text = + widget.initialData!['ruralcategory'].toString(); } if (widget.initialData!.containsKey('healthstatus')) { - _healthStatusController.text = widget.initialData!['healthstatus'].toString(); + _healthStatusController.text = + widget.initialData!['healthstatus'].toString(); } if (widget.initialData!.containsKey('nomineerelationship')) { - _nomineeRelationshipController.text = widget.initialData!['nomineerelationship'].toString(); + _nomineeRelationshipController.text = + widget.initialData!['nomineerelationship'].toString(); } if (widget.initialData!.containsKey('nomineeminor')) { - _nomineeMinorController.text = widget.initialData!['nomineeminor'].toString(); + _nomineeMinorController.text = + widget.initialData!['nomineeminor'].toString(); } } } @@ -136,9 +159,9 @@ class _PMJJBYScreenState extends State { } bool _isFetched(String key) { - return widget.initialData != null && - widget.initialData!.containsKey(key) && - widget.initialData![key]?.toString().isNotEmpty == true; + return widget.initialData != null && + widget.initialData!.containsKey(key) && + widget.initialData![key]?.toString().isNotEmpty == true; } Future _handleRegister() async { @@ -180,8 +203,8 @@ class _PMJJBYScreenState extends State { ruralcategory: _ruralCategoryController.text, ); String x = response.toString(); - if(x.contains('RECORD ALREADY EXISTS')){ - x= l10n.recordAlreadyExists; + if (x.contains('RECORD ALREADY EXISTS')) { + x = l10n.recordAlreadyExists; } if (mounted) { @@ -229,38 +252,77 @@ class _PMJJBYScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _buildTextField(_nameController, l10n.customerName, readOnly: _isFetched('customername')), - _buildTextField(_customerNoController, l10n.customerNo, readOnly: _isFetched('customerno')), - _buildTextField(_accountNoController, l10n.accountNumber, keyboardType: TextInputType.number, readOnly: _isFetched('accountno')), - _buildTextField(_balanceController, l10n.availableBalance, keyboardType: TextInputType.number, readOnly: _isFetched('availablebalance')), - _buildTextField(_aadhaarController, l10n.aadhaarNo, keyboardType: TextInputType.number, readOnly: _isFetched('aadharno')), - _buildTextField(_dobController, l10n.customerDobFormat, readOnly: _isFetched('customerdob')), - _buildTextField(_genderController, l10n.gender, readOnly: _isFetched('gender')), - _buildTextField(_marriedController, l10n.marriedYesNo, readOnly: _isFetched('married')), - _buildTextField(_mobileController, l10n.mobileNumber, keyboardType: TextInputType.phone, readOnly: _isFetched('mobileno')), - _buildTextField(_emailController, 'Email ID', keyboardType: TextInputType.emailAddress, readOnly: _isFetched('emailid')), - _buildTextField(_panController, l10n.pan, readOnly: _isFetched('pan')), - _buildTextField(_ifscController, l10n.ifscCode, readOnly: _isFetched('ifsccode')), - _buildTextField(_acctOpeningDateController, l10n.dateOfAcctOpening, readOnly: _isFetched('dateofacctopening')), - _buildTextField(_pincodeController, l10n.pincode, keyboardType: TextInputType.number, readOnly: _isFetched('pincode')), - _buildTextField(_stateController, l10n.state, readOnly: _isFetched('state')), - _buildTextField(_countryController, l10n.country, readOnly: _isFetched('country')), - _buildDropdownField(_ruralCategoryController, l10n.ruralCategory, _ruralOptions, readOnly: _isFetched('ruralcategory')), + _buildTextField(_nameController, l10n.customerName, + readOnly: _isFetched('customername')), + _buildTextField(_customerNoController, l10n.customerNo, + readOnly: _isFetched('customerno')), + _buildTextField(_accountNoController, l10n.accountNumber, + keyboardType: TextInputType.number, + readOnly: _isFetched('accountno')), + _buildTextField(_balanceController, l10n.availableBalance, + keyboardType: TextInputType.number, + readOnly: _isFetched('availablebalance')), + _buildTextField(_aadhaarController, l10n.aadhaarNo, + keyboardType: TextInputType.number, + readOnly: _isFetched('aadharno')), + _buildTextField(_dobController, l10n.customerDobFormat, + readOnly: _isFetched('customerdob')), + _buildTextField(_genderController, l10n.gender, + readOnly: _isFetched('gender')), + _buildTextField(_marriedController, l10n.marriedYesNo, + readOnly: _isFetched('married')), + _buildTextField(_mobileController, l10n.mobileNumber, + keyboardType: TextInputType.phone, + readOnly: _isFetched('mobileno')), + _buildTextField(_emailController, 'Email ID', + keyboardType: TextInputType.emailAddress, + readOnly: _isFetched('emailid')), + _buildTextField(_panController, l10n.pan, + readOnly: _isFetched('pan')), + _buildTextField(_ifscController, l10n.ifscCode, + readOnly: _isFetched('ifsccode')), + _buildTextField( + _acctOpeningDateController, l10n.dateOfAcctOpening, + readOnly: _isFetched('dateofacctopening')), + _buildTextField(_pincodeController, l10n.pincode, + keyboardType: TextInputType.number, + readOnly: _isFetched('pincode')), + _buildTextField(_stateController, l10n.state, + readOnly: _isFetched('state')), + _buildTextField(_countryController, l10n.country, + readOnly: _isFetched('country')), + _buildDropdownField( + _ruralCategoryController, l10n.ruralCategory, _ruralOptions, + readOnly: _isFetched('ruralcategory')), const Divider(height: 32), - Text(l10n.policyDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text(l10n.policyDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), - _buildTextField(_policyNumberController, l10n.policyNumber, readOnly: _isFetched('policynumber')), - _buildTextField(_premiumAmountController, l10n.premiumAmount, keyboardType: TextInputType.number, readOnly: _isFetched('premiumamount')), - _buildTextField(_financialYearController, l10n.financialYear, readOnly: _isFetched('financialyear')), - _buildDropdownField(_healthStatusController, l10n.healthStatus, _healthStatusOptions), - _buildTextField(_collectionChannelController, l10n.collectionChannel), + _buildTextField(_policyNumberController, l10n.policyNumber, + readOnly: _isFetched('policynumber')), + _buildTextField(_premiumAmountController, l10n.premiumAmount, + keyboardType: TextInputType.number, + readOnly: _isFetched('premiumamount')), + _buildTextField(_financialYearController, l10n.financialYear, + readOnly: _isFetched('financialyear')), + _buildDropdownField(_healthStatusController, l10n.healthStatus, + _healthStatusOptions), + _buildTextField( + _collectionChannelController, l10n.collectionChannel), const Divider(height: 32), - Text(l10n.nomineeDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text(l10n.nomineeDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildTextField(_nomineeNameController, l10n.nomineeName), _buildTextField(_nomineeAddressController, l10n.nomineeAddress), - _buildDropdownField(_nomineeRelationshipController, l10n.nomineeRelationship, _relationshipOptions, readOnly: _isFetched('nomineerelationship')), - _buildDropdownField(_nomineeMinorController, l10n.nomineeMinor, _minorOptions, readOnly: _isFetched('nomineeminor')), + _buildDropdownField(_nomineeRelationshipController, + l10n.nomineeRelationship, _relationshipOptions, + readOnly: _isFetched('nomineerelationship')), + _buildDropdownField( + _nomineeMinorController, l10n.nomineeMinor, _minorOptions, + readOnly: _isFetched('nomineeminor')), const SizedBox(height: 24), ElevatedButton( onPressed: _handleRegister, @@ -274,7 +336,8 @@ class _PMJJBYScreenState extends State { ), child: Text( l10n.register, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 32), @@ -285,25 +348,29 @@ class _PMJJBYScreenState extends State { ); } - Widget _buildDropdownField( - TextEditingController controller, String label, Map options, + Widget _buildDropdownField(TextEditingController controller, String label, + Map options, {bool readOnly = false}) { // Determine current value - String? currentValue = options.containsKey(controller.text) ? controller.text : null; + String? currentValue = + options.containsKey(controller.text) ? controller.text : null; return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: DropdownButtonFormField( value: currentValue, - onChanged: readOnly ? null : (newValue) { - setState(() { - controller.text = newValue ?? ''; - }); - }, + onChanged: readOnly + ? null + : (newValue) { + setState(() { + controller.text = newValue ?? ''; + }); + }, decoration: InputDecoration( labelText: label, border: const OutlineInputBorder(), - contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), items: options.entries.map((entry) { return DropdownMenuItem( @@ -315,7 +382,9 @@ class _PMJJBYScreenState extends State { ); } - Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) { + Widget _buildTextField(TextEditingController controller, String label, + {TextInputType keyboardType = TextInputType.text, + bool readOnly = false}) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: TextFormField( @@ -324,7 +393,8 @@ class _PMJJBYScreenState extends State { decoration: InputDecoration( labelText: label, border: const OutlineInputBorder(), - contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), keyboardType: keyboardType, ), diff --git a/lib/features/yojna/screens/pmsby_enquiry_screen.dart b/lib/features/yojna/screens/pmsby_enquiry_screen.dart index 33961cc..fcdec3b 100644 --- a/lib/features/yojna/screens/pmsby_enquiry_screen.dart +++ b/lib/features/yojna/screens/pmsby_enquiry_screen.dart @@ -119,7 +119,8 @@ class _PMSBYEnquiryScreenState extends State { labelText: l10n.selectFinancialYear, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.calendar_today), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), ), items: _financialYears.map((String year) { return DropdownMenuItem( @@ -153,7 +154,9 @@ class _PMSBYEnquiryScreenState extends State { padding: const EdgeInsets.all(16.0), child: Text( _errorMessage!, - style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold), + style: TextStyle( + color: Colors.red.shade700, + fontWeight: FontWeight.bold), //textAlign: Center, ), ), @@ -177,13 +180,24 @@ class _PMSBYEnquiryScreenState extends State { ), ), const Divider(), - _buildDetailRow(l10n.customerName, _enquiryData!['customername']), - _buildDetailRow(l10n.policyNumber, _enquiryData!['policynumber'] ?? _enquiryData!['policyno']), - _buildDetailRow(l10n.accountNumber, _enquiryData!['accountno']), - _buildDetailRow(l10n.premiumAmount, _enquiryData!['preimiumamount'] ?? _enquiryData!['premiumamount']), - _buildDetailRow(l10n.nomineeName, _enquiryData!['nomineename']), - _buildDetailRow(l10n.date, _enquiryData!['transactiondate']), - _buildDetailRow(l10n.journalNo, _enquiryData!['journalno']), + _buildDetailRow( + l10n.customerName, _enquiryData!['customername']), + _buildDetailRow( + l10n.policyNumber, + _enquiryData!['policynumber'] ?? + _enquiryData!['policyno']), + _buildDetailRow( + l10n.accountNumber, _enquiryData!['accountno']), + _buildDetailRow( + l10n.premiumAmount, + _enquiryData!['preimiumamount'] ?? + _enquiryData!['premiumamount']), + _buildDetailRow( + l10n.nomineeName, _enquiryData!['nomineename']), + _buildDetailRow( + l10n.date, _enquiryData!['transactiondate']), + _buildDetailRow( + l10n.journalNo, _enquiryData!['journalno']), ], ), ), @@ -202,7 +216,8 @@ class _PMSBYEnquiryScreenState extends State { children: [ Text( label, - style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey), + style: const TextStyle( + fontWeight: FontWeight.w500, color: Colors.grey), ), Flexible( child: Text( diff --git a/lib/features/yojna/screens/pmsby_screen.dart b/lib/features/yojna/screens/pmsby_screen.dart index 23f0023..9ce4eaf 100644 --- a/lib/features/yojna/screens/pmsby_screen.dart +++ b/lib/features/yojna/screens/pmsby_screen.dart @@ -15,30 +15,54 @@ class _PMSBYScreenState extends State { final _formKey = GlobalKey(); // Controllers for all requested fields - late final _aadhaarController = TextEditingController(text: widget.initialData?['aadharno']?.toString()); - late final _accountNoController = TextEditingController(text: widget.initialData?['accountno']?.toString()); - late final _balanceController = TextEditingController(text: widget.initialData?['availablebalance']?.toString()); - late final _countryController = TextEditingController(text: widget.initialData?['country']?.toString() ?? 'IN'); - late final _dobController = TextEditingController(text: widget.initialData?['customerdob']?.toString()); - late final _nameController = TextEditingController(text: widget.initialData?['customername']?.toString()); - late final _customerNoController = TextEditingController(text: widget.initialData?['customerno']?.toString()); - late final _acctOpeningDateController = TextEditingController(text: widget.initialData?['dateofacctopening']?.toString()); - late final _emailController = TextEditingController(text: widget.initialData?['emailid']?.toString()); - late final _financialYearController = TextEditingController(text: widget.initialData?['financialyear']?.toString()); - late final _genderController = TextEditingController(text: widget.initialData?['gender']?.toString()); - late final _ifscController = TextEditingController(text: widget.initialData?['ifsccode']?.toString()); - late final _marriedController = TextEditingController(text: widget.initialData?['married']?.toString()); - late final _mobileController = TextEditingController(text: widget.initialData?['mobileno']?.toString()); - late final _panController = TextEditingController(text: widget.initialData?['pan']?.toString()); - late final _pincodeController = TextEditingController(text: widget.initialData?['pincode']?.toString()); - late final _policyNumberController = TextEditingController(text: widget.initialData?['policyno']?.toString()); - late final _premiumAmountController = TextEditingController(text: widget.initialData?['premiumamount']?.toString()); - late final _stateController = TextEditingController(text: widget.initialData?['state']?.toString()); - late final _address1Controller = TextEditingController(text: widget.initialData?['address1']?.toString()); - late final _address2Controller = TextEditingController(text: widget.initialData?['address2']?.toString()); - late final _cityController = TextEditingController(text: widget.initialData?['city']?.toString()); - late final _relationWithNomineeController = TextEditingController(text: widget.initialData?['relationwithnominee']?.toString()); - late final _policyStatusController = TextEditingController(text: widget.initialData?['policystatus']?.toString()); + late final _aadhaarController = + TextEditingController(text: widget.initialData?['aadharno']?.toString()); + late final _accountNoController = + TextEditingController(text: widget.initialData?['accountno']?.toString()); + late final _balanceController = TextEditingController( + text: widget.initialData?['availablebalance']?.toString()); + late final _countryController = TextEditingController( + text: widget.initialData?['country']?.toString() ?? 'IN'); + late final _dobController = TextEditingController( + text: widget.initialData?['customerdob']?.toString()); + late final _nameController = TextEditingController( + text: widget.initialData?['customername']?.toString()); + late final _customerNoController = TextEditingController( + text: widget.initialData?['customerno']?.toString()); + late final _acctOpeningDateController = TextEditingController( + text: widget.initialData?['dateofacctopening']?.toString()); + late final _emailController = + TextEditingController(text: widget.initialData?['emailid']?.toString()); + late final _financialYearController = TextEditingController( + text: widget.initialData?['financialyear']?.toString()); + late final _genderController = + TextEditingController(text: widget.initialData?['gender']?.toString()); + late final _ifscController = + TextEditingController(text: widget.initialData?['ifsccode']?.toString()); + late final _marriedController = + TextEditingController(text: widget.initialData?['married']?.toString()); + late final _mobileController = + TextEditingController(text: widget.initialData?['mobileno']?.toString()); + late final _panController = + TextEditingController(text: widget.initialData?['pan']?.toString()); + late final _pincodeController = + TextEditingController(text: widget.initialData?['pincode']?.toString()); + late final _policyNumberController = + TextEditingController(text: widget.initialData?['policyno']?.toString()); + late final _premiumAmountController = TextEditingController( + text: widget.initialData?['premiumamount']?.toString()); + late final _stateController = + TextEditingController(text: widget.initialData?['state']?.toString()); + late final _address1Controller = + TextEditingController(text: widget.initialData?['address1']?.toString()); + late final _address2Controller = + TextEditingController(text: widget.initialData?['address2']?.toString()); + late final _cityController = + TextEditingController(text: widget.initialData?['city']?.toString()); + late final _relationWithNomineeController = TextEditingController( + text: widget.initialData?['relationwithnominee']?.toString()); + late final _policyStatusController = TextEditingController( + text: widget.initialData?['policystatus']?.toString()); // Mapping options final Map _healthStatusOptions = { @@ -95,16 +119,20 @@ class _PMSBYScreenState extends State { // Initialize dropdown controllers if data exists in initialData if (widget.initialData != null) { if (widget.initialData!.containsKey('ruralcategory')) { - _ruralCategoryController.text = widget.initialData!['ruralcategory'].toString(); + _ruralCategoryController.text = + widget.initialData!['ruralcategory'].toString(); } if (widget.initialData!.containsKey('healthstatus')) { - _healthStatusController.text = widget.initialData!['healthstatus'].toString(); + _healthStatusController.text = + widget.initialData!['healthstatus'].toString(); } if (widget.initialData!.containsKey('relationwithnominee')) { - _nomineeRelationshipController.text = widget.initialData!['relationwithnominee'].toString(); + _nomineeRelationshipController.text = + widget.initialData!['relationwithnominee'].toString(); } if (widget.initialData!.containsKey('nomineeminor')) { - _nomineeMinorController.text = widget.initialData!['nomineeminor'].toString(); + _nomineeMinorController.text = + widget.initialData!['nomineeminor'].toString(); } } } @@ -146,9 +174,9 @@ class _PMSBYScreenState extends State { } bool _isFetched(String key) { - return widget.initialData != null && - widget.initialData!.containsKey(key) && - widget.initialData![key]?.toString().isNotEmpty == true; + return widget.initialData != null && + widget.initialData!.containsKey(key) && + widget.initialData![key]?.toString().isNotEmpty == true; } Future _handleRegister() async { @@ -192,8 +220,8 @@ class _PMSBYScreenState extends State { policystatus: _policyStatusController.text, ); String x = response.toString(); - if(x.contains('RECORD ALREADY EXISTS')){ - x= l10n.recordAlreadyExists; + if (x.contains('RECORD ALREADY EXISTS')) { + x = l10n.recordAlreadyExists; } if (mounted) { @@ -241,43 +269,87 @@ class _PMSBYScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _buildTextField(_nameController, l10n.customerName, readOnly: _isFetched('customername')), - _buildTextField(_customerNoController, l10n.customerNo, readOnly: _isFetched('customerno')), - _buildTextField(_accountNoController, l10n.accountNumber, keyboardType: TextInputType.number, readOnly: _isFetched('accountno')), - _buildTextField(_balanceController, l10n.availableBalance, keyboardType: TextInputType.number, readOnly: _isFetched('availablebalance')), - _buildTextField(_aadhaarController, l10n.aadhaarNo, keyboardType: TextInputType.number, readOnly: _isFetched('aadharno')), - _buildTextField(_dobController, l10n.customerDobFormat, readOnly: _isFetched('customerdob')), - _buildTextField(_genderController, l10n.gender, readOnly: _isFetched('gender')), - _buildTextField(_marriedController, l10n.marriedYesNo, readOnly: _isFetched('married')), - _buildTextField(_mobileController, l10n.mobileNumber, keyboardType: TextInputType.phone, readOnly: _isFetched('mobileno')), - _buildTextField(_emailController, 'Email ID', keyboardType: TextInputType.emailAddress, readOnly: _isFetched('emailid')), - _buildTextField(_address1Controller, l10n.address1, readOnly: _isFetched('address1')), - _buildTextField(_address2Controller, l10n.address2, readOnly: _isFetched('address2')), - _buildTextField(_cityController, l10n.city, readOnly: _isFetched('city')), - _buildTextField(_panController, l10n.pan, readOnly: _isFetched('pan')), - _buildTextField(_ifscController, l10n.ifscCode, readOnly: _isFetched('ifsccode')), - _buildTextField(_acctOpeningDateController, l10n.dateOfAcctOpening, readOnly: _isFetched('dateofacctopening')), - _buildTextField(_pincodeController, l10n.pincode, keyboardType: TextInputType.number, readOnly: _isFetched('pincode')), - _buildTextField(_stateController, l10n.state, readOnly: _isFetched('state')), - _buildTextField(_countryController, l10n.country, readOnly: _isFetched('country')), - _buildDropdownField(_ruralCategoryController, l10n.ruralCategory, _ruralOptions, readOnly: _isFetched('ruralcategory')), + _buildTextField(_nameController, l10n.customerName, + readOnly: _isFetched('customername')), + _buildTextField(_customerNoController, l10n.customerNo, + readOnly: _isFetched('customerno')), + _buildTextField(_accountNoController, l10n.accountNumber, + keyboardType: TextInputType.number, + readOnly: _isFetched('accountno')), + _buildTextField(_balanceController, l10n.availableBalance, + keyboardType: TextInputType.number, + readOnly: _isFetched('availablebalance')), + _buildTextField(_aadhaarController, l10n.aadhaarNo, + keyboardType: TextInputType.number, + readOnly: _isFetched('aadharno')), + _buildTextField(_dobController, l10n.customerDobFormat, + readOnly: _isFetched('customerdob')), + _buildTextField(_genderController, l10n.gender, + readOnly: _isFetched('gender')), + _buildTextField(_marriedController, l10n.marriedYesNo, + readOnly: _isFetched('married')), + _buildTextField(_mobileController, l10n.mobileNumber, + keyboardType: TextInputType.phone, + readOnly: _isFetched('mobileno')), + _buildTextField(_emailController, 'Email ID', + keyboardType: TextInputType.emailAddress, + readOnly: _isFetched('emailid')), + _buildTextField(_address1Controller, l10n.address1, + readOnly: _isFetched('address1')), + _buildTextField(_address2Controller, l10n.address2, + readOnly: _isFetched('address2')), + _buildTextField(_cityController, l10n.city, + readOnly: _isFetched('city')), + _buildTextField(_panController, l10n.pan, + readOnly: _isFetched('pan')), + _buildTextField(_ifscController, l10n.ifscCode, + readOnly: _isFetched('ifsccode')), + _buildTextField( + _acctOpeningDateController, l10n.dateOfAcctOpening, + readOnly: _isFetched('dateofacctopening')), + _buildTextField(_pincodeController, l10n.pincode, + keyboardType: TextInputType.number, + readOnly: _isFetched('pincode')), + _buildTextField(_stateController, l10n.state, + readOnly: _isFetched('state')), + _buildTextField(_countryController, l10n.country, + readOnly: _isFetched('country')), + _buildDropdownField( + _ruralCategoryController, l10n.ruralCategory, _ruralOptions, + readOnly: _isFetched('ruralcategory')), const Divider(height: 32), - Text(l10n.policyDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text(l10n.policyDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), - _buildTextField(_policyNumberController, l10n.policyNumber, readOnly: _isFetched('policyno')), - _buildTextField(_premiumAmountController, l10n.premiumAmount, keyboardType: TextInputType.number, readOnly: _isFetched('premiumamount')), - _buildTextField(_financialYearController, l10n.financialYear, readOnly: _isFetched('financialyear')), - _buildTextField(_policyStatusController, l10n.policyStatus, readOnly: _isFetched('policystatus')), - _buildDropdownField(_healthStatusController, l10n.healthStatus, _healthStatusOptions), - _buildTextField(_collectionChannelController, l10n.collectionChannel), + _buildTextField(_policyNumberController, l10n.policyNumber, + readOnly: _isFetched('policyno')), + _buildTextField(_premiumAmountController, l10n.premiumAmount, + keyboardType: TextInputType.number, + readOnly: _isFetched('premiumamount')), + _buildTextField(_financialYearController, l10n.financialYear, + readOnly: _isFetched('financialyear')), + _buildTextField(_policyStatusController, l10n.policyStatus, + readOnly: _isFetched('policystatus')), + _buildDropdownField(_healthStatusController, l10n.healthStatus, + _healthStatusOptions), + _buildTextField( + _collectionChannelController, l10n.collectionChannel), const Divider(height: 32), - Text(l10n.nomineeDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text(l10n.nomineeDetails, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), _buildTextField(_nomineeNameController, l10n.nomineeName), _buildTextField(_nomineeAddressController, l10n.nomineeAddress), - _buildDropdownField(_relationWithNomineeController, l10n.relationWithNominee, _relationshipOptions, readOnly: _isFetched('relationwithnominee')), - _buildTextField(_nomineeRelationshipController, l10n.nomineeRelationship), - _buildDropdownField(_nomineeMinorController, l10n.nomineeMinor, _minorOptions, readOnly: _isFetched('nomineeminor')), + _buildDropdownField(_relationWithNomineeController, + l10n.relationWithNominee, _relationshipOptions, + readOnly: _isFetched('relationwithnominee')), + _buildTextField( + _nomineeRelationshipController, l10n.nomineeRelationship), + _buildDropdownField( + _nomineeMinorController, l10n.nomineeMinor, _minorOptions, + readOnly: _isFetched('nomineeminor')), const SizedBox(height: 24), ElevatedButton( onPressed: _handleRegister, @@ -291,7 +363,8 @@ class _PMSBYScreenState extends State { ), child: Text( l10n.register, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 32), @@ -302,25 +375,29 @@ class _PMSBYScreenState extends State { ); } - Widget _buildDropdownField( - TextEditingController controller, String label, Map options, + Widget _buildDropdownField(TextEditingController controller, String label, + Map options, {bool readOnly = false}) { // Determine current value - String? currentValue = options.containsKey(controller.text) ? controller.text : null; + String? currentValue = + options.containsKey(controller.text) ? controller.text : null; return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: DropdownButtonFormField( value: currentValue, - onChanged: readOnly ? null : (newValue) { - setState(() { - controller.text = newValue ?? ''; - }); - }, + onChanged: readOnly + ? null + : (newValue) { + setState(() { + controller.text = newValue ?? ''; + }); + }, decoration: InputDecoration( labelText: label, border: const OutlineInputBorder(), - contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), items: options.entries.map((entry) { return DropdownMenuItem( @@ -332,7 +409,9 @@ class _PMSBYScreenState extends State { ); } - Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) { + Widget _buildTextField(TextEditingController controller, String label, + {TextInputType keyboardType = TextInputType.text, + bool readOnly = false}) { return Padding( padding: const EdgeInsets.only(bottom: 16.0), child: TextFormField( @@ -341,7 +420,8 @@ class _PMSBYScreenState extends State { decoration: InputDecoration( labelText: label, border: const OutlineInputBorder(), - contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12), + contentPadding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 12), ), keyboardType: keyboardType, ), diff --git a/lib/main.dart b/lib/main.dart index 6209eb2..b4f2e4b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,4 +24,4 @@ void main() async { // } await setupDependencies(); runApp(const KMobile()); -} \ No newline at end of file +} diff --git a/test/features/accounts/screens/account_statement_screen_test.dart b/test/features/accounts/screens/account_statement_screen_test.dart index 064a428..c938f01 100644 --- a/test/features/accounts/screens/account_statement_screen_test.dart +++ b/test/features/accounts/screens/account_statement_screen_test.dart @@ -134,7 +134,8 @@ void main() { // GROUP 1: Screen Rendering // ═══════════════════════════════════════════════════════════════════════════ group('Screen Rendering', () { - testWidgets('renders AppBar with "Account Statement" title', (tester) async { + testWidgets('renders AppBar with "Account Statement" title', + (tester) async { await tester.pumpWidget(_buildTestApp(users: [testUser])); await tester.pumpAndSettle(); @@ -204,8 +205,7 @@ void main() { expect(find.text('1234567890'), findsOneWidget); }); - testWidgets('dropdown shows all user accounts when tapped', - (tester) async { + testWidgets('dropdown shows all user accounts when tapped', (tester) async { await tester.pumpWidget(_buildTestApp(users: [testUser, testUser2])); await tester.pumpAndSettle(); @@ -370,8 +370,7 @@ void main() { // Find the Icon for credit transactions (call_received) final iconFinder = find.byWidgetPredicate( - (widget) => - widget is Icon && widget.color == const Color(0xFF10BB10), + (widget) => widget is Icon && widget.color == const Color(0xFF10BB10), ); expect(iconFinder, findsOneWidget); }); @@ -388,7 +387,8 @@ void main() { await tester.pumpAndSettle(); expect(find.byType(SnackBar), findsOneWidget); - expect(find.textContaining('Failed to load transactions'), findsOneWidget); + expect( + find.textContaining('Failed to load transactions'), findsOneWidget); }); }); @@ -441,8 +441,7 @@ void main() { // GROUP 9: PDF Export // ═══════════════════════════════════════════════════════════════════════════ group('PDF Export', () { - testWidgets( - 'pressing download FAB with no transactions shows snackbar', + testWidgets('pressing download FAB with no transactions shows snackbar', (tester) async { mockRepo.mockTransactions = [];