Compare commits
8 Commits
sms-testin
...
f024f200a4
| Author | SHA1 | Date | |
|---|---|---|---|
| f024f200a4 | |||
| 54a7b8f1b0 | |||
| 60270a5fa9 | |||
| 9d8c8dc8bd | |||
| 537a4faa62 | |||
| 149d4dbc83 | |||
| 3fa40f133a | |||
| 07d5ea8fbe |
@@ -2,8 +2,6 @@
|
|||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
|
||||||
<application
|
<application
|
||||||
android:label="kmobile"
|
android:label="kmobile"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
@@ -8,41 +8,6 @@ class AuthService {
|
|||||||
final Dio _dio;
|
final Dio _dio;
|
||||||
AuthService(this._dio);
|
AuthService(this._dio);
|
||||||
|
|
||||||
Future<void> simVerify(String uuid, String cifNo) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.post('/api/sim-details-verify', data: {
|
|
||||||
'uuid': uuid,
|
|
||||||
'cifNo': cifNo,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
final String message = response.data.toString().toUpperCase();
|
|
||||||
|
|
||||||
if (message.contains("VERIFIED")) {
|
|
||||||
return; // Success
|
|
||||||
} else {
|
|
||||||
throw AuthException(message); // Throw message received
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw AuthException('Verification Failed');
|
|
||||||
}
|
|
||||||
} on DioException catch (e) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
print(e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.response?.statusCode == 401) {
|
|
||||||
throw AuthException(
|
|
||||||
e.response?.data['error'] ?? 'SOMETHING WENT WRONG');
|
|
||||||
}
|
|
||||||
|
|
||||||
throw NetworkException('Network error during verification');
|
|
||||||
} catch (e) {
|
|
||||||
throw UnexpectedException(
|
|
||||||
'Unexpected error during verification: ${e.toString()}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<AuthToken> login(AuthCredentials credentials) async {
|
Future<AuthToken> login(AuthCredentials credentials) async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.post(
|
final response = await _dio.post(
|
||||||
|
|||||||
@@ -126,27 +126,4 @@ class BeneficiaryService {
|
|||||||
throw Exception('Unexpected error: ${e.toString()}');
|
throw Exception('Unexpected error: ${e.toString()}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Response> updateLimit({
|
|
||||||
required String beneficiaryAccountNo,
|
|
||||||
required String newLimit,
|
|
||||||
}) async {
|
|
||||||
log('inside update limit of beneficiary service');
|
|
||||||
final response = await _dio.patch(
|
|
||||||
'/api/beneficiary/update-limit',
|
|
||||||
data: {
|
|
||||||
'beneficiaryAccountNo': beneficiaryAccountNo,
|
|
||||||
'newLimit': int.tryParse(newLimit),
|
|
||||||
},
|
|
||||||
options: Options(
|
|
||||||
sendTimeout: const Duration(seconds: 60),
|
|
||||||
receiveTimeout: const Duration(seconds: 60),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
throw Exception("INTERNAL SERVER ERROR");
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class BranchService {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return Branch.listFromJson(response.data);
|
return Branch.listFromJson(response.data);
|
||||||
} else {
|
} else {
|
||||||
throw Exception("Failed to fetch beneficiaries");
|
throw Exception("Failed to fetch");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
class Cheque {
|
class Cheque {
|
||||||
@@ -128,64 +130,9 @@ class ChequeService {
|
|||||||
'tpin': tpin,
|
'tpin': tpin,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response.toString();
|
if (response.statusCode != 200) {
|
||||||
}
|
throw Exception(jsonEncode(response.data));
|
||||||
|
}
|
||||||
Future revokeStop({
|
|
||||||
required String accountno,
|
|
||||||
required String removeFromChequeNo,
|
|
||||||
required String instrType,
|
|
||||||
String? removeToChequeNo,
|
|
||||||
String? removeIssueDate,
|
|
||||||
String? removeExpiryDate,
|
|
||||||
String? removeAmount,
|
|
||||||
String? removeComment,
|
|
||||||
required String tpin,
|
|
||||||
}) async {
|
|
||||||
final response = await _dio.post(
|
|
||||||
'/api/cheque/removeStop',
|
|
||||||
options: Options(
|
|
||||||
validateStatus: (int? status) => true,
|
|
||||||
receiveDataWhenStatusError: true,
|
|
||||||
),
|
|
||||||
data: {
|
|
||||||
'accountNumber': accountno,
|
|
||||||
'removeFromChequeNo': removeFromChequeNo,
|
|
||||||
'instrumentType': instrType,
|
|
||||||
'removeToChequeNo': removeToChequeNo,
|
|
||||||
'removeIssueDate': removeIssueDate,
|
|
||||||
'removeExpiryDate': removeExpiryDate,
|
|
||||||
'removeAmount': removeAmount,
|
|
||||||
'removeComment': removeComment,
|
|
||||||
'tpin': tpin,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future registerPPS({
|
|
||||||
required String cheque_no,
|
|
||||||
required String account_number,
|
|
||||||
String? issue_date,
|
|
||||||
String? amount,
|
|
||||||
String? payee_name,
|
|
||||||
required String tpin,
|
|
||||||
}) async {
|
|
||||||
final response = await _dio.post(
|
|
||||||
'/api/pps',
|
|
||||||
options: Options(
|
|
||||||
validateStatus: (int? status) => true,
|
|
||||||
receiveDataWhenStatusError: true,
|
|
||||||
),
|
|
||||||
data: {
|
|
||||||
'cheque_no': cheque_no,
|
|
||||||
'account_number': account_number,
|
|
||||||
'issue_date': issue_date,
|
|
||||||
'amount': amount,
|
|
||||||
'payee_name': payee_name,
|
|
||||||
'tpin': tpin,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response.toString();
|
return response.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:send_message/send_message.dart' show sendSMS;
|
|
||||||
import 'package:simcards/sim_card.dart';
|
|
||||||
import 'package:simcards/simcards.dart';
|
|
||||||
|
|
||||||
// This enum provides detailed status back to the UI layer.
|
|
||||||
enum PermissionStatusResult { granted, denied, permanentlyDenied, restricted }
|
|
||||||
|
|
||||||
class SmsService {
|
|
||||||
final Simcards _simcards = Simcards();
|
|
||||||
|
|
||||||
/// Handles the requesting of SMS and Phone permissions.
|
|
||||||
/// Returns a detailed status: granted, denied, or permanentlyDenied.
|
|
||||||
Future<PermissionStatusResult> handleSmsPermission() async {
|
|
||||||
var smsStatus = await Permission.sms.status;
|
|
||||||
var phoneStatus = await Permission.phone.status;
|
|
||||||
|
|
||||||
// Check initial status
|
|
||||||
if (smsStatus.isGranted && phoneStatus.isGranted) {
|
|
||||||
return PermissionStatusResult.granted;
|
|
||||||
}
|
|
||||||
if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) {
|
|
||||||
return PermissionStatusResult.permanentlyDenied;
|
|
||||||
}
|
|
||||||
if (smsStatus.isRestricted || phoneStatus.isRestricted) {
|
|
||||||
return PermissionStatusResult.restricted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request permissions if not granted
|
|
||||||
print("Requesting SMS and Phone permissions...");
|
|
||||||
await [Permission.phone, Permission.sms].request();
|
|
||||||
|
|
||||||
// Re-check status after request
|
|
||||||
smsStatus = await Permission.sms.status;
|
|
||||||
phoneStatus = await Permission.phone.status;
|
|
||||||
|
|
||||||
if (smsStatus.isGranted && phoneStatus.isGranted) {
|
|
||||||
return PermissionStatusResult.granted;
|
|
||||||
}
|
|
||||||
if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) {
|
|
||||||
return PermissionStatusResult.permanentlyDenied;
|
|
||||||
}
|
|
||||||
if (smsStatus.isRestricted || phoneStatus.isRestricted) {
|
|
||||||
return PermissionStatusResult.restricted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If none of the above, it's denied
|
|
||||||
return PermissionStatusResult.denied;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to send a single verification SMS.
|
|
||||||
/// This should only be called AFTER permissions have been granted.
|
|
||||||
Future<bool> sendVerificationSms({
|
|
||||||
required BuildContext context,
|
|
||||||
required String destinationNumber,
|
|
||||||
required String message,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
List<SimCard> simCardList = await _simcards.getSimCards();
|
|
||||||
if (simCardList.isEmpty) {
|
|
||||||
print("No SIM card detected.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return await _sendSms(destinationNumber, message, simCardList.first);
|
|
||||||
} catch (e) {
|
|
||||||
print("An error occurred in the SMS process: $e");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Private function to perform the SMS sending action.
|
|
||||||
Future<bool> _sendSms(
|
|
||||||
String destinationNumber, String message, SimCard selectedSim) async {
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
try {
|
|
||||||
String smsMessage = message;
|
|
||||||
String result = await sendSMS(
|
|
||||||
message: smsMessage,
|
|
||||||
recipients: [destinationNumber],
|
|
||||||
sendDirect: true,
|
|
||||||
);
|
|
||||||
print("Background SMS send attempt result: $result");
|
|
||||||
|
|
||||||
if (result.toLowerCase().contains('sent')) {
|
|
||||||
print("Success: SMS appears to have been sent.");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
print("Failure: SMS was not sent. Result: $result");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print("Error attempting to send SMS directly: $e");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print("SMS sending is only supported on Android.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
import 'dart:developer';
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class YojnaService {
|
|
||||||
final Dio _dio;
|
|
||||||
|
|
||||||
YojnaService(this._dio);
|
|
||||||
|
|
||||||
Future<dynamic> fetchpmydetails({
|
|
||||||
required String scheme,
|
|
||||||
required String action,
|
|
||||||
required String accountno,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.post(
|
|
||||||
"/api/gov-scheme/req/PMJBY",
|
|
||||||
data: {
|
|
||||||
'scheme': scheme,
|
|
||||||
'action': action,
|
|
||||||
'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 PMY details: $e");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future secondvalidationPMJJBY({
|
|
||||||
String? aadharno,
|
|
||||||
String? accountno,
|
|
||||||
String? availablebalance,
|
|
||||||
String? country,
|
|
||||||
String? customerdob,
|
|
||||||
String? customername,
|
|
||||||
String? customerno,
|
|
||||||
String? dateofacctopening,
|
|
||||||
String? emailid,
|
|
||||||
String? financialyear,
|
|
||||||
String? gender,
|
|
||||||
String? ifsccode,
|
|
||||||
String? married,
|
|
||||||
String? mobileno,
|
|
||||||
String? pan,
|
|
||||||
String? pincode,
|
|
||||||
String? policynumber,
|
|
||||||
String? premiumamount,
|
|
||||||
String? state,
|
|
||||||
String? healthstatus,
|
|
||||||
String? collectionchannel,
|
|
||||||
String? nomineename,
|
|
||||||
String? nomineeaddress,
|
|
||||||
String? nomineerelationship,
|
|
||||||
String? nomineeminor,
|
|
||||||
String? ruralcategory,
|
|
||||||
}) async {
|
|
||||||
final response = await _dio.post(
|
|
||||||
'/api/gov-scheme/create/PMJBY',
|
|
||||||
options: Options(
|
|
||||||
validateStatus: (int? status) => true,
|
|
||||||
receiveDataWhenStatusError: true,
|
|
||||||
),
|
|
||||||
data: {
|
|
||||||
'aadharno': aadharno ,
|
|
||||||
'accountno': accountno,
|
|
||||||
'availablebalance': availablebalance,
|
|
||||||
'country': country,
|
|
||||||
'customerdob': customerdob,
|
|
||||||
'customername': customername,
|
|
||||||
'customerno': customerno,
|
|
||||||
'dateofacctopening': dateofacctopening,
|
|
||||||
'emailid': emailid,
|
|
||||||
'financialyear': financialyear,
|
|
||||||
'gender': gender,
|
|
||||||
'ifsccode': ifsccode,
|
|
||||||
'married': married,
|
|
||||||
'mobileno': mobileno,
|
|
||||||
'pan': pan,
|
|
||||||
'pincode': pincode,
|
|
||||||
'policynumber': policynumber,
|
|
||||||
'premiumamount': premiumamount,
|
|
||||||
'state': state,
|
|
||||||
'healthstatus': healthstatus,
|
|
||||||
'collectionchannel': collectionchannel,
|
|
||||||
'nomineename': nomineename,
|
|
||||||
'nomineeaddress': nomineeaddress,
|
|
||||||
'nomineerelationship': nomineerelationship,
|
|
||||||
'nomineeminor': nomineeminor,
|
|
||||||
'ruralcategory': ruralcategory,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future secondvalidationPMSBY({
|
|
||||||
String? aadharno,
|
|
||||||
String? accountno,
|
|
||||||
String? address1,
|
|
||||||
String? address2,
|
|
||||||
String? availablebalance,
|
|
||||||
String? city,
|
|
||||||
String? country,
|
|
||||||
String? customerdob,
|
|
||||||
String? customername,
|
|
||||||
String? customerno,
|
|
||||||
String? emailid,
|
|
||||||
String? financialyear,
|
|
||||||
String? gender,
|
|
||||||
String? married,
|
|
||||||
String? mobileno,
|
|
||||||
String? pan,
|
|
||||||
String? pincode,
|
|
||||||
String? policyno,
|
|
||||||
String? premiumamount,
|
|
||||||
String? state,
|
|
||||||
String? healthstatus,
|
|
||||||
String? nomineename,
|
|
||||||
String? nomineeadress,
|
|
||||||
String? relationwithnominee,
|
|
||||||
String? nomineeminor,
|
|
||||||
String? collectionchannel,
|
|
||||||
String? ruralcategory,
|
|
||||||
String? policystatus,
|
|
||||||
}) async {
|
|
||||||
final response = await _dio.post(
|
|
||||||
'/api/gov-scheme/create/PMSBY',
|
|
||||||
options: Options(
|
|
||||||
validateStatus: (int? status) => true,
|
|
||||||
receiveDataWhenStatusError: true,
|
|
||||||
),
|
|
||||||
data: {
|
|
||||||
"aadharno": aadharno,
|
|
||||||
"accountno": accountno,
|
|
||||||
"address1": address1,
|
|
||||||
"address2": address2,
|
|
||||||
"availablebalance": availablebalance,
|
|
||||||
"city": city,
|
|
||||||
"country": country,
|
|
||||||
"customerdob": customerdob,
|
|
||||||
"customername": customername,
|
|
||||||
"customerno": customerno,
|
|
||||||
"emailid": emailid,
|
|
||||||
"financialyear": financialyear,
|
|
||||||
"gender": gender,
|
|
||||||
"married": married,
|
|
||||||
"mobileno": mobileno,
|
|
||||||
"pan": pan,
|
|
||||||
"pincode": pincode,
|
|
||||||
"policyno": policyno,
|
|
||||||
"premiumamount": premiumamount,
|
|
||||||
"state": state,
|
|
||||||
"healthstatus": healthstatus,
|
|
||||||
"nomineename": nomineename,
|
|
||||||
"nomineeadress": nomineeadress,
|
|
||||||
"relationwithnominee": relationwithnominee,
|
|
||||||
"nomineeminor": nomineeminor,
|
|
||||||
"collectionchannel": collectionchannel,
|
|
||||||
"ruralcategory": ruralcategory,
|
|
||||||
"policystatus": policystatus,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> enquiry({
|
|
||||||
required String scheme,
|
|
||||||
required String action,
|
|
||||||
required String financialyear,
|
|
||||||
String? customerno,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.get(
|
|
||||||
"/api/gov-scheme/enquiry/PMJBY",
|
|
||||||
queryParameters: {
|
|
||||||
'scheme': scheme,
|
|
||||||
'action': action,
|
|
||||||
'financialyear': financialyear,
|
|
||||||
'customerno': customerno,
|
|
||||||
},
|
|
||||||
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 PMY details: $e");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ class Beneficiary {
|
|||||||
final String ifscCode;
|
final String ifscCode;
|
||||||
final String? bankName;
|
final String? bankName;
|
||||||
final String? branchName;
|
final String? branchName;
|
||||||
final String? transactionLimit;
|
|
||||||
final String? tpin;
|
final String? tpin;
|
||||||
|
|
||||||
Beneficiary({
|
Beneficiary({
|
||||||
@@ -17,7 +16,6 @@ class Beneficiary {
|
|||||||
required this.ifscCode,
|
required this.ifscCode,
|
||||||
this.bankName,
|
this.bankName,
|
||||||
this.branchName,
|
this.branchName,
|
||||||
this.transactionLimit,
|
|
||||||
this.tpin,
|
this.tpin,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -32,7 +30,6 @@ class Beneficiary {
|
|||||||
ifscCode: json['ifsc_code'] ?? json['ifscCode'] ?? '',
|
ifscCode: json['ifsc_code'] ?? json['ifscCode'] ?? '',
|
||||||
bankName: json['bank_name'] ?? json['bankName'] ?? '',
|
bankName: json['bank_name'] ?? json['bankName'] ?? '',
|
||||||
branchName: json['branch_name'] ?? json['branchName'] ?? '',
|
branchName: json['branch_name'] ?? json['branchName'] ?? '',
|
||||||
transactionLimit: json['transactionLimit'] ?? '',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:kmobile/api/services/beneficiary_service.dart';
|
import 'package:kmobile/api/services/beneficiary_service.dart';
|
||||||
import 'package:kmobile/api/services/payment_service.dart';
|
import 'package:kmobile/api/services/payment_service.dart';
|
||||||
import 'package:kmobile/api/services/user_service.dart';
|
import 'package:kmobile/api/services/user_service.dart';
|
||||||
import 'package:kmobile/api/services/yojna_service.dart';
|
|
||||||
import 'package:kmobile/data/repositories/transaction_repository.dart';
|
import 'package:kmobile/data/repositories/transaction_repository.dart';
|
||||||
import 'package:kmobile/features/auth/controllers/theme_cubit.dart';
|
import 'package:kmobile/features/auth/controllers/theme_cubit.dart';
|
||||||
import 'package:kmobile/features/auth/controllers/theme_mode_cubit.dart';
|
import 'package:kmobile/features/auth/controllers/theme_mode_cubit.dart';
|
||||||
@@ -59,7 +58,6 @@ Future<void> setupDependencies() async {
|
|||||||
getIt.registerSingleton<ImpsService>(ImpsService(getIt<Dio>()));
|
getIt.registerSingleton<ImpsService>(ImpsService(getIt<Dio>()));
|
||||||
getIt.registerSingleton<BranchService>(BranchService(getIt<Dio>()));
|
getIt.registerSingleton<BranchService>(BranchService(getIt<Dio>()));
|
||||||
getIt.registerSingleton<ChequeService>(ChequeService(getIt<Dio>()));
|
getIt.registerSingleton<ChequeService>(ChequeService(getIt<Dio>()));
|
||||||
getIt.registerSingleton<YojnaService>(YojnaService(getIt<Dio>()));
|
|
||||||
getIt.registerLazySingleton<ChangePasswordService>(
|
getIt.registerLazySingleton<ChangePasswordService>(
|
||||||
() => ChangePasswordService(getIt<Dio>()),
|
() => ChangePasswordService(getIt<Dio>()),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,175 +0,0 @@
|
|||||||
import 'package:flutter/material.dart'; // Keep if User model is generic
|
|
||||||
import 'package:kmobile/features/account_opening/screens/fd_screen.dart';
|
|
||||||
import 'package:kmobile/features/account_opening/screens/loan_screen.dart';
|
|
||||||
import 'package:kmobile/features/account_opening/screens/rd_screen.dart';
|
|
||||||
import 'package:kmobile/features/account_opening/screens/td_screen.dart';
|
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
|
||||||
import '../../../l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class AccountOpeningScreen extends StatefulWidget {
|
|
||||||
const AccountOpeningScreen({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AccountOpeningScreen> createState() => _AccountOpeningScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AccountOpeningScreenState extends State<AccountOpeningScreen> {
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text(
|
|
||||||
"Account Opening",
|
|
||||||
),
|
|
||||||
centerTitle: false,
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: AccountOpeningCardTile(
|
|
||||||
icon: Symbols.savings,
|
|
||||||
label: "Fixed Deposit (FD)",
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const FdScreen(
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: AccountOpeningCardTile(
|
|
||||||
icon: Symbols.currency_rupee,
|
|
||||||
label: "Term Deposit",
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const TermDepositScreen()
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: AccountOpeningCardTile(
|
|
||||||
icon: Symbols.account_balance,
|
|
||||||
label: AppLocalizations.of(context).recurringDeposit,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const RecurringDepositScreen() ),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: AccountOpeningCardTile(
|
|
||||||
icon: Symbols.credit_card,
|
|
||||||
label: "Request Loan",
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const LoanScreen()
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IgnorePointer(
|
|
||||||
child: Center(
|
|
||||||
child: Opacity(
|
|
||||||
opacity: 0.07,
|
|
||||||
child: ClipOval(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
width: 200,
|
|
||||||
height: 200,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AccountOpeningCardTile extends StatelessWidget {
|
|
||||||
final IconData icon;
|
|
||||||
final String label;
|
|
||||||
final VoidCallback onTap;
|
|
||||||
final bool disable;
|
|
||||||
|
|
||||||
const AccountOpeningCardTile({
|
|
||||||
super.key,
|
|
||||||
required this.icon,
|
|
||||||
required this.label,
|
|
||||||
required this.onTap,
|
|
||||||
this.disable = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
),
|
|
||||||
elevation: 4,
|
|
||||||
child: InkWell(
|
|
||||||
onTap:
|
|
||||||
disable ? null : onTap,
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
|
|
||||||
child: Center(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
icon,
|
|
||||||
size: 48,
|
|
||||||
color: disable
|
|
||||||
? theme.disabledColor
|
|
||||||
: theme.colorScheme.primary,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.titleLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: disable
|
|
||||||
? theme.disabledColor
|
|
||||||
: theme.colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/features/account_opening/screens/interest_rates_screen.dart';
|
|
||||||
|
|
||||||
class FdScreen extends StatefulWidget {
|
|
||||||
const FdScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<FdScreen> createState() => _FdScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FdScreenState extends State<FdScreen> {
|
|
||||||
final TextEditingController _debitAccountController = TextEditingController();
|
|
||||||
final TextEditingController _amountController = TextEditingController();
|
|
||||||
final TextEditingController _yearsController = TextEditingController();
|
|
||||||
final TextEditingController _monthsController = TextEditingController();
|
|
||||||
final TextEditingController _daysController = TextEditingController();
|
|
||||||
|
|
||||||
String _rateOfInterest = "N/A";
|
|
||||||
String _maturityDate = "N/A";
|
|
||||||
String _maturityAmount = "N/A";
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_debitAccountController.dispose();
|
|
||||||
_amountController.dispose();
|
|
||||||
_yearsController.dispose();
|
|
||||||
_monthsController.dispose();
|
|
||||||
_daysController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Fixed Deposit (FD)'),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
// Explanation Tile
|
|
||||||
Card(
|
|
||||||
margin: const EdgeInsets.only(bottom: 20),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Earn more on your savings with a simple, secure Fixed Deposit.',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Debit Account Number
|
|
||||||
TextFormField(
|
|
||||||
controller: _debitAccountController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Debit Account Number',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Enter Amount
|
|
||||||
TextFormField(
|
|
||||||
controller: _amountController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Enter Amount',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
prefixText: '₹ '
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Duration and Interest Rates Link
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Duration',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const InterestRatesScreen()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Interest Rates',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
|
|
||||||
// Duration TextBoxes
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _yearsController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Years',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _monthsController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Months',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _daysController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Days',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
|
|
||||||
// Rate of Interest and Maturity Date Display
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Rate of Interest',
|
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
_rateOfInterest,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Maturity Date',
|
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
_maturityDate,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
// Maturity Amount Display
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Maturity Amount',
|
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
_maturityAmount,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
|
|
||||||
// Proceed Button
|
|
||||||
Center(
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implement proceed logic
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'Proceed',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class InterestRatesScreen extends StatelessWidget {
|
|
||||||
const InterestRatesScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Interest Rates'),
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Text('This page will display a table of interest rates.'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class LoanScreen extends StatelessWidget {
|
|
||||||
const LoanScreen({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("Request Loan"),
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Text("Loan Account"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class RecurringDepositScreen extends StatelessWidget {
|
|
||||||
const RecurringDepositScreen({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("Recurring Deposit"),
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Text("Recurring Deposit"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class TermDepositScreen extends StatelessWidget {
|
|
||||||
const TermDepositScreen({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("Term Deposit (TD)"),
|
|
||||||
),
|
|
||||||
body: const Center(
|
|
||||||
child: Text("Term Deposit (TD)"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ import 'package:kmobile/app.dart';
|
|||||||
import 'package:kmobile/features/auth/screens/mpin_screen.dart';
|
import 'package:kmobile/features/auth/screens/mpin_screen.dart';
|
||||||
import 'package:kmobile/features/auth/screens/set_password_screen.dart';
|
import 'package:kmobile/features/auth/screens/set_password_screen.dart';
|
||||||
import 'package:kmobile/features/auth/screens/tnc_required_screen.dart';
|
import 'package:kmobile/features/auth/screens/tnc_required_screen.dart';
|
||||||
import 'package:kmobile/features/auth/screens/verification_screen.dart';
|
|
||||||
import 'package:kmobile/widgets/tnc_dialog.dart';
|
import 'package:kmobile/widgets/tnc_dialog.dart';
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -31,23 +30,12 @@ class LoginScreenState extends State<LoginScreen>
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _submitForm() async {
|
void _submitForm() {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
final bool? verificationSuccess = await Navigator.of(context).push(
|
context.read<AuthCubit>().login(
|
||||||
MaterialPageRoute(
|
_customerNumberController.text.trim(),
|
||||||
builder: (_) => VerificationScreen(
|
_passwordController.text,
|
||||||
customerNo: _customerNumberController.text.trim(),
|
);
|
||||||
password: _passwordController.text,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (verificationSuccess == true && mounted) {
|
|
||||||
context.read<AuthCubit>().login(
|
|
||||||
_customerNumberController.text.trim(),
|
|
||||||
_passwordController.text,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/send_sms_service.dart';
|
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class SmsVerificationHelper {
|
|
||||||
final SmsService _smsService = SmsService();
|
|
||||||
|
|
||||||
Future<void> _showPermanentlyDeniedDialog(BuildContext context) async {
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text("Permission Required"),
|
|
||||||
content: const Text(
|
|
||||||
"SMS and Phone permissions are required for device verification. Please enable them in your app settings to continue."),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Cancel"),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Open Settings"),
|
|
||||||
onPressed: () {
|
|
||||||
openAppSettings(); // Opens the phone's settings screen for this app
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showRestrictedSmsDialog(BuildContext context) async {
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text("SMS Permission Restricted"),
|
|
||||||
content: const SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"It seems your device is restricting this app from sending SMS messages, which is required for verification. Please follow these steps to enable it:\n"),
|
|
||||||
Text("1. Open your device Settings.",
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
|
||||||
Text("2. Go to 'Apps' or 'Apps & notifications'."),
|
|
||||||
Text("3. Find and tap on this app ('KMobile')."),
|
|
||||||
Text("4. Tap on the three dots (⋮) in the top right corner."),
|
|
||||||
Text(
|
|
||||||
"5. Select 'Allow restricted settings' and confirm. This is crucial to allow SMS permission."),
|
|
||||||
Text("6. Now you have two options to allow SMS permission:"),
|
|
||||||
Text(
|
|
||||||
" a. Tap on 'Permissions', then find 'SMS' is set to 'Allow'."),
|
|
||||||
Text(
|
|
||||||
" b. Alternatively, you can return to the KMobile app, and the SMS permission pop-up should appear again, allowing you to grant it directly."),
|
|
||||||
Text(
|
|
||||||
"\nSome devices have an additional setting for 'Premium SMS'. If the above doesn't work, look for a 'Premium SMS access' setting (you can search for it in your Settings app) and set it to 'Always Allow' for this app.\n"),
|
|
||||||
Text(
|
|
||||||
"After you've enabled the permission, please come back to the app."),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: const Text("I've Enabled It"),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String?> initiateSmsSequence({
|
|
||||||
required BuildContext context,
|
|
||||||
}) async {
|
|
||||||
bool hasPermission = false;
|
|
||||||
|
|
||||||
// --- PERMISSION LOOP ---
|
|
||||||
while (!hasPermission) {
|
|
||||||
// handleSmsPermission will check the status and request if not granted.
|
|
||||||
final status = await _smsService.handleSmsPermission();
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case PermissionStatusResult.granted:
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text("Permissions Granted! Proceeding..."),
|
|
||||||
duration: Duration(seconds: 2)),
|
|
||||||
);
|
|
||||||
hasPermission = true; // This will break the loop
|
|
||||||
break;
|
|
||||||
case PermissionStatusResult.denied:
|
|
||||||
// The user denied the permission. We show a dialog to explain why we need it
|
|
||||||
// and give them a chance to cancel or let the loop try again.
|
|
||||||
final tryAgain = await showDialog<bool>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text("Permission Required"),
|
|
||||||
content: const Text(
|
|
||||||
"This app requires SMS and Phone permissions to verify your device. Please grant the permissions to continue."),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Cancel"),
|
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Try Again"),
|
|
||||||
onPressed: () => Navigator.of(context).pop(true),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (tryAgain != true) {
|
|
||||||
return null; // User chose to cancel.
|
|
||||||
}
|
|
||||||
// If they chose "Try Again", the loop will repeat.
|
|
||||||
break;
|
|
||||||
case PermissionStatusResult.permanentlyDenied:
|
|
||||||
await _showPermanentlyDeniedDialog(context);
|
|
||||||
// Give user time to come back from settings
|
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
|
||||||
// The loop will repeat and re-check the status.
|
|
||||||
break;
|
|
||||||
case PermissionStatusResult.restricted:
|
|
||||||
await _showRestrictedSmsDialog(context);
|
|
||||||
// Give user time to come back from settings
|
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
|
||||||
// The loop will repeat and re-check the status.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- SMS SENDING LOOP ---
|
|
||||||
// This part will only be reached if hasPermission is true.
|
|
||||||
int retries = 3;
|
|
||||||
while (retries > 0) {
|
|
||||||
var uuid = const Uuid();
|
|
||||||
String uniqueId = uuid.v4();
|
|
||||||
String smsMessage = uniqueId;
|
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content:
|
|
||||||
Text("Attempting to send verification SMS... (${4 - retries})"),
|
|
||||||
duration: const Duration(seconds: 2)),
|
|
||||||
);
|
|
||||||
|
|
||||||
bool isSmsSent = await _smsService.sendVerificationSms(
|
|
||||||
context: context,
|
|
||||||
destinationNumber: '9580079717', // Replace with your number
|
|
||||||
message: smsMessage,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isSmsSent) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text("SMS sent successfully!"),
|
|
||||||
duration: Duration(seconds: 2)),
|
|
||||||
);
|
|
||||||
return uniqueId;
|
|
||||||
} else {
|
|
||||||
retries--;
|
|
||||||
if (retries > 0) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text("SMS failed to send. Retrying in 5 seconds..."),
|
|
||||||
duration: Duration(seconds: 4)),
|
|
||||||
);
|
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all retries fail
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/auth_service.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/features/auth/screens/sms_verification_helper.dart';
|
|
||||||
|
|
||||||
class VerificationScreen extends StatefulWidget {
|
|
||||||
final String customerNo;
|
|
||||||
final String password;
|
|
||||||
|
|
||||||
const VerificationScreen({
|
|
||||||
super.key,
|
|
||||||
required this.customerNo,
|
|
||||||
required this.password,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<VerificationScreen> createState() => _VerificationScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VerificationScreenState extends State<VerificationScreen> {
|
|
||||||
String _statusMessage = "Starting verification...";
|
|
||||||
Timer? _timer;
|
|
||||||
int _countdown = 120;
|
|
||||||
bool _isVerifying = false;
|
|
||||||
bool _verificationFailed = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_startVerificationProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_timer?.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startTimer() {
|
|
||||||
_timer?.cancel(); // Cancel any existing timer
|
|
||||||
_countdown = 120;
|
|
||||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
||||||
if (_countdown > 0) {
|
|
||||||
setState(() {
|
|
||||||
_countdown--;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_timer?.cancel();
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Verification timed out. Please try again.";
|
|
||||||
_isVerifying = false;
|
|
||||||
_verificationFailed = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _startVerificationProcess() async {
|
|
||||||
setState(() {
|
|
||||||
_isVerifying = true;
|
|
||||||
_verificationFailed = false;
|
|
||||||
_statusMessage = "Starting verification...";
|
|
||||||
});
|
|
||||||
_startTimer();
|
|
||||||
|
|
||||||
// 1. Send SMS
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "SMS sending...";
|
|
||||||
});
|
|
||||||
final smsHelper = SmsVerificationHelper();
|
|
||||||
final uuid = await smsHelper.initiateSmsSequence(context: context);
|
|
||||||
|
|
||||||
if (uuid != null && mounted) {
|
|
||||||
// SMS sending was successful, now wait before verifying.
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "SMS sent. Waiting for network delivery...";
|
|
||||||
});
|
|
||||||
|
|
||||||
// Adding a 10-second delay to account for SMS network latency.
|
|
||||||
await Future.delayed(const Duration(seconds: 10));
|
|
||||||
|
|
||||||
if (!mounted) return;
|
|
||||||
|
|
||||||
// 2. Verify SIM
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Verifying with server...";
|
|
||||||
});
|
|
||||||
|
|
||||||
final authService = getIt<AuthService>();
|
|
||||||
try {
|
|
||||||
await authService.simVerify(uuid, widget.customerNo);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Verification successful!";
|
|
||||||
_isVerifying = false;
|
|
||||||
});
|
|
||||||
_timer?.cancel();
|
|
||||||
|
|
||||||
// Pop with success result
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
} catch (e) {
|
|
||||||
setState(() {
|
|
||||||
if(e.toString().contains("NOT_VERIFIED")){
|
|
||||||
_statusMessage = "SIM details not found. Please ensure your mobile number is registered with the bank.";
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
_statusMessage = e.toString();
|
|
||||||
}
|
|
||||||
_isVerifying = false;
|
|
||||||
_verificationFailed = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage =
|
|
||||||
"SMS sending failed. Please check permissions and try again.";
|
|
||||||
_isVerifying = false;
|
|
||||||
_verificationFailed = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text("Device Verification"),
|
|
||||||
automaticallyImplyLeading: !_isVerifying,
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(24.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
if (_isVerifying) const CircularProgressIndicator(),
|
|
||||||
if (!_isVerifying && _verificationFailed)
|
|
||||||
const Icon(Icons.error_outline, color: Colors.red, size: 50),
|
|
||||||
if (!_isVerifying && !_verificationFailed)
|
|
||||||
const Icon(Icons.check_circle_outline,
|
|
||||||
color: Colors.green, size: 50),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
Text(
|
|
||||||
_statusMessage,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
if (_isVerifying)
|
|
||||||
Text(
|
|
||||||
"Time remaining: $_countdown seconds",
|
|
||||||
style: const TextStyle(fontSize: 16, color: Colors.grey),
|
|
||||||
),
|
|
||||||
if (_verificationFailed && !_isVerifying) ...[
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: _startVerificationProcess,
|
|
||||||
child: const Text('Retry'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:kmobile/data/models/beneficiary.dart';
|
import 'package:kmobile/data/models/beneficiary.dart';
|
||||||
import 'package:kmobile/di/injection.dart';
|
import 'package:kmobile/di/injection.dart';
|
||||||
import 'package:kmobile/widgets/bank_logos.dart';
|
import 'package:kmobile/widgets/bank_logos.dart';
|
||||||
@@ -7,39 +6,16 @@ import 'package:kmobile/api/services/beneficiary_service.dart';
|
|||||||
|
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
class BeneficiaryDetailsScreen extends StatefulWidget {
|
class BeneficiaryDetailsScreen extends StatelessWidget {
|
||||||
final Beneficiary beneficiary;
|
final Beneficiary beneficiary;
|
||||||
|
|
||||||
const BeneficiaryDetailsScreen({super.key, required this.beneficiary});
|
BeneficiaryDetailsScreen({super.key, required this.beneficiary});
|
||||||
|
|
||||||
@override
|
|
||||||
State<BeneficiaryDetailsScreen> createState() =>
|
|
||||||
_BeneficiaryDetailsScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BeneficiaryDetailsScreenState extends State<BeneficiaryDetailsScreen> {
|
|
||||||
final service = getIt<BeneficiaryService>();
|
final service = getIt<BeneficiaryService>();
|
||||||
late String _currentLimit;
|
|
||||||
final _limitController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_currentLimit = (widget.beneficiary.transactionLimit == null ||
|
|
||||||
widget.beneficiary.transactionLimit!.isEmpty)
|
|
||||||
? 'N/A'
|
|
||||||
: widget.beneficiary.transactionLimit!;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_limitController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _deleteBeneficiary(BuildContext context) async {
|
void _deleteBeneficiary(BuildContext context) async {
|
||||||
try {
|
try {
|
||||||
await service.deleteBeneficiary(widget.beneficiary.accountNo);
|
await service.deleteBeneficiary(beneficiary.accountNo);
|
||||||
if (!context.mounted) {
|
if (!context.mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -101,73 +77,6 @@ class _BeneficiaryDetailsScreenState extends State<BeneficiaryDetailsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showEditLimitDialog() async {
|
|
||||||
_limitController.text = _currentLimit == 'N/A' ? '' : _currentLimit;
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (dialogContext) {
|
|
||||||
final localizations = AppLocalizations.of(dialogContext);
|
|
||||||
final theme = Theme.of(dialogContext);
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(localizations.editLimit),
|
|
||||||
content: TextField(
|
|
||||||
controller: _limitController,
|
|
||||||
autofocus: true,
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.allow(RegExp(r'^\d+')),
|
|
||||||
],
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: localizations.limitAmount,
|
|
||||||
prefixText: '₹',
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
|
||||||
child: Text(localizations.cancel),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
final value = _limitController.text;
|
|
||||||
if (value.isEmpty || int.tryParse(value) == null) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await service.updateLimit(
|
|
||||||
beneficiaryAccountNo: widget.beneficiary.accountNo,
|
|
||||||
newLimit: value,
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
|
||||||
setState(() {
|
|
||||||
_currentLimit = value;
|
|
||||||
});
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(localizations.limitUpdatedSuccess),
|
|
||||||
behavior: SnackBarBehavior.floating,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text("${localizations.error}: $e"),
|
|
||||||
behavior: SnackBarBehavior.floating,
|
|
||||||
backgroundColor: theme.colorScheme.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(localizations.save),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -187,11 +96,11 @@ class _BeneficiaryDetailsScreenState extends State<BeneficiaryDetailsScreen> {
|
|||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 24,
|
radius: 24,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
child: getBankLogo(widget.beneficiary.bankName, context),
|
child: getBankLogo(beneficiary.bankName, context),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
widget.beneficiary.name,
|
beneficiary.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.bold),
|
fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
@@ -199,28 +108,28 @@ class _BeneficiaryDetailsScreenState extends State<BeneficiaryDetailsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
_buildDetailRow('${AppLocalizations.of(context).bankName} ',
|
_buildDetailRow('${AppLocalizations.of(context).bankName} ',
|
||||||
widget.beneficiary.bankName ?? 'N/A'),
|
beneficiary.bankName ?? 'N/A'),
|
||||||
_buildDetailRow(
|
_buildDetailRow(
|
||||||
'${AppLocalizations.of(context).accountNumber} ',
|
'${AppLocalizations.of(context).accountNumber} ',
|
||||||
widget.beneficiary.accountNo),
|
beneficiary.accountNo),
|
||||||
_buildDetailRow(
|
_buildDetailRow(
|
||||||
'${AppLocalizations.of(context).accountType} ',
|
'${AppLocalizations.of(context).accountType} ',
|
||||||
widget.beneficiary.accountType),
|
beneficiary.accountType),
|
||||||
_buildDetailRow('${AppLocalizations.of(context).ifscCode} ',
|
_buildDetailRow('${AppLocalizations.of(context).ifscCode} ',
|
||||||
widget.beneficiary.ifscCode),
|
beneficiary.ifscCode),
|
||||||
_buildDetailRow('${AppLocalizations.of(context).branchName} ',
|
_buildDetailRow('${AppLocalizations.of(context).branchName} ',
|
||||||
widget.beneficiary.branchName ?? 'N/A'),
|
beneficiary.branchName ?? 'N/A'),
|
||||||
_buildDetailRow(
|
|
||||||
"Beneficiary Transactional Limit", _currentLimit),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
// ElevatedButton.icon(
|
||||||
onPressed: _showEditLimitDialog,
|
// onPressed: () {
|
||||||
icon: const Icon(Icons.currency_rupee),
|
// // Set Transaction Limit for this beneficiary
|
||||||
label: Text(AppLocalizations.of(context).editLimit),
|
// },
|
||||||
),
|
// icon: const Icon(Icons.currency_rupee),
|
||||||
|
// label: const Text('Set Limit'),
|
||||||
|
// ),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Delete beneficiary option
|
// Delete beneficiary option
|
||||||
@@ -274,4 +183,3 @@ class _BeneficiaryDetailsScreenState extends State<BeneficiaryDetailsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,12 +90,12 @@ class CardTile extends StatelessWidget {
|
|||||||
const Text(
|
const Text(
|
||||||
"Kangra Central Co-operative Bank",
|
"Kangra Central Co-operative Bank",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Color.fromARGB(255, 238, 237, 237),
|
color: Colors.white,
|
||||||
fontSize: 15,
|
fontSize: 15.5,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.visible,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context).cardManagement,
|
AppLocalizations.of(context).cardManagement,
|
||||||
),
|
),
|
||||||
@@ -60,7 +61,7 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
disabled: false,
|
disabled: true,
|
||||||
),
|
),
|
||||||
Divider(height: 1, color: Theme.of(context).dividerColor),
|
Divider(height: 1, color: Theme.of(context).dividerColor),
|
||||||
CardManagementTile(
|
CardManagementTile(
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context).changeCardPin,
|
AppLocalizations.of(context).cardDetails,
|
||||||
),
|
),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
@@ -66,8 +66,12 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(),
|
enabledBorder: const OutlineInputBorder(
|
||||||
focusedBorder: const OutlineInputBorder(),
|
borderSide: BorderSide(color: Colors.black),
|
||||||
|
),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
@@ -88,8 +92,13 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor:
|
fillColor:
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(),
|
enabledBorder: const OutlineInputBorder(
|
||||||
focusedBorder: const OutlineInputBorder(),
|
borderSide: BorderSide(color: Colors.black),
|
||||||
|
),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: Colors.black, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
@@ -114,8 +123,13 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor:
|
fillColor:
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(),
|
enabledBorder: const OutlineInputBorder(
|
||||||
focusedBorder: const OutlineInputBorder(),
|
borderSide: BorderSide(color: Colors.black),
|
||||||
|
),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: Colors.black, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
validator: (value) => value != null &&
|
validator: (value) => value != null &&
|
||||||
value.isNotEmpty
|
value.isNotEmpty
|
||||||
@@ -135,8 +149,12 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(),
|
enabledBorder: const OutlineInputBorder(
|
||||||
focusedBorder: const OutlineInputBorder(),
|
borderSide: BorderSide(color: Colors.black),
|
||||||
|
),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:kmobile/data/models/user.dart';
|
import 'package:kmobile/data/models/user.dart';
|
||||||
import 'package:kmobile/features/cheque/screens/cheque_enquiry_screen.dart';
|
import 'package:kmobile/features/cheque/screens/cheque_enquiry_screen.dart';
|
||||||
import 'package:kmobile/features/cheque/screens/positive_pay_screen.dart';
|
|
||||||
import 'package:kmobile/features/cheque/screens/revoke_stop_screen.dart';
|
|
||||||
import 'package:kmobile/features/cheque/screens/stop_cheque_screen.dart';
|
import 'package:kmobile/features/cheque/screens/stop_cheque_screen.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
@@ -44,6 +42,8 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
child: ChequeManagementCardTile(
|
child: ChequeManagementCardTile(
|
||||||
icon: Symbols.payments,
|
icon: Symbols.payments,
|
||||||
label: AppLocalizations.of(context).chequeEnquiryTitle,
|
label: AppLocalizations.of(context).chequeEnquiryTitle,
|
||||||
|
subtitle:
|
||||||
|
AppLocalizations.of(context).chequeEnquirySubtitle,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -61,6 +61,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
child: ChequeManagementCardTile(
|
child: ChequeManagementCardTile(
|
||||||
icon: Symbols.block_sharp,
|
icon: Symbols.block_sharp,
|
||||||
label: AppLocalizations.of(context).stopCheque,
|
label: AppLocalizations.of(context).stopCheque,
|
||||||
|
subtitle: AppLocalizations.of(context).stopChequeSubtitle,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -74,40 +75,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
|
||||||
child: ChequeManagementCardTile(
|
|
||||||
icon: Symbols.stop_circle,
|
|
||||||
label: AppLocalizations.of(context).revokeStop,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => RevokeStopChequeScreen(
|
|
||||||
users: users,
|
|
||||||
selectedIndex: selectedAccountIndex,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: ChequeManagementCardTile(
|
|
||||||
icon: Symbols.check_circle, // Using check_circle for Positive Pay
|
|
||||||
label: AppLocalizations.of(context).positivePayTitle,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => PositivePayScreen(
|
|
||||||
users: users,
|
|
||||||
selectedIndex: selectedAccountIndex,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -134,6 +101,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
class ChequeManagementCardTile extends StatelessWidget {
|
class ChequeManagementCardTile extends StatelessWidget {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String label;
|
final String label;
|
||||||
|
final String? subtitle;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final bool disable;
|
final bool disable;
|
||||||
|
|
||||||
@@ -141,6 +109,7 @@ class ChequeManagementCardTile extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.label,
|
required this.label,
|
||||||
|
this.subtitle,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.disable = false,
|
this.disable = false,
|
||||||
});
|
});
|
||||||
@@ -183,6 +152,19 @@ class ChequeManagementCardTile extends StatelessWidget {
|
|||||||
: theme.colorScheme.onSurface,
|
: theme.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (subtitle != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(
|
||||||
|
subtitle!,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
|
color: disable
|
||||||
|
? theme.disabledColor
|
||||||
|
: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/cheque_service.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PositivePayScreen extends StatefulWidget {
|
|
||||||
final List<User> users;
|
|
||||||
final int selectedIndex;
|
|
||||||
const PositivePayScreen({
|
|
||||||
super.key,
|
|
||||||
required this.users,
|
|
||||||
required this.selectedIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PositivePayScreen> createState() => _PositivePayScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PositivePayScreenState extends State<PositivePayScreen> {
|
|
||||||
User? _selectedAccount;
|
|
||||||
List<User> _filteredUsers = [];
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
final _chequeNumberController = TextEditingController();
|
|
||||||
final _chequeDateController = TextEditingController();
|
|
||||||
final _amountController = TextEditingController();
|
|
||||||
final _payeeController = TextEditingController();
|
|
||||||
final _chequeService = getIt<ChequeService>();
|
|
||||||
String? _ciFromCheque;
|
|
||||||
String? _ciToCheque;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_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) {
|
|
||||||
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
} else {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_filteredUsers.isNotEmpty) {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_loadChequeDetails();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadChequeDetails() async {
|
|
||||||
if (_selectedAccount == null) return;
|
|
||||||
|
|
||||||
String instrType;
|
|
||||||
switch (_selectedAccount!.accountType) {
|
|
||||||
case 'SA':
|
|
||||||
case 'SB':
|
|
||||||
instrType = '10';
|
|
||||||
break;
|
|
||||||
case 'CA':
|
|
||||||
instrType = '11';
|
|
||||||
break;
|
|
||||||
case 'CC':
|
|
||||||
instrType = '13';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
instrType = '10';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final data = await _chequeService.ChequeEnquiry(
|
|
||||||
accountNumber: _selectedAccount!.accountNo!,
|
|
||||||
instrType: instrType,
|
|
||||||
);
|
|
||||||
final ciCheque = data.where((cheque) => cheque.type == 'CI').toList();
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
if (ciCheque.isNotEmpty) {
|
|
||||||
_ciFromCheque = ciCheque.first.fromCheque;
|
|
||||||
_ciToCheque = ciCheque.first.toCheque;
|
|
||||||
} else {
|
|
||||||
_ciFromCheque = null;
|
|
||||||
_ciToCheque = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_ciFromCheque = null;
|
|
||||||
_ciToCheque = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_chequeNumberController.dispose();
|
|
||||||
_chequeDateController.dispose();
|
|
||||||
_amountController.dispose();
|
|
||||||
_payeeController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showResponseDialog(String title, String message) async {
|
|
||||||
return showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false, // user must tap button!
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(title),
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(message),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
child: Text(AppLocalizations.of(context).closeButton),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(
|
|
||||||
AppLocalizations.of(context).positivePay, // Will be replaced by localization
|
|
||||||
),
|
|
||||||
centerTitle: false,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: <Widget>[
|
|
||||||
const SizedBox(height: 16.0),
|
|
||||||
DropdownButtonFormField<User>(
|
|
||||||
value: _selectedAccount,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).accountNumber,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
items: _filteredUsers.map((user) {
|
|
||||||
return DropdownMenuItem<User>(
|
|
||||||
value: user,
|
|
||||||
child: Text(user.accountNo.toString()),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (User? newUser) {
|
|
||||||
setState(() {
|
|
||||||
_selectedAccount = newUser;
|
|
||||||
_loadChequeDetails();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null) {
|
|
||||||
return AppLocalizations.of(context).accountNumberRequired;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16.0),
|
|
||||||
TextFormField(
|
|
||||||
controller: _chequeNumberController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context).pleaseEnterChequeNumber;
|
|
||||||
}
|
|
||||||
final chequeNumber = int.tryParse(value);
|
|
||||||
final fromCheque = int.tryParse(_ciFromCheque ?? '');
|
|
||||||
final toCheque = int.tryParse(_ciToCheque ?? '');
|
|
||||||
if (chequeNumber == null) {
|
|
||||||
return AppLocalizations.of(context).invalidChequeNumberFormatError;
|
|
||||||
}
|
|
||||||
if (fromCheque != null && toCheque != null) {
|
|
||||||
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
|
||||||
return AppLocalizations.of(context).chequeNumberRangeError(
|
|
||||||
_ciFromCheque!, _ciToCheque!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16.0),
|
|
||||||
TextFormField(
|
|
||||||
controller: _chequeDateController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).chequeIssuedDate,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: const Icon(Icons.calendar_today),
|
|
||||||
),
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () async {
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: DateTime.now(),
|
|
||||||
firstDate: DateTime(2000),
|
|
||||||
lastDate: DateTime.now(),
|
|
||||||
);
|
|
||||||
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')}";
|
|
||||||
_chequeDateController.text = formattedDate;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context).pleaseSelectChequeIssuedDate;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16.0),
|
|
||||||
TextFormField(
|
|
||||||
controller: _payeeController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).payeeName,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16.0),
|
|
||||||
TextFormField(
|
|
||||||
controller: _amountController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).amountLabel,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
prefixText: '₹ ',
|
|
||||||
),
|
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context).pleaseEnterAmount;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32.0),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (_formKey.currentState!.validate()) {
|
|
||||||
// Process data
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => TransactionPinScreen(
|
|
||||||
onPinCompleted: (ctx, pin) async {
|
|
||||||
Navigator.pop(context);
|
|
||||||
try {
|
|
||||||
final response = await _chequeService.registerPPS(
|
|
||||||
cheque_no: _chequeNumberController.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'){
|
|
||||||
_showResponseDialog('REGISTRATION SUCCESFUL',
|
|
||||||
'Your Positive Pay Request has been registered succesfully');
|
|
||||||
}
|
|
||||||
if(responseString.contains('Cheque already registered')){
|
|
||||||
_showResponseDialog('ERROR',
|
|
||||||
'Your Request for the selected cheque number has already been registered');
|
|
||||||
}
|
|
||||||
if(responseString.contains('INCORRECT_TPIN')){
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'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') &&
|
|
||||||
errorBody['error'] == 'INCORRECT_TPIN') {
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
|
||||||
} else {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(AppLocalizations.of(context).proceedButton),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,338 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/cheque_service.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class RevokeStopMultipleChequesScreen extends StatefulWidget {
|
|
||||||
final User selectedAccount;
|
|
||||||
final String date;
|
|
||||||
final String instrType;
|
|
||||||
final String fromCheque;
|
|
||||||
final String toCheque;
|
|
||||||
|
|
||||||
const RevokeStopMultipleChequesScreen(
|
|
||||||
{super.key,
|
|
||||||
required this.selectedAccount,
|
|
||||||
required this.date,
|
|
||||||
required this.instrType,
|
|
||||||
required this.fromCheque,
|
|
||||||
required this.toCheque});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RevokeStopMultipleChequesScreen> createState() =>
|
|
||||||
_RevokeStopMultipleChequesScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RevokeStopMultipleChequesScreenState extends State<RevokeStopMultipleChequesScreen> {
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
final _stopFromChequeNoController = TextEditingController();
|
|
||||||
final _stopToChequeNoController = TextEditingController();
|
|
||||||
final _stopIssueDateController = TextEditingController();
|
|
||||||
final _stopExpiryDateController = TextEditingController();
|
|
||||||
final _stopAmountController = TextEditingController();
|
|
||||||
final _chequeService = getIt<ChequeService>();
|
|
||||||
|
|
||||||
String? _selectedComment;
|
|
||||||
final _otherCommentController = TextEditingController();
|
|
||||||
bool _showOtherCommentField = false;
|
|
||||||
final List<String> _commentOptions = [
|
|
||||||
'Cheque Found',
|
|
||||||
'Cheque Fixed',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
Future<void> _selectDate(TextEditingController controller) async {
|
|
||||||
final DateTime? picked = await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: DateTime.now(),
|
|
||||||
firstDate: DateTime.now(),
|
|
||||||
lastDate: DateTime(2101),
|
|
||||||
);
|
|
||||||
if (picked != null) {
|
|
||||||
setState(() {
|
|
||||||
controller.text =
|
|
||||||
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showResponseDialog(String title, String message) async {
|
|
||||||
return showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false, // user must tap button!
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(title),
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(message),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
child: const Text('Close'),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(AppLocalizations.of(context).revokeMultipleStops),
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 0,
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: ListTile(
|
|
||||||
leading: Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
),
|
|
||||||
title: Text(widget.selectedAccount.accountNo!),
|
|
||||||
subtitle:
|
|
||||||
Text(AppLocalizations.of(context).accountNumberTitle),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopFromChequeNoController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).fromChequeNumberHint,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.pleaseEnterChequeNumberError;
|
|
||||||
}
|
|
||||||
final chequeNumber = int.tryParse(value);
|
|
||||||
final fromCheque = int.tryParse(widget.fromCheque);
|
|
||||||
final toCheque = int.tryParse(widget.toCheque);
|
|
||||||
if (chequeNumber == null ||
|
|
||||||
fromCheque == null ||
|
|
||||||
toCheque == null) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.invalidChequeNumberFormatError;
|
|
||||||
}
|
|
||||||
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
|
||||||
return AppLocalizations.of(context).chequeNumberRangeError(
|
|
||||||
widget.fromCheque, widget.toCheque);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopToChequeNoController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).toChequeNumberHint,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.pleaseEnterChequeNumberError;
|
|
||||||
}
|
|
||||||
final chequeNumber = int.tryParse(value);
|
|
||||||
final fromCheque = int.tryParse(widget.fromCheque);
|
|
||||||
final toCheque = int.tryParse(widget.toCheque);
|
|
||||||
if (chequeNumber == null ||
|
|
||||||
fromCheque == null ||
|
|
||||||
toCheque == null) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.invalidChequeNumberFormatError;
|
|
||||||
}
|
|
||||||
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
|
||||||
return AppLocalizations.of(context).chequeNumberRangeError(
|
|
||||||
widget.fromCheque, widget.toCheque);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
initialValue: widget.instrType,
|
|
||||||
readOnly: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).instrumentTypeLabel,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopIssueDateController,
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopIssueDateController),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeIssueDate,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopIssueDateController),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.datetime,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopExpiryDateController,
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopExpiryDateController),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeExpiryDate,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopExpiryDateController),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.datetime,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopAmountController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeAmount,
|
|
||||||
prefixText: '₹ ',
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DropdownButtonFormField<String>(
|
|
||||||
value: _selectedComment,
|
|
||||||
items: _commentOptions.map((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedComment = newValue;
|
|
||||||
_showOtherCommentField = newValue == 'Other';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeComment,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_showOtherCommentField)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _otherCommentController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: "Other Reasons :",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (_formKey.currentState!.validate()) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => TransactionPinScreen(
|
|
||||||
onPinCompleted: (ctx, pin) async {
|
|
||||||
Navigator.pop(context);
|
|
||||||
try {
|
|
||||||
final response = await _chequeService.revokeStop(
|
|
||||||
accountno: widget.selectedAccount.accountNo!,
|
|
||||||
removeFromChequeNo:
|
|
||||||
_stopFromChequeNoController.text,
|
|
||||||
instrType: widget.instrType,
|
|
||||||
removeToChequeNo:
|
|
||||||
_stopToChequeNoController.text,
|
|
||||||
removeIssueDate: _stopIssueDateController.text,
|
|
||||||
removeExpiryDate: _stopExpiryDateController.text,
|
|
||||||
removeAmount: _stopAmountController.text,
|
|
||||||
removeComment: _selectedComment == 'Other'
|
|
||||||
? _otherCommentController.text
|
|
||||||
: _selectedComment ?? '',
|
|
||||||
tpin: pin,
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
|
||||||
final decodedResponse = jsonDecode(response);
|
|
||||||
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') {
|
|
||||||
String errMessage = "error";
|
|
||||||
if(code == '0172') {
|
|
||||||
errMessage = 'The selected Cheque is not stopped';
|
|
||||||
} else if(code == '0748') {
|
|
||||||
errMessage = 'The selected Cheque is already presented';
|
|
||||||
}
|
|
||||||
_showResponseDialog('Error', errMessage);
|
|
||||||
}
|
|
||||||
if(responseString.contains('INCORRECT_TPIN')){
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
|
||||||
}
|
|
||||||
} on Exception catch (e) {
|
|
||||||
try {
|
|
||||||
final errorBodyString =
|
|
||||||
e.toString().split('Exception: ')[1];
|
|
||||||
final errorBody = jsonDecode(errorBodyString);
|
|
||||||
if (errorBody.containsKey('error') &&
|
|
||||||
errorBody['error'] == 'INCORRECT_TPIN') {
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
|
||||||
} else {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(AppLocalizations.of(context).revokeStopButton),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/cheque_service.dart';
|
|
||||||
import 'package:kmobile/features/cheque/screens/revoke%20_stop_multiple_screen.dart';
|
|
||||||
import 'package:kmobile/features/cheque/screens/revoke_stop_single_screen.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class RevokeStopChequeScreen extends StatefulWidget {
|
|
||||||
final List<User> users;
|
|
||||||
final int selectedIndex;
|
|
||||||
|
|
||||||
const RevokeStopChequeScreen(
|
|
||||||
{
|
|
||||||
super.key,
|
|
||||||
required this.users,
|
|
||||||
required this.selectedIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RevokeStopChequeScreen> createState() => _RevokeStopChequeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RevokeStopChequeScreenState extends State<RevokeStopChequeScreen> {
|
|
||||||
User? _selectedAccount;
|
|
||||||
var service = getIt<ChequeService>();
|
|
||||||
bool _isLoading = true;
|
|
||||||
List<Cheque> _stCheques = [];
|
|
||||||
List<User> _filteredUsers = [];
|
|
||||||
String? _ciFromCheque;
|
|
||||||
String? _ciToCheque;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_filteredUsers = widget.users
|
|
||||||
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
|
||||||
if (_filteredUsers.isNotEmpty) {
|
|
||||||
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
} else {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_filteredUsers.isNotEmpty) {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_loadCheques();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadCheques() async {
|
|
||||||
if (_selectedAccount == null) {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = false;
|
|
||||||
_stCheques = [];
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState(() {
|
|
||||||
_isLoading = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
String instrType;
|
|
||||||
switch (_selectedAccount!.accountType) {
|
|
||||||
case 'SA':
|
|
||||||
case 'SB':
|
|
||||||
instrType = '10';
|
|
||||||
break;
|
|
||||||
case 'CA':
|
|
||||||
instrType = '11';
|
|
||||||
break;
|
|
||||||
case 'CC':
|
|
||||||
instrType = '13';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
instrType = '10';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final data = await service.ChequeEnquiry(
|
|
||||||
accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
|
|
||||||
final stCheques = data.where((cheque) => cheque.type == 'ST').toList();
|
|
||||||
final ciCheque = data.where((cheque) => cheque.type == 'CI').toList();
|
|
||||||
setState(() {
|
|
||||||
_stCheques = stCheques;
|
|
||||||
if (ciCheque.isNotEmpty) {
|
|
||||||
_ciFromCheque = ciCheque.first.fromCheque;
|
|
||||||
_ciToCheque = ciCheque.first.toCheque;
|
|
||||||
} else {
|
|
||||||
_ciFromCheque = null;
|
|
||||||
_ciToCheque = null;
|
|
||||||
}
|
|
||||||
_isLoading = false;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = false;
|
|
||||||
_stCheques = [];
|
|
||||||
});
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Failed to fetch cheque status: ${e.toString()}'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getAccountTypeDisplayName(String accountType) {
|
|
||||||
switch (accountType.toLowerCase()) {
|
|
||||||
case 'sa':
|
|
||||||
return AppLocalizations.of(context).savingsAccount;
|
|
||||||
case 'sb':
|
|
||||||
return AppLocalizations.of(context).savingsAccount;
|
|
||||||
case 'ca':
|
|
||||||
return "Current Account";
|
|
||||||
case 'cc':
|
|
||||||
return "Cash Credit Account";
|
|
||||||
default:
|
|
||||||
return accountType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(AppLocalizations.of(context).revokeStop),
|
|
||||||
centerTitle: false,
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(children: [
|
|
||||||
Card(
|
|
||||||
elevation: 4,
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context).accountNumber,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold, fontSize: 18),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
if (_selectedAccount != null)
|
|
||||||
Expanded(
|
|
||||||
child: DropdownButton<User>(
|
|
||||||
value: _selectedAccount,
|
|
||||||
onChanged: (User? newUser) {
|
|
||||||
if (newUser != null) {
|
|
||||||
setState(() {
|
|
||||||
_selectedAccount = newUser;
|
|
||||||
_loadCheques();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
items: _filteredUsers.map((user) {
|
|
||||||
return DropdownMenuItem<User>(
|
|
||||||
value: user,
|
|
||||||
child: Text(user.accountNo.toString()),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Text(AppLocalizations.of(context).noAccountsFound),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Card(
|
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
|
||||||
elevation: 4,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
if (_selectedAccount != null &&
|
|
||||||
_stCheques.isNotEmpty) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) =>
|
|
||||||
RevokeStopSingleChequeScreen(
|
|
||||||
selectedAccount: _selectedAccount!,
|
|
||||||
date: _stCheques.first.Date!,
|
|
||||||
instrType: _stCheques.first.InstrType!,
|
|
||||||
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
|
||||||
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text("No stopped cheques present"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context).revokeSingleStopTitle,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onPrimaryContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Card(
|
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
|
||||||
elevation: 4,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
if (_selectedAccount != null &&
|
|
||||||
_stCheques.isNotEmpty) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) =>
|
|
||||||
RevokeStopMultipleChequesScreen(
|
|
||||||
selectedAccount: _selectedAccount!,
|
|
||||||
date: _stCheques.first.Date!,
|
|
||||||
instrType: _stCheques.first.InstrType!,
|
|
||||||
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
|
||||||
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(AppLocalizations.of(context)
|
|
||||||
.pleaseSelectAccountFirst),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context).revokeMultipleStops,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSecondaryContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Expanded(
|
|
||||||
child: _isLoading
|
|
||||||
? const Center(child: CircularProgressIndicator())
|
|
||||||
: _stCheques.isEmpty
|
|
||||||
? Center(
|
|
||||||
child: Text(AppLocalizations.of(context)
|
|
||||||
.noChequeIssuedStatus))
|
|
||||||
: ListView.builder(
|
|
||||||
itemCount: _stCheques.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return _buildSTTile(context, _stCheques[index]);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
IgnorePointer(
|
|
||||||
child: Center(
|
|
||||||
child: Opacity(
|
|
||||||
opacity: 0.07, // Reduced opacity
|
|
||||||
child: ClipOval(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
width: 200, // Adjust size as needed
|
|
||||||
height: 200, // Adjust size as needed
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSTTile(BuildContext context, Cheque cheque) {
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
vertical: 8.0,
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(AppLocalizations.of(context).stopChequeLabel,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
_buildInfoRow('From Cheque:', cheque.fromCheque),
|
|
||||||
_buildInfoRow('To Cheque:', cheque.toCheque),
|
|
||||||
_buildInfoRow('Account Type:',
|
|
||||||
_getAccountTypeDisplayName(_selectedAccount!.accountType!)),
|
|
||||||
_buildInfoRow('Branch Code:', cheque.branchCode),
|
|
||||||
_buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
|
|
||||||
_buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
|
|
||||||
_buildInfoRow('Cheques Count:', cheque.Chequescount),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildInfoRow(String label, String? value) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
|
||||||
Text(value ?? ''),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/cheque_service.dart';
|
|
||||||
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class RevokeStopSingleChequeScreen extends StatefulWidget {
|
|
||||||
final User selectedAccount;
|
|
||||||
final String date;
|
|
||||||
final String instrType;
|
|
||||||
final String fromCheque;
|
|
||||||
final String toCheque;
|
|
||||||
|
|
||||||
const RevokeStopSingleChequeScreen(
|
|
||||||
{super.key,
|
|
||||||
required this.selectedAccount,
|
|
||||||
required this.date,
|
|
||||||
required this.instrType,
|
|
||||||
required this.fromCheque,
|
|
||||||
required this.toCheque});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RevokeStopSingleChequeScreen> createState() => _RevokeStopSingleChequeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RevokeStopSingleChequeScreenState extends State<RevokeStopSingleChequeScreen> {
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
final _stopFromChequeNoController = TextEditingController();
|
|
||||||
final _stopIssueDateController = TextEditingController();
|
|
||||||
final _stopExpiryDateController = TextEditingController();
|
|
||||||
final _stopAmountController = TextEditingController();
|
|
||||||
final _chequeService = getIt<ChequeService>();
|
|
||||||
|
|
||||||
String? _selectedComment;
|
|
||||||
final _otherCommentController = TextEditingController();
|
|
||||||
bool _showOtherCommentField = false;
|
|
||||||
final List<String> _commentOptions = [
|
|
||||||
'Cheque Found',
|
|
||||||
'Cheque Fixed',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
Future<void> _selectDate(TextEditingController controller) async {
|
|
||||||
final DateTime? picked = await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: DateTime.now(),
|
|
||||||
firstDate: DateTime.now(),
|
|
||||||
lastDate: DateTime(2101),
|
|
||||||
);
|
|
||||||
if (picked != null) {
|
|
||||||
setState(() {
|
|
||||||
controller.text =
|
|
||||||
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showResponseDialog(String title, String message) async {
|
|
||||||
return showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false, // user must tap button!
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: Text(title),
|
|
||||||
content: SingleChildScrollView(
|
|
||||||
child: ListBody(
|
|
||||||
children: <Widget>[
|
|
||||||
Text(message),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
TextButton(
|
|
||||||
child: Text(AppLocalizations.of(context).closeButton),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(AppLocalizations.of(context).revokeSingleStopTitle)),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
child: ListView(
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 0,
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: ListTile(
|
|
||||||
leading: Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
),
|
|
||||||
title: Text(widget.selectedAccount.accountNo!),
|
|
||||||
subtitle:
|
|
||||||
Text(AppLocalizations.of(context).accountNumberLabel),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopFromChequeNoController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.pleaseEnterChequeNumberError;
|
|
||||||
}
|
|
||||||
final chequeNumber = int.tryParse(value);
|
|
||||||
final fromCheque = int.tryParse(widget.fromCheque);
|
|
||||||
final toCheque = int.tryParse(widget.toCheque);
|
|
||||||
if (chequeNumber == null ||
|
|
||||||
fromCheque == null ||
|
|
||||||
toCheque == null) {
|
|
||||||
return AppLocalizations.of(context)
|
|
||||||
.invalidChequeNumberFormatError;
|
|
||||||
}
|
|
||||||
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
|
||||||
return AppLocalizations.of(context).chequeNumberRangeError(
|
|
||||||
widget.fromCheque, widget.toCheque);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
initialValue: widget.instrType,
|
|
||||||
readOnly: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).instrumentTypeLabel,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopIssueDateController,
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopIssueDateController),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeIssueDate,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopIssueDateController),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.datetime,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopExpiryDateController,
|
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopExpiryDateController),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeExpiryDate,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopExpiryDateController),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.datetime,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
TextFormField(
|
|
||||||
controller: _stopAmountController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeAmount,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DropdownButtonFormField<String>(
|
|
||||||
value: _selectedComment,
|
|
||||||
items: _commentOptions.map((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedComment = newValue;
|
|
||||||
_showOtherCommentField = newValue == 'Other';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: AppLocalizations.of(context).revokeComment,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_showOtherCommentField)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _otherCommentController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: "Other Reasons :",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (_formKey.currentState!.validate()) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => TransactionPinScreen(
|
|
||||||
onPinCompleted: (ctx, pin) async {
|
|
||||||
Navigator.pop(context);
|
|
||||||
try {
|
|
||||||
final response = await _chequeService.revokeStop(
|
|
||||||
accountno: widget.selectedAccount.accountNo!,
|
|
||||||
removeFromChequeNo:
|
|
||||||
_stopFromChequeNoController.text,
|
|
||||||
instrType: widget.instrType,
|
|
||||||
removeToChequeNo:
|
|
||||||
_stopFromChequeNoController.text,
|
|
||||||
removeIssueDate: _stopIssueDateController.text,
|
|
||||||
removeExpiryDate: _stopExpiryDateController.text,
|
|
||||||
removeAmount: _stopAmountController.text,
|
|
||||||
removeComment: _selectedComment == 'Other'
|
|
||||||
? _otherCommentController.text
|
|
||||||
: _selectedComment ?? '',
|
|
||||||
tpin: pin,
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
|
||||||
final decodedResponse = jsonDecode(response);
|
|
||||||
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') {
|
|
||||||
String errMessage = "error";
|
|
||||||
if(code == '0172') {
|
|
||||||
errMessage = 'The selected Cheque is not stopped';
|
|
||||||
} else if(code == '0748') {
|
|
||||||
errMessage = 'The selected Cheque is already presented';
|
|
||||||
}
|
|
||||||
_showResponseDialog('Error', errMessage);
|
|
||||||
}
|
|
||||||
if(responseString.contains('INCORRECT_TPIN')){
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'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') &&
|
|
||||||
errorBody['error'] == 'INCORRECT_TPIN') {
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
|
||||||
} else {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
} catch (_) {
|
|
||||||
_showResponseDialog(
|
|
||||||
'Error', 'Internal Server Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Text(AppLocalizations.of(context).revokeStopButton),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,19 +34,9 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
final _stopIssueDateController = TextEditingController();
|
final _stopIssueDateController = TextEditingController();
|
||||||
final _stopExpiryDateController = TextEditingController();
|
final _stopExpiryDateController = TextEditingController();
|
||||||
final _stopAmountController = TextEditingController();
|
final _stopAmountController = TextEditingController();
|
||||||
|
final _stopCommentController = TextEditingController();
|
||||||
final _chequeService = getIt<ChequeService>();
|
final _chequeService = getIt<ChequeService>();
|
||||||
|
|
||||||
String? _selectedComment;
|
|
||||||
final _otherCommentController = TextEditingController();
|
|
||||||
bool _showOtherCommentField = false;
|
|
||||||
final List<String> _commentOptions = [
|
|
||||||
'Cheque Lost',
|
|
||||||
'Cheque Stolen',
|
|
||||||
'Cheque Missing',
|
|
||||||
'Cheque Damaged',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
String _formatDate(String dateString) {
|
String _formatDate(String dateString) {
|
||||||
if (dateString.length != 8) {
|
if (dateString.length != 8) {
|
||||||
return dateString; // Return as is if not in expected ddmmyyyy format
|
return dateString; // Return as is if not in expected ddmmyyyy format
|
||||||
@@ -61,21 +51,6 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _selectDate(TextEditingController controller) async {
|
|
||||||
final DateTime? picked = await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: DateTime.now(),
|
|
||||||
firstDate: DateTime.now(),
|
|
||||||
lastDate: DateTime(2101),
|
|
||||||
);
|
|
||||||
if (picked != null) {
|
|
||||||
setState(() {
|
|
||||||
controller.text =
|
|
||||||
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showResponseDialog(String title, String message) async {
|
Future<void> _showResponseDialog(String title, String message) async {
|
||||||
return showDialog<void>(
|
return showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -135,7 +110,6 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).fromChequeNumberHint,
|
labelText: AppLocalizations.of(context).fromChequeNumberHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
@@ -165,7 +139,6 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).toChequeNumberHint,
|
labelText: AppLocalizations.of(context).toChequeNumberHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
@@ -201,30 +174,18 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _stopIssueDateController,
|
controller: _stopIssueDateController,
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopIssueDateController),
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopIssueDateHint,
|
labelText: AppLocalizations.of(context).stopIssueDateHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopIssueDateController),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.datetime,
|
keyboardType: TextInputType.datetime,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _stopExpiryDateController,
|
controller: _stopExpiryDateController,
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopExpiryDateController),
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopExpiryDateHint,
|
labelText: AppLocalizations.of(context).stopExpiryDateHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopExpiryDateController),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.datetime,
|
keyboardType: TextInputType.datetime,
|
||||||
),
|
),
|
||||||
@@ -238,39 +199,13 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
DropdownButtonFormField<String>(
|
TextFormField(
|
||||||
value: _selectedComment,
|
controller: _stopCommentController,
|
||||||
items: _commentOptions.map((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedComment = newValue;
|
|
||||||
_showOtherCommentField = newValue == 'Other';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopCommentHint,
|
labelText: AppLocalizations.of(context).stopCommentHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_showOtherCommentField)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _otherCommentController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: "Other Reasons :",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
initialValue: _formatDate(widget.date),
|
initialValue: _formatDate(widget.date),
|
||||||
@@ -301,34 +236,23 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
stopIssueDate: _stopIssueDateController.text,
|
stopIssueDate: _stopIssueDateController.text,
|
||||||
stopExpiryDate: _stopExpiryDateController.text,
|
stopExpiryDate: _stopExpiryDateController.text,
|
||||||
stopAmount: _stopAmountController.text,
|
stopAmount: _stopAmountController.text,
|
||||||
stopComment: _selectedComment == 'Other'
|
stopComment: _stopCommentController.text,
|
||||||
? _otherCommentController.text
|
|
||||||
: _selectedComment ?? '',
|
|
||||||
chequeIssueDate: widget.date,
|
chequeIssueDate: widget.date,
|
||||||
tpin: pin,
|
tpin: pin,
|
||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final decodedResponse = jsonDecode(response);
|
final decodedResponse = jsonDecode(response);
|
||||||
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
|
||||||
final status = decodedResponse['status'];
|
final status = decodedResponse['status'];
|
||||||
final message = decodedResponse['message'];
|
final message = decodedResponse['message'];
|
||||||
final code = decodedResponse['code'];
|
|
||||||
if (status == 'SUCCESS') {
|
if (status == 'SUCCESS') {
|
||||||
_showResponseDialog('Success', message);
|
_showResponseDialog('Success', message);
|
||||||
} if (status == 'ERROR') {
|
} else {
|
||||||
String errMessage = "error";
|
_showResponseDialog('Error', message);
|
||||||
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')){
|
|
||||||
_showResponseDialog('Invalid TPIN',
|
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
|
||||||
}
|
}
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
|
print('inside catch block');
|
||||||
|
print(e.toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final errorBodyString =
|
final errorBodyString =
|
||||||
e.toString().split('Exception: ')[1];
|
e.toString().split('Exception: ')[1];
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
import 'package:kmobile/data/models/user.dart';
|
||||||
import 'package:kmobile/di/injection.dart';
|
import 'package:kmobile/di/injection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -32,19 +31,9 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
final _stopIssueDateController = TextEditingController();
|
final _stopIssueDateController = TextEditingController();
|
||||||
final _stopExpiryDateController = TextEditingController();
|
final _stopExpiryDateController = TextEditingController();
|
||||||
final _stopAmountController = TextEditingController();
|
final _stopAmountController = TextEditingController();
|
||||||
|
final _stopCommentController = TextEditingController();
|
||||||
final _chequeService = getIt<ChequeService>();
|
final _chequeService = getIt<ChequeService>();
|
||||||
|
|
||||||
String? _selectedComment;
|
|
||||||
final _otherCommentController = TextEditingController();
|
|
||||||
bool _showOtherCommentField = false;
|
|
||||||
final List<String> _commentOptions = [
|
|
||||||
'Cheque Lost',
|
|
||||||
'Cheque Stolen',
|
|
||||||
'Cheque Missing',
|
|
||||||
'Cheque Damaged',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
String _formatDate(String dateString) {
|
String _formatDate(String dateString) {
|
||||||
if (dateString.length != 8) {
|
if (dateString.length != 8) {
|
||||||
return dateString; // Return as is if not in expected ddmmyyyy format
|
return dateString; // Return as is if not in expected ddmmyyyy format
|
||||||
@@ -59,21 +48,6 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _selectDate(TextEditingController controller) async {
|
|
||||||
final DateTime? picked = await showDatePicker(
|
|
||||||
context: context,
|
|
||||||
initialDate: DateTime.now(),
|
|
||||||
firstDate: DateTime.now(),
|
|
||||||
lastDate: DateTime(2101),
|
|
||||||
);
|
|
||||||
if (picked != null) {
|
|
||||||
setState(() {
|
|
||||||
controller.text =
|
|
||||||
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showResponseDialog(String title, String message) async {
|
Future<void> _showResponseDialog(String title, String message) async {
|
||||||
return showDialog<void>(
|
return showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -133,7 +107,6 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
errorMaxLines: 2,
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
@@ -169,30 +142,18 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _stopIssueDateController,
|
controller: _stopIssueDateController,
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopIssueDateController),
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopIssueDateLabel,
|
labelText: AppLocalizations.of(context).stopIssueDateLabel,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopIssueDateController),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.datetime,
|
keyboardType: TextInputType.datetime,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _stopExpiryDateController,
|
controller: _stopExpiryDateController,
|
||||||
readOnly: true,
|
|
||||||
onTap: () => _selectDate(_stopExpiryDateController),
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopExpiryDateLabel,
|
labelText: AppLocalizations.of(context).stopExpiryDateLabel,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: const Icon(Icons.calendar_today),
|
|
||||||
onPressed: () => _selectDate(_stopExpiryDateController),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.datetime,
|
keyboardType: TextInputType.datetime,
|
||||||
),
|
),
|
||||||
@@ -206,39 +167,13 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
DropdownButtonFormField<String>(
|
TextFormField(
|
||||||
value: _selectedComment,
|
controller: _stopCommentController,
|
||||||
items: _commentOptions.map((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedComment = newValue;
|
|
||||||
_showOtherCommentField = newValue == 'Other';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: AppLocalizations.of(context).stopCommentHint,
|
labelText: AppLocalizations.of(context).stopCommentHint,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_showOtherCommentField)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _otherCommentController,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: "Other Reasons :",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
initialValue: _formatDate(widget.date),
|
initialValue: _formatDate(widget.date),
|
||||||
@@ -270,39 +205,28 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
stopIssueDate: _stopIssueDateController.text,
|
stopIssueDate: _stopIssueDateController.text,
|
||||||
stopExpiryDate: _stopExpiryDateController.text,
|
stopExpiryDate: _stopExpiryDateController.text,
|
||||||
stopAmount: _stopAmountController.text,
|
stopAmount: _stopAmountController.text,
|
||||||
stopComment: _selectedComment == 'Other'
|
stopComment: _stopCommentController.text,
|
||||||
? _otherCommentController.text
|
|
||||||
: _selectedComment ?? '',
|
|
||||||
chequeIssueDate: widget.date,
|
chequeIssueDate: widget.date,
|
||||||
tpin: pin,
|
tpin: pin,
|
||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final decodedResponse = jsonDecode(response);
|
final decodedResponse = jsonDecode(response);
|
||||||
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
|
||||||
final status = decodedResponse['status'];
|
final status = decodedResponse['status'];
|
||||||
final message = decodedResponse['message'];
|
final message = decodedResponse['message'];
|
||||||
final code = decodedResponse['code'];
|
|
||||||
if (status == 'SUCCESS') {
|
if (status == 'SUCCESS') {
|
||||||
_showResponseDialog('Success', message);
|
_showResponseDialog('Success', message);
|
||||||
} if (status == 'ERROR') {
|
} else {
|
||||||
String errMessage = "error";
|
_showResponseDialog('Error', message);
|
||||||
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')){
|
} on Exception catch (e) {
|
||||||
_showResponseDialog('Invalid TPIN',
|
print('inside catch block');
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
print(e.toString());
|
||||||
}
|
|
||||||
} on DioException catch (e) {
|
|
||||||
try {
|
try {
|
||||||
final errorBodyString =
|
final errorBodyString =
|
||||||
e.toString().split('Exception: ')[1];
|
e.toString().split('Exception: ')[1];
|
||||||
final errorBody = jsonDecode(errorBodyString);
|
final errorBody = jsonDecode(errorBodyString);
|
||||||
if (errorBody.containsKey('error') &&
|
if (errorBody.containsKey('error') &&
|
||||||
errorBody['error'] == 'INCORRECT_TPIN') {
|
errorBody['error'] == 'INCORRECT_TPIN') {
|
||||||
_showResponseDialog('Invalid TPIN',
|
_showResponseDialog('Invalid TPIN',
|
||||||
'The TPIN you entered is incorrect. Please try again.');
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import 'package:kmobile/features/auth/controllers/auth_state.dart';
|
|||||||
import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart';
|
import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart';
|
||||||
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
|
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
|
||||||
import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart';
|
import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart';
|
||||||
|
import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart';
|
||||||
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart';
|
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart';
|
||||||
import 'package:kmobile/features/profile/profile_screen.dart';
|
import 'package:kmobile/features/profile/profile_screen.dart';
|
||||||
import 'package:kmobile/features/quick_pay/screens/quick_pay_screen.dart';
|
import 'package:kmobile/features/quick_pay/screens/quick_pay_screen.dart';
|
||||||
import 'package:kmobile/features/service/screens/branch_locator_screen.dart';
|
import 'package:kmobile/features/service/screens/branch_locator_screen.dart';
|
||||||
import 'package:kmobile/features/yojna/screens/gov_scheme_screen.dart';
|
|
||||||
import 'package:kmobile/security/secure_storage.dart';
|
import 'package:kmobile/security/secure_storage.dart';
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
@@ -636,14 +636,13 @@ class _DashboardScreenState extends State<DashboardScreen>
|
|||||||
ManageBeneficiariesScreen(
|
ManageBeneficiariesScreen(
|
||||||
customerName: currAccount.name!)));
|
customerName: currAccount.name!)));
|
||||||
}, disable: false),
|
}, disable: false),
|
||||||
_buildQuickLink(Symbols.family_group,
|
_buildQuickLink(Symbols.support_agent,
|
||||||
AppLocalizations.of(context).governmentSchemes, () {
|
AppLocalizations.of(context).contactUs, () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
GovSchemeScreen(users: users,
|
const EnquiryScreen()));
|
||||||
selectedIndex: selectedAccountIndex)));
|
|
||||||
}),
|
}),
|
||||||
_buildQuickLink(
|
_buildQuickLink(
|
||||||
Symbols.checkbook,
|
Symbols.checkbook,
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import 'package:kmobile/features/account_opening/screens/account_opening_screen.dart';
|
|
||||||
import 'package:kmobile/features/card/screens/card_management_screen.dart';
|
|
||||||
import 'package:kmobile/features/service/screens/atm_locator_screen.dart';
|
import 'package:kmobile/features/service/screens/atm_locator_screen.dart';
|
||||||
import 'package:kmobile/features/service/screens/enquiry_screen.dart';
|
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
@@ -46,6 +43,7 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ServiceManagementTile(
|
child: ServiceManagementTile(
|
||||||
icon: Symbols.question_mark,
|
icon: Symbols.question_mark,
|
||||||
@@ -59,6 +57,7 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ServiceManagementTile(
|
child: ServiceManagementTile(
|
||||||
icon: Symbols.location_pin,
|
icon: Symbols.location_pin,
|
||||||
@@ -72,46 +71,7 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Expanded(
|
// No Spacer() needed here as Expanded children will fill space
|
||||||
// child: ServiceManagementTile(
|
|
||||||
// icon: Symbols.box,
|
|
||||||
// label: "Account Opening",
|
|
||||||
// onTap: () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => const AccountOpeningScreen()));
|
|
||||||
// },
|
|
||||||
// disabled: false,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Expanded(
|
|
||||||
// child: ServiceManagementTile(
|
|
||||||
// icon: Symbols.credit_card,
|
|
||||||
// label: AppLocalizations.of(context).cardManagement,
|
|
||||||
// onTap: () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => const CardManagementScreen()));
|
|
||||||
// },
|
|
||||||
// disabled: false,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
Expanded(
|
|
||||||
child: ServiceManagementTile(
|
|
||||||
icon: Symbols.support_agent,
|
|
||||||
label: AppLocalizations.of(context).contactUs,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const EnquiryScreen()));
|
|
||||||
},
|
|
||||||
disabled: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// No Spacer() needed here as Expanded children will fill space
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -162,33 +122,32 @@ class ServiceManagementTile extends StatelessWidget {
|
|||||||
onTap:
|
onTap:
|
||||||
disabled ? null : onTap, // Disable InkWell if the tile is disabled
|
disabled ? null : onTap, // Disable InkWell if the tile is disabled
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
child: Center(
|
child: Padding(
|
||||||
child: SingleChildScrollView(
|
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 48, // Make icon larger
|
size: 48, // Make icon larger
|
||||||
color:
|
color:
|
||||||
disabled ? theme.disabledColor : theme.colorScheme.primary,
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class APYScreen extends StatefulWidget {
|
|
||||||
final List<User> users;
|
|
||||||
final int selectedIndex;
|
|
||||||
const APYScreen({
|
|
||||||
super.key,
|
|
||||||
required this.users,
|
|
||||||
required this.selectedIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<APYScreen> createState() => _APYScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _APYScreenState extends State<APYScreen> {
|
|
||||||
User? _selectedAccount;
|
|
||||||
List<User> _filteredUsers = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_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) {
|
|
||||||
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
} else {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_filteredUsers.isNotEmpty) {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.apyRegistration),
|
|
||||||
centerTitle: false,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 2,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text(
|
|
||||||
l10n.apyDescription,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Card(
|
|
||||||
elevation: 2,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
DropdownButtonFormField<User>(
|
|
||||||
value: _selectedAccount,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: l10n.accountNumber,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 20, horizontal: 12),
|
|
||||||
),
|
|
||||||
items: _filteredUsers.map((user) {
|
|
||||||
return DropdownMenuItem<User>(
|
|
||||||
value: user,
|
|
||||||
child: Text(user.accountNo.toString()),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (User? newUser) {
|
|
||||||
setState(() {
|
|
||||||
_selectedAccount = newUser;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null) {
|
|
||||||
return l10n.accountNumberRequired;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/data/models/user.dart';
|
|
||||||
import 'package:kmobile/features/yojna/screens/apy_screen.dart';
|
|
||||||
import 'package:kmobile/features/yojna/screens/pm_main_screen.dart';
|
|
||||||
import '../../../l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class GovSchemeScreen extends StatefulWidget {
|
|
||||||
final List<User> users;
|
|
||||||
final int selectedIndex;
|
|
||||||
const GovSchemeScreen({
|
|
||||||
super.key,
|
|
||||||
required this.users,
|
|
||||||
required this.selectedIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<GovSchemeScreen> createState() => _GovSchemeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GovSchemeScreenState extends State<GovSchemeScreen> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.governmentSchemes),
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: GovSchemeTile(
|
|
||||||
logoText: "PMJJBY/PMSBY",
|
|
||||||
label: l10n.pradhanMantriYojana,
|
|
||||||
subtitle: l10n.enrollPMJJBYPMSBY,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => PMMainScreen(
|
|
||||||
users: widget.users,
|
|
||||||
selectedIndex: widget.selectedIndex,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Expanded(
|
|
||||||
// child: GovSchemeTile(
|
|
||||||
// logoText: "APY",
|
|
||||||
// label: l10n.registerForAtalPensionYojana,
|
|
||||||
// subtitle: l10n.secureYourFutureAPY,
|
|
||||||
// onTap: () {
|
|
||||||
// Navigator.push(
|
|
||||||
// context,
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => APYScreen(
|
|
||||||
// users: widget.users,
|
|
||||||
// selectedIndex: widget.selectedIndex,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );// Action for APY will be added later
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IgnorePointer(
|
|
||||||
child: Center(
|
|
||||||
child: Opacity(
|
|
||||||
opacity: 0.07,
|
|
||||||
child: ClipOval(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/logo.png',
|
|
||||||
width: 200,
|
|
||||||
height: 200,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GovSchemeTile extends StatelessWidget {
|
|
||||||
final String logoText;
|
|
||||||
final String label;
|
|
||||||
final String? subtitle;
|
|
||||||
final VoidCallback onTap;
|
|
||||||
final bool disable;
|
|
||||||
|
|
||||||
const GovSchemeTile({
|
|
||||||
super.key,
|
|
||||||
required this.logoText,
|
|
||||||
required this.label,
|
|
||||||
this.subtitle,
|
|
||||||
required this.onTap,
|
|
||||||
this.disable = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
),
|
|
||||||
elevation: 4,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: disable ? null : onTap,
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 36.0, horizontal: 16.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
logoText,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: logoText.length > 5 ? 28 : 40,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: theme.colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.headlineSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: disable
|
|
||||||
? theme.disabledColor
|
|
||||||
: theme.colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (subtitle != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Text(
|
|
||||||
subtitle!,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: disable
|
|
||||||
? theme.disabledColor
|
|
||||||
: theme.colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
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/pmjjby_screen.dart';
|
|
||||||
import 'package:kmobile/features/yojna/screens/pmsby_screen.dart';
|
|
||||||
import 'package:kmobile/features/yojna/screens/pmjjby_enquiry_screen.dart';
|
|
||||||
import 'package:kmobile/features/yojna/screens/pmsby_enquiry_screen.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PMMainScreen extends StatefulWidget {
|
|
||||||
final List<User> users;
|
|
||||||
final int selectedIndex;
|
|
||||||
const PMMainScreen({
|
|
||||||
super.key,
|
|
||||||
required this.users,
|
|
||||||
required this.selectedIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PMMainScreen> createState() => _PMMainScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PMMainScreenState extends State<PMMainScreen> {
|
|
||||||
User? _selectedAccount;
|
|
||||||
List<User> _filteredUsers = [];
|
|
||||||
String? _selectedScheme;
|
|
||||||
|
|
||||||
List<String> _getSchemes(AppLocalizations l10n) => [
|
|
||||||
l10n.pmjjbyFull,
|
|
||||||
l10n.pmsbyFull,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_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) {
|
|
||||||
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
} else {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_selectedAccount = widget.users[widget.selectedIndex];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_filteredUsers.isNotEmpty) {
|
|
||||||
_selectedAccount = _filteredUsers.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleCreate() async {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
if (_selectedAccount == null) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.pleaseSelectAccountNumber)),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_selectedScheme == null) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.pleaseSelectSchemeFirst)),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String schemeCode = (_selectedScheme == l10n.pmjjbyFull) ? '02' : '01';
|
|
||||||
|
|
||||||
// Show loading
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Row(
|
|
||||||
children: [
|
|
||||||
const CircularProgressIndicator(),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Text(l10n.fetchingDetails),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
duration: const Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await getIt<YojnaService>().fetchpmydetails(
|
|
||||||
scheme: schemeCode,
|
|
||||||
action: 'C',
|
|
||||||
accountno: _selectedAccount!.accountNo!,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
Map<String, dynamic>? data;
|
|
||||||
if (response is Map<String, dynamic>) {
|
|
||||||
data = response;
|
|
||||||
} else if (response is List && response.isNotEmpty && response[0] is Map<String, dynamic>) {
|
|
||||||
data = response[0] as Map<String, dynamic>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != null && data.isNotEmpty) {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) {
|
|
||||||
if (_selectedScheme == l10n.pmjjbyFull) {
|
|
||||||
return PMJJBYScreen(initialData: data!);
|
|
||||||
} else {
|
|
||||||
return PMSBYScreen(initialData: data!);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.failedToFetchDetails)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleEnquiry() {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
if (_selectedAccount == null) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.pleaseSelectAccountNumber)),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_selectedScheme == null) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.pleaseSelectSchemeFirst)),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) {
|
|
||||||
if (_selectedScheme == l10n.pmjjbyFull) {
|
|
||||||
return PMJJBYEnquiryScreen(cifNumber: _selectedAccount!.cifNumber);
|
|
||||||
} else {
|
|
||||||
return PMSBYEnquiryScreen(cifNumber: _selectedAccount!.cifNumber);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.pradhanMantriYojana),
|
|
||||||
centerTitle: false,
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 2,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text(
|
|
||||||
l10n.pmjjbyPmsbyDescription,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Card(
|
|
||||||
elevation: 2,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
DropdownButtonFormField<User>(
|
|
||||||
value: _selectedAccount,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: l10n.accountNumber,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 20, horizontal: 12),
|
|
||||||
),
|
|
||||||
items: _filteredUsers.map((user) {
|
|
||||||
return DropdownMenuItem<User>(
|
|
||||||
value: user,
|
|
||||||
child: Text(user.accountNo.toString()),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (User? newUser) {
|
|
||||||
setState(() {
|
|
||||||
_selectedAccount = newUser;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null) {
|
|
||||||
return l10n.accountNumberRequired;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DropdownButtonFormField<String>(
|
|
||||||
value: _selectedScheme,
|
|
||||||
isExpanded: true,
|
|
||||||
isDense: false,
|
|
||||||
itemHeight: null,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: l10n.selectScheme,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
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();
|
|
||||||
},
|
|
||||||
items: schemes.map((String scheme) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: scheme,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
|
||||||
child: Text(
|
|
||||||
scheme,
|
|
||||||
style: const TextStyle(fontSize: 15),
|
|
||||||
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedScheme = newValue;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: _handleCreate,
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).colorScheme.primaryContainer,
|
|
||||||
foregroundColor:
|
|
||||||
Theme.of(context).colorScheme.onPrimaryContainer,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
l10n.create,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Expanded(
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: _handleEnquiry,
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).colorScheme.primaryContainer,
|
|
||||||
foregroundColor:
|
|
||||||
Theme.of(context).colorScheme.onPrimaryContainer,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
l10n.enquiry,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/yojna_service.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PMJJBYEnquiryScreen extends StatefulWidget {
|
|
||||||
final String? cifNumber;
|
|
||||||
|
|
||||||
const PMJJBYEnquiryScreen({
|
|
||||||
super.key,
|
|
||||||
required this.cifNumber,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PMJJBYEnquiryScreen> createState() => _PMJJBYEnquiryScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PMJJBYEnquiryScreenState extends State<PMJJBYEnquiryScreen> {
|
|
||||||
String? _selectedFinancialYear;
|
|
||||||
bool _isLoading = false;
|
|
||||||
Map<String, dynamic>? _enquiryData;
|
|
||||||
String? _errorMessage;
|
|
||||||
|
|
||||||
final List<String> _financialYears = [
|
|
||||||
'2021-2022',
|
|
||||||
'2022-2023',
|
|
||||||
'2023-2024',
|
|
||||||
'2024-2025',
|
|
||||||
'2025-2026',
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_selectedFinancialYear = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _fetchEnquiryData() async {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
if (_selectedFinancialYear == null || widget.cifNumber == null) return;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_isLoading = true;
|
|
||||||
_enquiryData = null;
|
|
||||||
_errorMessage = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
final formattedYear = _selectedFinancialYear!.replaceAll('-', '');
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await getIt<YojnaService>().enquiry(
|
|
||||||
scheme: '02',
|
|
||||||
action: 'E',
|
|
||||||
financialyear: formattedYear,
|
|
||||||
customerno: widget.cifNumber,
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
if (response is Map<String, dynamic>) {
|
|
||||||
if (response['status'] == 'FAILED') {
|
|
||||||
_errorMessage = response['message'] ?? l10n.noRecordFound;
|
|
||||||
} else {
|
|
||||||
_enquiryData = response;
|
|
||||||
}
|
|
||||||
} else if (response is List && response.isNotEmpty) {
|
|
||||||
_enquiryData = response[0] as Map<String, dynamic>;
|
|
||||||
} else {
|
|
||||||
_errorMessage = l10n.noDataFoundYear;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
setState(() {
|
|
||||||
_errorMessage = l10n.genericError(e.toString());
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.pmjjbyDetails),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
leading: const Icon(Icons.person, color: Colors.blue),
|
|
||||||
title: Text(l10n.cifNumber),
|
|
||||||
subtitle: Text(
|
|
||||||
widget.cifNumber ?? l10n.notApplicable,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DropdownButtonFormField<String>(
|
|
||||||
value: _selectedFinancialYear,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: l10n.selectFinancialYear,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
prefixIcon: const Icon(Icons.calendar_today),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
||||||
),
|
|
||||||
items: _financialYears.map((String year) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: year,
|
|
||||||
child: Text(year),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedFinancialYear = newValue;
|
|
||||||
});
|
|
||||||
_fetchEnquiryData();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
if (_isLoading)
|
|
||||||
const Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(20.0),
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else if (_errorMessage != null)
|
|
||||||
Card(
|
|
||||||
color: Colors.red.shade50,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text(
|
|
||||||
_errorMessage!,
|
|
||||||
style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold),
|
|
||||||
//textAlign: Center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else if (_enquiryData != null)
|
|
||||||
Card(
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
l10n.schemeDetails,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
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']),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDetailRow(String label, dynamic value) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
value?.toString() ?? AppLocalizations.of(context).notApplicable,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.end,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,333 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/yojna_service.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PMJJBYScreen extends StatefulWidget {
|
|
||||||
final Map<String, dynamic>? initialData;
|
|
||||||
const PMJJBYScreen({super.key, this.initialData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PMJJBYScreen> createState() => _PMJJBYScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PMJJBYScreenState extends State<PMJJBYScreen> {
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
// Mapping options
|
|
||||||
final Map<String, String> _healthStatusOptions = {
|
|
||||||
'1': 'Excellent',
|
|
||||||
'2': 'Good',
|
|
||||||
'3': 'Bad',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _relationshipOptions = {
|
|
||||||
'01': 'Self',
|
|
||||||
'02': 'Wife',
|
|
||||||
'03': 'Father',
|
|
||||||
'04': 'Mother',
|
|
||||||
'05': 'Son',
|
|
||||||
'06': 'Daughter',
|
|
||||||
'07': 'Brother',
|
|
||||||
'08': 'Sister',
|
|
||||||
'09': 'Father-in-law',
|
|
||||||
'10': 'Mother-in-law',
|
|
||||||
'11': 'Grandson',
|
|
||||||
'12': 'Granddaughter',
|
|
||||||
'13': 'Grandfather',
|
|
||||||
'14': 'Grandmother',
|
|
||||||
'15': 'Brother-in-law',
|
|
||||||
'16': 'Sister-in-law',
|
|
||||||
'17': 'Husband',
|
|
||||||
'18': 'Guardian',
|
|
||||||
'99': 'Others',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _minorOptions = {
|
|
||||||
'Y': 'Yes',
|
|
||||||
'N': 'No',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _ruralOptions = {
|
|
||||||
'R': 'Rural',
|
|
||||||
'U': 'Urban',
|
|
||||||
'S': 'Semi-Urban',
|
|
||||||
'M': 'Metro',
|
|
||||||
};
|
|
||||||
|
|
||||||
final _healthStatusController = TextEditingController();
|
|
||||||
final _collectionChannelController = TextEditingController();
|
|
||||||
final _nomineeNameController = TextEditingController();
|
|
||||||
final _nomineeAddressController = TextEditingController();
|
|
||||||
final _nomineeRelationshipController = TextEditingController();
|
|
||||||
final _nomineeMinorController = TextEditingController();
|
|
||||||
final _ruralCategoryController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// Initialize dropdown controllers if data exists in initialData
|
|
||||||
if (widget.initialData != null) {
|
|
||||||
if (widget.initialData!.containsKey('ruralcategory')) {
|
|
||||||
_ruralCategoryController.text = widget.initialData!['ruralcategory'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('healthstatus')) {
|
|
||||||
_healthStatusController.text = widget.initialData!['healthstatus'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('nomineerelationship')) {
|
|
||||||
_nomineeRelationshipController.text = widget.initialData!['nomineerelationship'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('nomineeminor')) {
|
|
||||||
_nomineeMinorController.text = widget.initialData!['nomineeminor'].toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_aadhaarController.dispose();
|
|
||||||
_accountNoController.dispose();
|
|
||||||
_balanceController.dispose();
|
|
||||||
_countryController.dispose();
|
|
||||||
_dobController.dispose();
|
|
||||||
_nameController.dispose();
|
|
||||||
_customerNoController.dispose();
|
|
||||||
_acctOpeningDateController.dispose();
|
|
||||||
_emailController.dispose();
|
|
||||||
_financialYearController.dispose();
|
|
||||||
_genderController.dispose();
|
|
||||||
_ifscController.dispose();
|
|
||||||
_marriedController.dispose();
|
|
||||||
_mobileController.dispose();
|
|
||||||
_panController.dispose();
|
|
||||||
_pincodeController.dispose();
|
|
||||||
_policyNumberController.dispose();
|
|
||||||
_premiumAmountController.dispose();
|
|
||||||
_stateController.dispose();
|
|
||||||
_healthStatusController.dispose();
|
|
||||||
_collectionChannelController.dispose();
|
|
||||||
_nomineeNameController.dispose();
|
|
||||||
_nomineeAddressController.dispose();
|
|
||||||
_nomineeRelationshipController.dispose();
|
|
||||||
_nomineeMinorController.dispose();
|
|
||||||
_ruralCategoryController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isFetched(String key) {
|
|
||||||
return widget.initialData != null &&
|
|
||||||
widget.initialData!.containsKey(key) &&
|
|
||||||
widget.initialData![key]?.toString().isNotEmpty == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleRegister() async {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
// Show loading spinner
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => const Center(child: CircularProgressIndicator()),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await getIt<YojnaService>().secondvalidationPMJJBY(
|
|
||||||
aadharno: _aadhaarController.text,
|
|
||||||
accountno: _accountNoController.text,
|
|
||||||
availablebalance: _balanceController.text,
|
|
||||||
country: _countryController.text,
|
|
||||||
customerdob: _dobController.text,
|
|
||||||
customername: _nameController.text,
|
|
||||||
customerno: _customerNoController.text,
|
|
||||||
dateofacctopening: _acctOpeningDateController.text,
|
|
||||||
emailid: _emailController.text,
|
|
||||||
financialyear: _financialYearController.text,
|
|
||||||
gender: _genderController.text,
|
|
||||||
ifsccode: _ifscController.text,
|
|
||||||
married: _marriedController.text,
|
|
||||||
mobileno: _mobileController.text,
|
|
||||||
pan: _panController.text,
|
|
||||||
pincode: _pincodeController.text,
|
|
||||||
policynumber: _policyNumberController.text,
|
|
||||||
premiumamount: _premiumAmountController.text,
|
|
||||||
state: _stateController.text,
|
|
||||||
healthstatus: _healthStatusController.text,
|
|
||||||
collectionchannel: _collectionChannelController.text,
|
|
||||||
nomineename: _nomineeNameController.text,
|
|
||||||
nomineeaddress: _nomineeAddressController.text,
|
|
||||||
nomineerelationship: _nomineeRelationshipController.text,
|
|
||||||
nomineeminor: _nomineeMinorController.text,
|
|
||||||
ruralcategory: _ruralCategoryController.text,
|
|
||||||
);
|
|
||||||
String x = response.toString();
|
|
||||||
if(x.contains('RECORD ALREADY EXISTS')){
|
|
||||||
x= l10n.recordAlreadyExists;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
// Close loading spinner
|
|
||||||
Navigator.pop(context);
|
|
||||||
// Show response dialog
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text(l10n.response),
|
|
||||||
content: SingleChildScrollView(child: Text(x)),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
||||||
},
|
|
||||||
child: Text(l10n.close),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (mounted) {
|
|
||||||
Navigator.pop(context); // Close loading spinner
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.pmjjbyRegistration),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
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')),
|
|
||||||
const Divider(height: 32),
|
|
||||||
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),
|
|
||||||
const Divider(height: 32),
|
|
||||||
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')),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: _handleRegister,
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
l10n.register,
|
|
||||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDropdownField(
|
|
||||||
TextEditingController controller, String label, Map<String, String> options,
|
|
||||||
{bool readOnly = false}) {
|
|
||||||
// Determine current value
|
|
||||||
String? currentValue = options.containsKey(controller.text) ? controller.text : null;
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
child: DropdownButtonFormField<String>(
|
|
||||||
value: currentValue,
|
|
||||||
onChanged: readOnly ? null : (newValue) {
|
|
||||||
setState(() {
|
|
||||||
controller.text = newValue ?? '';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: label,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
|
||||||
),
|
|
||||||
items: options.entries.map((entry) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: entry.key,
|
|
||||||
child: Text("${entry.key} - ${entry.value}"),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: controller,
|
|
||||||
readOnly: readOnly,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: label,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
|
||||||
),
|
|
||||||
keyboardType: keyboardType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/yojna_service.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PMSBYEnquiryScreen extends StatefulWidget {
|
|
||||||
final String? cifNumber;
|
|
||||||
|
|
||||||
const PMSBYEnquiryScreen({
|
|
||||||
super.key,
|
|
||||||
required this.cifNumber,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PMSBYEnquiryScreen> createState() => _PMSBYEnquiryScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PMSBYEnquiryScreenState extends State<PMSBYEnquiryScreen> {
|
|
||||||
String? _selectedFinancialYear;
|
|
||||||
bool _isLoading = false;
|
|
||||||
Map<String, dynamic>? _enquiryData;
|
|
||||||
String? _errorMessage;
|
|
||||||
|
|
||||||
final List<String> _financialYears = [
|
|
||||||
'2021-2022',
|
|
||||||
'2022-2023',
|
|
||||||
'2023-2024',
|
|
||||||
'2024-2025',
|
|
||||||
'2025-2026',
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_selectedFinancialYear = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _fetchEnquiryData() async {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
if (_selectedFinancialYear == null || widget.cifNumber == null) return;
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_isLoading = true;
|
|
||||||
_enquiryData = null;
|
|
||||||
_errorMessage = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
final formattedYear = _selectedFinancialYear!.replaceAll('-', '');
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await getIt<YojnaService>().enquiry(
|
|
||||||
scheme: '01',
|
|
||||||
action: 'E',
|
|
||||||
financialyear: formattedYear,
|
|
||||||
customerno: widget.cifNumber,
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
if (response is Map<String, dynamic>) {
|
|
||||||
if (response['status'] == 'FAILED') {
|
|
||||||
_errorMessage = response['message'] ?? l10n.noRecordFound;
|
|
||||||
} else {
|
|
||||||
_enquiryData = response;
|
|
||||||
}
|
|
||||||
} else if (response is List && response.isNotEmpty) {
|
|
||||||
_enquiryData = response[0] as Map<String, dynamic>;
|
|
||||||
} else {
|
|
||||||
_errorMessage = l10n.noDataFoundYear;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
setState(() {
|
|
||||||
_errorMessage = l10n.genericError(e.toString());
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.pmsbyDetails),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Card(
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
leading: const Icon(Icons.person, color: Colors.blue),
|
|
||||||
title: Text(l10n.cifNumber),
|
|
||||||
subtitle: Text(
|
|
||||||
widget.cifNumber ?? l10n.notApplicable,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
DropdownButtonFormField<String>(
|
|
||||||
value: _selectedFinancialYear,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: l10n.selectFinancialYear,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
prefixIcon: const Icon(Icons.calendar_today),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
||||||
),
|
|
||||||
items: _financialYears.map((String year) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: year,
|
|
||||||
child: Text(year),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedFinancialYear = newValue;
|
|
||||||
});
|
|
||||||
_fetchEnquiryData();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
if (_isLoading)
|
|
||||||
const Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(20.0),
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else if (_errorMessage != null)
|
|
||||||
Card(
|
|
||||||
color: Colors.red.shade50,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text(
|
|
||||||
_errorMessage!,
|
|
||||||
style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold),
|
|
||||||
//textAlign: Center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else if (_enquiryData != null)
|
|
||||||
Card(
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
l10n.schemeDetails,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
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']),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDetailRow(String label, dynamic value) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
value?.toString() ?? AppLocalizations.of(context).notApplicable,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
textAlign: TextAlign.end,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kmobile/api/services/yojna_service.dart';
|
|
||||||
import 'package:kmobile/di/injection.dart';
|
|
||||||
import 'package:kmobile/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class PMSBYScreen extends StatefulWidget {
|
|
||||||
final Map<String, dynamic>? initialData;
|
|
||||||
const PMSBYScreen({super.key, this.initialData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<PMSBYScreen> createState() => _PMSBYScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PMSBYScreenState extends State<PMSBYScreen> {
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
// Mapping options
|
|
||||||
final Map<String, String> _healthStatusOptions = {
|
|
||||||
'1': 'Excellent',
|
|
||||||
'2': 'Good',
|
|
||||||
'3': 'Bad',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _relationshipOptions = {
|
|
||||||
'01': 'Self',
|
|
||||||
'02': 'Wife',
|
|
||||||
'03': 'Father',
|
|
||||||
'04': 'Mother',
|
|
||||||
'05': 'Son',
|
|
||||||
'06': 'Daughter',
|
|
||||||
'07': 'Brother',
|
|
||||||
'08': 'Sister',
|
|
||||||
'09': 'Father-in-law',
|
|
||||||
'10': 'Mother-in-law',
|
|
||||||
'11': 'Grandson',
|
|
||||||
'12': 'Granddaughter',
|
|
||||||
'13': 'Grandfather',
|
|
||||||
'14': 'Grandmother',
|
|
||||||
'15': 'Brother-in-law',
|
|
||||||
'16': 'Sister-in-law',
|
|
||||||
'17': 'Husband',
|
|
||||||
'18': 'Guardian',
|
|
||||||
'99': 'Others',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _minorOptions = {
|
|
||||||
'Y': 'Yes',
|
|
||||||
'N': 'No',
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<String, String> _ruralOptions = {
|
|
||||||
'R': 'Rural',
|
|
||||||
'U': 'Urban',
|
|
||||||
'S': 'Semi-Urban',
|
|
||||||
'M': 'Metro',
|
|
||||||
};
|
|
||||||
|
|
||||||
final _healthStatusController = TextEditingController();
|
|
||||||
final _collectionChannelController = TextEditingController();
|
|
||||||
final _nomineeNameController = TextEditingController();
|
|
||||||
final _nomineeAddressController = TextEditingController();
|
|
||||||
final _nomineeRelationshipController = TextEditingController();
|
|
||||||
final _nomineeMinorController = TextEditingController();
|
|
||||||
final _ruralCategoryController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// Initialize dropdown controllers if data exists in initialData
|
|
||||||
if (widget.initialData != null) {
|
|
||||||
if (widget.initialData!.containsKey('ruralcategory')) {
|
|
||||||
_ruralCategoryController.text = widget.initialData!['ruralcategory'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('healthstatus')) {
|
|
||||||
_healthStatusController.text = widget.initialData!['healthstatus'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('relationwithnominee')) {
|
|
||||||
_nomineeRelationshipController.text = widget.initialData!['relationwithnominee'].toString();
|
|
||||||
}
|
|
||||||
if (widget.initialData!.containsKey('nomineeminor')) {
|
|
||||||
_nomineeMinorController.text = widget.initialData!['nomineeminor'].toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_aadhaarController.dispose();
|
|
||||||
_accountNoController.dispose();
|
|
||||||
_balanceController.dispose();
|
|
||||||
_countryController.dispose();
|
|
||||||
_dobController.dispose();
|
|
||||||
_nameController.dispose();
|
|
||||||
_customerNoController.dispose();
|
|
||||||
_acctOpeningDateController.dispose();
|
|
||||||
_emailController.dispose();
|
|
||||||
_financialYearController.dispose();
|
|
||||||
_genderController.dispose();
|
|
||||||
_ifscController.dispose();
|
|
||||||
_marriedController.dispose();
|
|
||||||
_mobileController.dispose();
|
|
||||||
_panController.dispose();
|
|
||||||
_pincodeController.dispose();
|
|
||||||
_policyNumberController.dispose();
|
|
||||||
_premiumAmountController.dispose();
|
|
||||||
_stateController.dispose();
|
|
||||||
_address1Controller.dispose();
|
|
||||||
_address2Controller.dispose();
|
|
||||||
_cityController.dispose();
|
|
||||||
_relationWithNomineeController.dispose();
|
|
||||||
_policyStatusController.dispose();
|
|
||||||
_healthStatusController.dispose();
|
|
||||||
_collectionChannelController.dispose();
|
|
||||||
_nomineeNameController.dispose();
|
|
||||||
_nomineeAddressController.dispose();
|
|
||||||
_nomineeRelationshipController.dispose();
|
|
||||||
_nomineeMinorController.dispose();
|
|
||||||
_ruralCategoryController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isFetched(String key) {
|
|
||||||
return widget.initialData != null &&
|
|
||||||
widget.initialData!.containsKey(key) &&
|
|
||||||
widget.initialData![key]?.toString().isNotEmpty == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _handleRegister() async {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
// Show loading spinner
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => const Center(child: CircularProgressIndicator()),
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await getIt<YojnaService>().secondvalidationPMSBY(
|
|
||||||
aadharno: _aadhaarController.text,
|
|
||||||
accountno: _accountNoController.text,
|
|
||||||
address1: _address1Controller.text,
|
|
||||||
address2: _address2Controller.text,
|
|
||||||
availablebalance: _balanceController.text,
|
|
||||||
city: _cityController.text,
|
|
||||||
country: _countryController.text,
|
|
||||||
customerdob: _dobController.text,
|
|
||||||
customername: _nameController.text,
|
|
||||||
customerno: _customerNoController.text,
|
|
||||||
emailid: _emailController.text,
|
|
||||||
financialyear: _financialYearController.text,
|
|
||||||
gender: _genderController.text,
|
|
||||||
married: _marriedController.text,
|
|
||||||
mobileno: _mobileController.text,
|
|
||||||
pan: _panController.text,
|
|
||||||
pincode: _pincodeController.text,
|
|
||||||
policyno: _policyNumberController.text,
|
|
||||||
premiumamount: _premiumAmountController.text,
|
|
||||||
state: _stateController.text,
|
|
||||||
healthstatus: _healthStatusController.text,
|
|
||||||
nomineename: _nomineeNameController.text,
|
|
||||||
nomineeadress: _nomineeAddressController.text,
|
|
||||||
relationwithnominee: _relationWithNomineeController.text,
|
|
||||||
nomineeminor: _nomineeMinorController.text,
|
|
||||||
collectionchannel: _collectionChannelController.text,
|
|
||||||
ruralcategory: _ruralCategoryController.text,
|
|
||||||
policystatus: _policyStatusController.text,
|
|
||||||
);
|
|
||||||
String x = response.toString();
|
|
||||||
if(x.contains('RECORD ALREADY EXISTS')){
|
|
||||||
x= l10n.recordAlreadyExists;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
// Close loading spinner
|
|
||||||
Navigator.pop(context);
|
|
||||||
// Show response dialog
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text(l10n.response),
|
|
||||||
content: SingleChildScrollView(child: Text(x)),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
||||||
},
|
|
||||||
child: Text(l10n.close),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (mounted) {
|
|
||||||
Navigator.pop(context); // Close loading spinner
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final l10n = AppLocalizations.of(context);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(l10n.pmsbyRegistration),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Form(
|
|
||||||
key: _formKey,
|
|
||||||
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')),
|
|
||||||
const Divider(height: 32),
|
|
||||||
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),
|
|
||||||
const Divider(height: 32),
|
|
||||||
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')),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: _handleRegister,
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
l10n.register,
|
|
||||||
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDropdownField(
|
|
||||||
TextEditingController controller, String label, Map<String, String> options,
|
|
||||||
{bool readOnly = false}) {
|
|
||||||
// Determine current value
|
|
||||||
String? currentValue = options.containsKey(controller.text) ? controller.text : null;
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
child: DropdownButtonFormField<String>(
|
|
||||||
value: currentValue,
|
|
||||||
onChanged: readOnly ? null : (newValue) {
|
|
||||||
setState(() {
|
|
||||||
controller.text = newValue ?? '';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: label,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
|
||||||
),
|
|
||||||
items: options.entries.map((entry) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: entry.key,
|
|
||||||
child: Text("${entry.key} - ${entry.value}"),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: controller,
|
|
||||||
readOnly: readOnly,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: label,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
|
||||||
),
|
|
||||||
keyboardType: keyboardType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -555,100 +555,5 @@
|
|||||||
"stopChequeButton": "Stop Cheque",
|
"stopChequeButton": "Stop Cheque",
|
||||||
"stopMultipleChequesTitle": "Stop Multiple Cheques",
|
"stopMultipleChequesTitle": "Stop Multiple Cheques",
|
||||||
"fromChequeNumberHint": "From Cheque Number *",
|
"fromChequeNumberHint": "From Cheque Number *",
|
||||||
"toChequeNumberHint": "To Cheque Number *",
|
"toChequeNumberHint": "To Cheque Number *"
|
||||||
"failedToFetchChequeStatus": "Failed to fetch cheque status: {error}",
|
}
|
||||||
"revokeStopSubtitle": "Revoke your stopped cheques so as to reuse it",
|
|
||||||
"positivePaySubtitle": "Prevent unauthorized use of your issued cheque",
|
|
||||||
"positivePayTitle": "Positive Pay",
|
|
||||||
"pleaseEnterAccountNumber": "Please enter account number",
|
|
||||||
"chequeNumber": "Cheque Number",
|
|
||||||
"pleaseEnterChequeNumber": "Please enter cheque number",
|
|
||||||
"chequeIssuedDate": "Cheque Issued Date",
|
|
||||||
"pleaseSelectChequeIssuedDate": "Please select cheque issued date",
|
|
||||||
"payeeName": "Payee Name",
|
|
||||||
"pleaseEnterAmount": "Please enter the amount",
|
|
||||||
"processingData": "Processing Data",
|
|
||||||
"revokeStopCheque": "Revoke Stop Cheque",
|
|
||||||
"currentAccount": "Current Account",
|
|
||||||
"cashCreditAccount": "Cash Credit Account",
|
|
||||||
"revokeSingleStop": "Revoke Single Stop",
|
|
||||||
"noStoppedChequesPresent": "No stopped cheques present",
|
|
||||||
"revokeMultipleStops": "Revoke Multiple Stops",
|
|
||||||
"revokeSingleStopTitle": "Revoke Single Stop",
|
|
||||||
"chequeFound": "Cheque Found",
|
|
||||||
"chequeFixed": "Cheque Fixed",
|
|
||||||
"other": "Other",
|
|
||||||
"revokeIssueDate": "Revoke Issue Date",
|
|
||||||
"revokeExpiryDate": "Revoke Expiry Date",
|
|
||||||
"revokeAmount": "Revoke Amount",
|
|
||||||
"revokeComment": "Revoke Comment",
|
|
||||||
"otherReasons": "Other Reasons :",
|
|
||||||
"revokeStopButton": "Revoke Stop",
|
|
||||||
"invalidTpin": "Invalid TPIN",
|
|
||||||
"incorrectTpinMessage": "The TPIN you entered is incorrect. Please try again.",
|
|
||||||
"chequeAlreadyStopped": "The selected Cheque is already stopped",
|
|
||||||
"chequeAlreadyPresented": "The selected Cheque is already presented",
|
|
||||||
"chequeLost": "Cheque Lost",
|
|
||||||
"chequeStolen": "Cheque Stolen",
|
|
||||||
"chequeMissing": "Cheque Missing",
|
|
||||||
"chequeDamaged": "Cheque Damaged",
|
|
||||||
"close": "Close",
|
|
||||||
"governmentSchemes": "Government Schemes",
|
|
||||||
"pradhanMantriYojana": "Pradhan Mantri Yojana",
|
|
||||||
"atalPensionYojana": "Atal Pension Yojana",
|
|
||||||
"registerForAtalPensionYojana": "Register for Atal Pension Yojana",
|
|
||||||
"secureYourFutureAPY": "Secure your future with Atal Pension Yojana (APY) retirement scheme. Register in a few steps.",
|
|
||||||
"enrollPMJJBYPMSBY": "Enroll in Pradhan Mantri Jeevan Jyoti Bima Yojana (PMJJBY) and Pradhan Mantri Suraksha Bima Yojana (PMSBY) insurance schemes",
|
|
||||||
"apyRegistration": "APY registration",
|
|
||||||
"apyDescription": "Atal Pension Yojana (APY) is a periodic contribution-based pension scheme for citizens of India.",
|
|
||||||
"pmjjbyPmsbyDescription": "Create and Enquire about your Pradhan Mantri Jeevan Jyoti Bima Yojana (PMJJBY) and Pradhan Mantri Suraksha Bima Yojana(PMSBY) schemes.",
|
|
||||||
"selectScheme": "Select Scheme",
|
|
||||||
"pmjjbyFull": "Pradhan Mantri Jeevan Jyoti Bima Yojana (PMJJBY)",
|
|
||||||
"pmsbyFull": "Pradhan Mantri Suraksha Bima Yojana (PMSBY)",
|
|
||||||
"create": "Create",
|
|
||||||
"pleaseSelectAccountNumber": "Please select account number",
|
|
||||||
"pleaseSelectSchemeFirst": "Please select a scheme first",
|
|
||||||
"fetchingDetails": "Fetching details...",
|
|
||||||
"failedToFetchDetails": "Failed to fetch details or no data found.",
|
|
||||||
"pmjjbyDetails": "PMJJBY details",
|
|
||||||
"pmsbyDetails": "PMSBY details",
|
|
||||||
"cifNumber": "CIF Number",
|
|
||||||
"selectFinancialYear": "Select Financial Year",
|
|
||||||
"schemeDetails": "Scheme Details",
|
|
||||||
"customerName": "Customer Name",
|
|
||||||
"policyNumber": "Policy Number",
|
|
||||||
"premiumAmount": "Premium Amount",
|
|
||||||
"nomineeName": "Nominee Name",
|
|
||||||
"journalNo": "Journal No",
|
|
||||||
"noRecordFound": "No record found",
|
|
||||||
"noDataFoundYear": "No data found for the selected year.",
|
|
||||||
"pmjjbyRegistration": "PMJJBY Registration",
|
|
||||||
"pmsbyRegistration": "PMSBY Registration",
|
|
||||||
"customerNo": "Customer No",
|
|
||||||
"aadhaarNo": "Aadhaar No",
|
|
||||||
"customerDobFormat": "Customer DOB (DD/MM/YYYY)",
|
|
||||||
"gender": "Gender",
|
|
||||||
"marriedYesNo": "Married (Yes/No)",
|
|
||||||
"pan": "PAN",
|
|
||||||
"dateOfAcctOpening": "Date of Acct Opening",
|
|
||||||
"pincode": "Pincode",
|
|
||||||
"state": "State",
|
|
||||||
"country": "Country",
|
|
||||||
"ruralCategory": "Rural Category",
|
|
||||||
"policyDetails": "Policy Details",
|
|
||||||
"financialYear": "Financial Year",
|
|
||||||
"healthStatus": "Health Status",
|
|
||||||
"collectionChannel": "Collection Channel",
|
|
||||||
"nomineeDetails": "Nominee Details",
|
|
||||||
"nomineeAddress": "Nominee Address",
|
|
||||||
"nomineeRelationship": "Nominee Relationship",
|
|
||||||
"nomineeMinor": "Nominee Minor",
|
|
||||||
"response": "Response",
|
|
||||||
"recordAlreadyExists": "A record already exists for this request. Your submission has been registered previously.",
|
|
||||||
"address1": "Address 1",
|
|
||||||
"address2": "Address 2",
|
|
||||||
"city": "City",
|
|
||||||
"relationWithNominee": "Relation with Nominee",
|
|
||||||
"policyStatus": "Policy Status",
|
|
||||||
"emailId": "Email ID"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -556,99 +556,5 @@
|
|||||||
"stopChequeButton": "चेक रोकें",
|
"stopChequeButton": "चेक रोकें",
|
||||||
"stopMultipleChequesTitle": "एकाधिक चेक रोकें",
|
"stopMultipleChequesTitle": "एकाधिक चेक रोकें",
|
||||||
"fromChequeNumberHint": "चेक नंबर से *",
|
"fromChequeNumberHint": "चेक नंबर से *",
|
||||||
"toChequeNumberHint": "चेक नंबर तक *",
|
"toChequeNumberHint": "चेक नंबर तक *"
|
||||||
"failedToFetchChequeStatus": "चेक स्थिति लाने में विफल: {error}",
|
}
|
||||||
"revokeStopSubtitle": "अपने रोके गए चेकों को फिर से उपयोग करने के लिए निरस्त करें",
|
|
||||||
"positivePaySubtitle": "अनधिकृत उपयोग को रोकने के लिए अपने जारी किए गए चेक का विवरण जमा करें",
|
|
||||||
"positivePayTitle": "सकारात्मक वेतन",
|
|
||||||
"pleaseEnterAccountNumber": "कृपया खाता संख्या दर्ज करें",
|
|
||||||
"chequeNumber": "चेक संख्या",
|
|
||||||
"pleaseEnterChequeNumber": "कृपया चेक संख्या दर्ज करें",
|
|
||||||
"chequeIssuedDate": "चेक जारी करने की तारीख",
|
|
||||||
"pleaseSelectChequeIssuedDate": "कृपया चेक जारी करने की तारीख चुनें",
|
|
||||||
"payeeName": "प्राप्तकर्ता का नाम",
|
|
||||||
"pleaseEnterAmount": "कृपया राशि दर्ज करें",
|
|
||||||
"processingData": "डेटा संसाधित हो रहा है",
|
|
||||||
"revokeStopCheque": "चेक रोको रद्द करें",
|
|
||||||
"currentAccount": "चालू खाता",
|
|
||||||
"cashCreditAccount": "नगद श्रेय खाता",
|
|
||||||
"revokeSingleStop": "एकल रोक रद्द करें",
|
|
||||||
"noStoppedChequesPresent": "कोई रोका हुआ चेक मौजूद नहीं है",
|
|
||||||
"revokeMultipleStops": "कई रोक रद्द करें",
|
|
||||||
"revokeSingleStopTitle": "एकल रोक रद्द करें",
|
|
||||||
"chequeFound": "चेक मिला",
|
|
||||||
"chequeFixed": "चेक ठीक किया गया",
|
|
||||||
"other": "अन्य",
|
|
||||||
"revokeIssueDate": "रोक जारी करने की तारीख रद्द करें",
|
|
||||||
"revokeExpiryDate": "रोक समाप्ति तिथि रद्द करें",
|
|
||||||
"revokeAmount": "राशि रद्द करें",
|
|
||||||
"revokeComment": "टिप्पणी रद्द करें",
|
|
||||||
"otherReasons": "अन्य कारण :",
|
|
||||||
"revokeStopButton": "रोक रद्द करें",
|
|
||||||
"invalidTpin": "अमान्य टीपिन",
|
|
||||||
"incorrectTpinMessage": "आपके द्वारा दर्ज किया गया टीपिन गलत है। कृपया पुनः प्रयास करें।",
|
|
||||||
"chequeAlreadyStopped": "चुना हुआ चेक पहले से ही रोका हुआ है",
|
|
||||||
"chequeAlreadyPresented": "चुना हुआ चेक पहले से ही प्रस्तुत किया जा चुका है",
|
|
||||||
"chequeLost": "चेक खो गया",
|
|
||||||
"chequeStolen": "चेक चोरी हो गया",
|
|
||||||
"chequeMissing": "चेक गायब है",
|
|
||||||
"chequeDamaged": "चेक क्षतिग्रस्त है",
|
|
||||||
"close": "बंद करें",
|
|
||||||
"governmentSchemes": "सरकारी योजनाएं",
|
|
||||||
"pradhanMantriYojana": "प्रधानमंत्री योजना",
|
|
||||||
"atalPensionYojana": "अटल पेंशन योजना",
|
|
||||||
"registerForAtalPensionYojana": "अटल पेंशन योजना के लिए पंजीकरण करें",
|
|
||||||
"secureYourFutureAPY": "अटल पेंशन योजना (APY) सेवानिवृत्ति योजना के साथ अपना भविष्य सुरक्षित करें। कुछ ही चरणों में पंजीकरण करें।",
|
|
||||||
"enrollPMJJBYPMSBY": "प्रधानमंत्री जीवन ज्योति बीमा योजना (PMJJBY) और प्रधानमंत्री सुरक्षा बीमा योजना (PMSBY) बीमा योजनाओं में नामांकन करें",
|
|
||||||
"apyRegistration": "APY पंजीकरण",
|
|
||||||
"apyDescription": "अटल पेंशन योजना (APY) भारत के नागरिकों के लिए एक आवधिक योगदान-आधारित पेंशन योजना है।",
|
|
||||||
"pmjjbyPmsbyDescription": "अपनी प्रधानमंत्री जीवन ज्योति बीमा योजना (PMJJBY) और प्रधानमंत्री सुरक्षा बीमा योजना (PMSBY) योजनाओं के बारे में बनाएं और पूछताछ करें।",
|
|
||||||
"selectScheme": "योजना चुनें",
|
|
||||||
"pmjjbyFull": "प्रधानमंत्री जीवन ज्योति बीमा योजना (PMJJBY)",
|
|
||||||
"pmsbyFull": "प्रधानमंत्री सुरक्षा बीमा योजना (PMSBY)",
|
|
||||||
"create": "बनाएं",
|
|
||||||
"pleaseSelectAccountNumber": "कृपया खाता संख्या चुनें",
|
|
||||||
"pleaseSelectSchemeFirst": "कृपया पहले एक योजना चुनें",
|
|
||||||
"fetchingDetails": "विवरण प्राप्त किया जा रहा है...",
|
|
||||||
"failedToFetchDetails": "विवरण प्राप्त करने में विफल या कोई डेटा नहीं मिला।",
|
|
||||||
"pmjjbyDetails": "PMJJBY विवरण",
|
|
||||||
"pmsbyDetails": "PMSBY विवरण",
|
|
||||||
"cifNumber": "CIF संख्या",
|
|
||||||
"selectFinancialYear": "वित्तीय वर्ष चुनें",
|
|
||||||
"schemeDetails": "योजना विवरण",
|
|
||||||
"customerName": "ग्राहक का नाम",
|
|
||||||
"policyNumber": "पॉलिसी संख्या",
|
|
||||||
"premiumAmount": "प्रीमियम राशि",
|
|
||||||
"nomineeName": "नामांकित व्यक्ति का नाम",
|
|
||||||
"journalNo": "जर्नल नंबर",
|
|
||||||
"noRecordFound": "कोई रिकॉर्ड नहीं मिला",
|
|
||||||
"noDataFoundYear": "चयनित वर्ष के लिए कोई डेटा नहीं मिला।",
|
|
||||||
"pmjjbyRegistration": "PMJJBY पंजीकरण",
|
|
||||||
"pmsbyRegistration": "PMSBY पंजीकरण",
|
|
||||||
"customerNo": "ग्राहक संख्या",
|
|
||||||
"aadhaarNo": "आधार संख्या",
|
|
||||||
"customerDobFormat": "ग्राहक की जन्म तिथि (DD/MM/YYYY)",
|
|
||||||
"gender": "लिंग",
|
|
||||||
"marriedYesNo": "विवाहित (हाँ/नहीं)",
|
|
||||||
"pan": "पैन",
|
|
||||||
"dateOfAcctOpening": "खाता खोलने की तिथि",
|
|
||||||
"pincode": "पिनकोड",
|
|
||||||
"state": "राज्य",
|
|
||||||
"country": "देश",
|
|
||||||
"ruralCategory": "ग्रामीण श्रेणी",
|
|
||||||
"policyDetails": "पॉलिसी विवरण",
|
|
||||||
"financialYear": "वित्तीय वर्ष",
|
|
||||||
"healthStatus": "स्वास्थ्य की स्थिति",
|
|
||||||
"collectionChannel": "संग्रह चैनल",
|
|
||||||
"nomineeDetails": "नामांकित व्यक्ति का विवरण",
|
|
||||||
"nomineeAddress": "नामांकित व्यक्ति का पता",
|
|
||||||
"nomineeRelationship": "नामांकित व्यक्ति से संबंध",
|
|
||||||
"nomineeMinor": "नामांकित व्यक्ति नाबालिग है",
|
|
||||||
"response": "प्रतिक्रिया",
|
|
||||||
"recordAlreadyExists": "इस अनुरोध के लिए एक रिकॉर्ड पहले से मौजूद है। आपका सबमिशन पहले पंजीकृत किया जा चुका है।",
|
|
||||||
"address1": "पता 1",
|
|
||||||
"address2": "पता 2",
|
|
||||||
"city": "शहर",
|
|
||||||
"relationWithNominee": "नामांकित व्यक्ति के साथ संबंध",
|
|
||||||
"policyStatus": "पॉलिसी की स्थिति"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ void main() async {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Check for device compromise
|
// Check for device compromise
|
||||||
final compromisedMessage = await SecurityService.deviceCompromisedMessage;
|
// final compromisedMessage = await SecurityService.deviceCompromisedMessage;
|
||||||
if (compromisedMessage != null) {
|
// if (compromisedMessage != null) {
|
||||||
runApp(MaterialApp(
|
// runApp(MaterialApp(
|
||||||
home: SecurityErrorScreen(message: compromisedMessage),
|
// home: SecurityErrorScreen(message: compromisedMessage),
|
||||||
));
|
// ));
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
await setupDependencies();
|
await setupDependencies();
|
||||||
runApp(const KMobile());
|
runApp(const KMobile());
|
||||||
}
|
}
|
||||||
|
|||||||
18
pubspec.lock
18
pubspec.lock
@@ -773,14 +773,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
send_message:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: send_message
|
|
||||||
sha256: "79b5f69fd3ab0b9e6265f8d972800d7989b3082a0523c7f4b8e38bf4e1c71235"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.2"
|
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -869,14 +861,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
simcards:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: simcards
|
|
||||||
sha256: b621cc265ebbb3e11009ca9be67063efbc011396c4224aff8b08edaba30fa5ae
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.1"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -1019,7 +1003,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.4"
|
version: "3.1.4"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ dependencies:
|
|||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
jailbreak_root_detection: ^1.1.6
|
jailbreak_root_detection: ^1.1.6
|
||||||
equatable: ^2.0.7
|
equatable: ^2.0.7
|
||||||
dio: ^5.9.0
|
dio: ^5.8.0+1
|
||||||
flutter_secure_storage: ^9.2.4
|
flutter_secure_storage: ^9.2.4
|
||||||
bloc: ^9.0.0
|
bloc: ^9.0.0
|
||||||
flutter_bloc: ^9.1.0
|
flutter_bloc: ^9.1.0
|
||||||
@@ -63,9 +63,6 @@ dependencies:
|
|||||||
package_info_plus: ^4.2.0
|
package_info_plus: ^4.2.0
|
||||||
flutter_local_notifications: ^19.5.0
|
flutter_local_notifications: ^19.5.0
|
||||||
open_filex: ^4.7.0
|
open_filex: ^4.7.0
|
||||||
simcards: ^0.0.1
|
|
||||||
uuid: ^4.5.1
|
|
||||||
send_message: ^1.0.0
|
|
||||||
# jailbreak_root_detection: "^1.1.6"
|
# jailbreak_root_detection: "^1.1.6"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user