diff --git a/lib/controller/kyc_controller.dart b/lib/controller/kyc_controller.dart index 8450c51..c436c22 100644 --- a/lib/controller/kyc_controller.dart +++ b/lib/controller/kyc_controller.dart @@ -13,7 +13,7 @@ class KycController extends GetxController { @override void onInit() { super.onInit(); - loadKycFromLocalStorage(); // Load KYC data from local storage when initialized + // loadKycFromLocalStorage(); // Load KYC data from local storage when initialized } Future fetchKycData() async { @@ -28,24 +28,44 @@ class KycController extends GetxController { if (data != null && data.isNotEmpty) { // Parse the list of KYC objects kycList.value = KycModel.fromJsonList(data); // Convert to List - saveKycToLocalStorage(); // Save the fetched KYC data to local storage + // saveKycToLocalStorage(); // Save the fetched KYC data to local storage } else { print("No KYC data found or API response is empty."); } - print("KYC details: ${kycList}"); + print("KYC details: ${kycList[0].id}"); } finally { isLoading(false); } } + + void approveKyc(String kycId) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + + if (token != null && kycId.isNotEmpty) { + print("Approving KYC with ID: $kycId"); + + bool result = await KycService().approveKycStatus(token, kycId, "approved"); + + if (result) { + print("KYC approved successfully."); + } else { + print("Failed to approve KYC."); + } + } else { + print("Token or KYC ID is missing."); + } + } + // Update KYC status locally and persist the changes Future updateKycStatus(KycModel kycModel, String status, String comment) async { final index = kycList.indexOf(kycModel); if (index != -1) { kycList[index].status = status; // Update status locally - saveKycToLocalStorage(); // Persist the changes locally + // saveKycToLocalStorage(); // Persist the changes locally // Show a success message after updating Get.snackbar( @@ -58,26 +78,20 @@ class KycController extends GetxController { } } - // Save the current KYC list to SharedPreferences - Future saveKycToLocalStorage() async { + + void rejectKyc(String kycId,String? rejectionReason,String? user) async { SharedPreferences prefs = await SharedPreferences.getInstance(); - List kycListJson = kycList.map((kyc) => jsonEncode(kyc.toJson())).toList(); - prefs.setStringList('kycList', kycListJson); // Save the updated list locally - } - - // Load KYC data from SharedPreferences - Future loadKycFromLocalStorage() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - List? kycListJson = prefs.getStringList('kycList'); - - if (kycListJson != null) { - kycList.value = kycListJson.map((jsonStr) => KycModel.fromJson(jsonDecode(jsonStr))).toList(); - print("Loaded KYC data from local storage."); + String? token = prefs.getString('token'); + //String? kycId = kycList[0].id; // Replace with the KYC ID + // var rejectionReason = kycList[0].notes; // Example rejection reason + // var principalDistributer = kycList[0].notes!.name; + bool result = await KycService().rejectKycStatus(token!, kycId, rejectionReason, user , "reject"); + if (result) { + print("KYC rejected successfully."); } else { - // If no data found, fetch from API - fetchKycData(); - + print("Failed to reject KYC."); } } + } diff --git a/lib/controller/kyc_service.dart b/lib/controller/kyc_service.dart index ed2e6a9..ce1f313 100644 --- a/lib/controller/kyc_service.dart +++ b/lib/controller/kyc_service.dart @@ -1,3 +1,4 @@ +import 'package:cheminova/models/kyc_model.dart'; import 'package:cheminova/utils/api_urls.dart'; import 'package:dio/dio.dart'; @@ -28,6 +29,192 @@ class KycService { return []; } } + + Future approveKycStatus(String token, String kycId,String status) async { + try { + // Prepare the payload for approval directly + var payload = { + "status": "approved", // Set status to approve + }; + + // Log the payload + // print("Payload: $payload"); + + // Make a PATCH request to update the KYC status + var response = await Dio().patch( + 'https://api.cnapp.co.in/api/kyc/update/$kycId', // URL with the KYC ID + data: payload, // Payload with the status + options: Options( + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ), + ); + + // Check if the response indicates success + if (response.statusCode == 200) { + print("KYC status approved successfully: ${response.data}"); + return true; // Return true if the update was successful + } else { + print("Failed to approve KYC status: ${response.statusCode} - ${response.data}"); + return false; + } + } catch (e) { + print("Error approving KYC status: ${e}"); + if (e is DioError) { + // Check if the error has a response + if (e.response != null) { + print("Error response data: ${e.response!.data}"); + print("Error response status: ${e.response!.statusCode}"); + } + } + return false; + } + } + Future rejectKycStatus( + String token, String kycId, String? rejectionReason, String? user, String status) async { + try { + // Prepare the payload for the PATCH request + var data = { + "status": status, // The KYC status (e.g., "reject") + "rejectionReason": rejectionReason, // Reason for rejection + "user": user, // The role of the user (e.g., "Principal Distributer") + // "notes": [ + // { + // "message": rejectionReason, // Rejection message + // "user": user, // User role + // "replyDate": DateTime.now().toUtc().toIso8601String(), // Current UTC date for replyDate + // } + // ] + }; + + print("Payload: $data"); + + // Make a PATCH request to update the KYC status + var response = await Dio().patch( + 'https://api.cnapp.co.in/api/kyc/update/$kycId', + data: data, + options: Options( + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ), + ); + + // Check if the response indicates success + if (response.statusCode == 200) { + print("KYC status rejected successfully: ${response.data}"); + return true; // Return true if the update was successful + } else { + print("Failed to reject KYC status: ${response.statusCode}"); + return false; + } + } catch (e) { + print("Error rejecting KYC status: ${e}"); + if (e is DioError) { + // Check if the error has a response + if (e.response != null) { + print("Error response data: ${e.response!.data}"); + print("Error response status: ${e.response!.statusCode}"); + } + } + return false; + } + } + // + // Future rejectKycStatus(String token, String kycId, String? rejectionReason, + // PrincipalDistributer? user, String status) async { + // try { + // // Prepare the payload with proper rejectionReason structure + // var data = { + // "status": status, + // "rejectionReason": rejectionReason, + // "user": user, + // }; + // + // print("Payload: $data"); + // + // // Make a PATCH request to update the KYC status + // var response = await Dio().patch( + // 'https://api.cnapp.co.in/api/kyc/update/$kycId', + // data: data, + // options: Options( + // headers: { + // 'Authorization': 'Bearer $token', + // 'Content-Type': 'application/json', + // }, + // ), + // ); + // + // // Check if the response indicates success + // if (response.statusCode == 200) { + // print("KYC status rejected successfully: ${response.data}"); + // return true; // Return true if the update was successful + // } else { + // print("Failed to reject KYC status: ${response.statusCode}"); + // return false; + // } + // } catch (e) { + // print("Error rejecting KYC status: ${e}"); + // if (e is DioError) { + // // Check if the error has a response + // if (e.response != null) { + // print("Error response data: ${e.response!.data}"); + // print("Error response status: ${e.response!.statusCode}"); + // } + // } + // return false; + // } + // } + +// + // Future updateKycStatus(String token, String kycId, + // {List? rejectionReason, PrincipalDistributer? user}) async { + // try { + // // Prepare the payload based on the action (approve or reject) + // var data; + // + // + // // Payload for approve action + // + // data = { + // "status": "reject", // Set status to reject + // "rejectionReason": rejectionReason, // Pass the rejection reason + // "user": user, // Pass the user (e.g., 'Principal Distributer') + // }; + // + // else { + // throw Exception("Invalid action: must be 'approve' or 'reject'"); + // } + // + // // Make a PATCH request to update the KYC status + // var response = await Dio().patch( + // 'https://api.cnapp.co.in/api/kyc/update/$kycId', // URL with the KYC ID + // data: data, // Payload with the status + // options: Options( + // headers: { + // 'Authorization': 'Bearer $token', + // 'Content-Type': 'application/json', + // }, + // ), + // ); + // + // // Check if the response indicates success + // if (response.statusCode == 200) { + // print("KYC status updated successfully: ${response.data}"); + // return true; // Return true if the update was successful + // } else { + // print("Failed to update KYC status: ${response.statusCode}"); + // return false; + // } + // } catch (e) { + // print("Error updating KYC status: $e"); + // return false; + // } + // } + } diff --git a/lib/models/kyc_model.dart b/lib/models/kyc_model.dart index 33d661b..53dc941 100644 --- a/lib/models/kyc_model.dart +++ b/lib/models/kyc_model.dart @@ -21,7 +21,7 @@ class KycModel { String? status; AddedBy? addedBy; String? userType; - List? notes; +List? notes; String? createdAt; String? updatedAt; int? v; @@ -87,7 +87,9 @@ class KycModel { status: json["status"], addedBy: json["addedBy"] != null ? AddedBy.fromJson(json["addedBy"]) : null, userType: json["userType"], - notes: json["notes"], + notes: json['notes'] != null + ? (json['notes'] as List).map((i) => Notes.fromJson(i)).toList() + : null, createdAt: json["createdAt"], updatedAt: json["updatedAt"], v: json["__v"], @@ -123,7 +125,7 @@ class KycModel { "status": status, "addedBy": addedBy?.toJson(), "userType": userType, - "notes": notes, + "notes": notes?.map((note) => note.toJson()).toList(), "createdAt": createdAt, "updatedAt": updatedAt, "__v": v, @@ -162,6 +164,39 @@ class PrincipalDistributer { } } + +class Notes { + String? message; + String? replyDate; + String? id; + String? user; + + Notes({this.message, this.replyDate, this.id,this.user}); + + factory Notes.fromJson(Map json) { + return Notes( + message: json["message"], + replyDate: json["replyDate"], + id: json["_id"], + user: json['user'] + ); + } + + Map toJson() { + return { + "message": message, + "replyDate": replyDate, + "_id": id, + "user":user + }; + } + + @override + String toString() { + return 'Notes{message: $message, replyDate: $replyDate, id: $id,user:$user}'; + } +} + class ImageModel { String? publicId; String? url; diff --git a/lib/screens/authentication/login_screen.dart b/lib/screens/authentication/login_screen.dart index 6cd2a78..47a7581 100644 --- a/lib/screens/authentication/login_screen.dart +++ b/lib/screens/authentication/login_screen.dart @@ -21,7 +21,7 @@ class _LoginScreenState extends State { // Controller for handling authentication logic final authController = Get.put(AuthController()); // Email validation pattern - final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'; + final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,}$'; // Password validation pattern (at least 6 characters) final String passwordPattern = r'^.{6,}$'; // At least 6 characters diff --git a/lib/screens/kyc/kyc_retailer_details_screen.dart b/lib/screens/kyc/kyc_retailer_details_screen.dart index a5b12d2..9ec411a 100644 --- a/lib/screens/kyc/kyc_retailer_details_screen.dart +++ b/lib/screens/kyc/kyc_retailer_details_screen.dart @@ -1,4 +1,5 @@ +import 'package:cheminova/utils/show_snackbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; @@ -22,47 +23,61 @@ class _KycRetailerDetailScreenState final KycController _kycController = Get.put(KycController()); final commentController = TextEditingController(); - String currentStatus = "new"; + String? currentStatus ; + String selectedStatus = "All"; void _approveKyc() { if (widget.kycModel!.status == "approved") { - Get.snackbar( - "Error", - "The KYC has already been approved.", - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.red, - colorText: Colors.white, - ); + showSnackbar("The KYC has already been approved."); } else { - // Update the status in the model before calling the controller method - widget.kycModel!.status = "approved"; - _kycController.updateKycStatus(widget.kycModel!, "approved", ""); - setState(() { + // Show confirmation dialog + Get.dialog( + AlertDialog( + title: Text("Approval Confirmation"), + content: Text("Are you sure you want to approve this KYC?"), + actions: [ + TextButton( + onPressed: () { + // Close the dialog without approving + Get.back(); + }, + child: Text("Cancel"), + ), + TextButton( + onPressed: () { + // If "Approve" is pressed, approve the KYC + _kycController.approveKyc(widget.kycModel!.id.toString()); - }); + // Update the KYC status and show success message + widget.kycModel!.status = "approved"; - Get.snackbar( - "Success", - "KYC approved successfully.", - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.green, - colorText: Colors.white, + showSnackbar("KYC approved successfully"); + + // Delay closing the dialog to ensure the user sees the success message + Future.delayed(Duration(seconds: 1), () { + Get.back(); // Close the dialog after a delay + }); + + setState(() {}); // Refresh the UI + }, + child: Text("Approve"), + ), + ], + ), ); - - // Pass the updated model back to the previous screen - Get.back(result: widget.kycModel); } } void _rejectKyc() { if (widget.kycModel!.status == "reject") { - Get.snackbar( - "Error", - "The KYC has already been rejected.", - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.red, - colorText: Colors.white, - ); + showSnackbar("The KYC has already been rejected"); + // Get.snackbar( + // "Error", + // "The KYC has already been rejected.", + // snackPosition: SnackPosition.BOTTOM, + // backgroundColor: Colors.red, + // colorText: Colors.white, + // ); } else { // Show dialog to enter a comment Get.dialog( @@ -86,32 +101,30 @@ class _KycRetailerDetailScreenState // Update the status in the model before calling the controller method widget.kycModel!.status = "reject"; - // Append the comment to the notes list + // Create a new Notes object (assuming Notes has a field for comments) + Notes rejectionNote = Notes(message: comment); + + // Append the new Notes object to the notes list widget.kycModel!.notes ??= []; // Initialize if null - widget.kycModel!.notes!.add(comment); + widget.kycModel!.notes!.add(rejectionNote); - _kycController.updateKycStatus(widget.kycModel!, "reject", comment); + // Call the controller method with the updated notes + _kycController.rejectKyc(widget.kycModel!.id.toString(), widget.kycModel!.notes![0].message,"Principal Distributer"); + + + showSnackbar("KYC rejected successfully"); + + // Delay closing the dialog to ensure the user sees the success message + Future.delayed(Duration(seconds: 1), () { + Get.back(); // Close the dialog after a delay + }); setState(() {}); - - Get.snackbar( - "Success", - "KYC rejected with comment: $comment", - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.green, - colorText: Colors.white, - ); - // Pass the updated model back to the previous screen - Get.back(); // Close the dialog - Get.back(result: widget.kycModel); // Pass the result back + // Close the dialog + // Pass the result back } else { - Get.snackbar( - "Error", - "Comment is required", - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.red, - colorText: Colors.white, - ); + showSnackbar("Comment is required"); + } }, child: const Text("Reject"), @@ -128,6 +141,11 @@ class _KycRetailerDetailScreenState + + + + + @override Widget build(BuildContext context) { return Scaffold( @@ -236,15 +254,16 @@ class _KycRetailerDetailScreenState ), ), SizedBox(height: Get.height * 0.01), + SizedBox( - width: Get.width*0.9, + width: Get.width * 0.9, child: Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.fromLTRB( - 16, 8, 8, 0), + if (widget.kycModel!.status == "new") + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 8, 0), child: Text( "Verification Options", style: GoogleFonts.roboto( @@ -253,82 +272,85 @@ class _KycRetailerDetailScreenState ), ), ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SizedBox( - width: Get.width * 0.4, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ElevatedButton( - onPressed: _approveKyc, - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: - const Color(0xFF004791), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), + // Conditionally render buttons based on KYC status + if (widget.kycModel!.status == "new" ) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + width: Get.width * 0.4, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: _approveKyc, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: const Color(0xFF004791), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), ), - ), - child: Text( - "Approve", - style: GoogleFonts.roboto( - fontSize: 14, - fontWeight: FontWeight.w400, + child: Text( + "Approve", + style: GoogleFonts.roboto( + fontSize: 14, + fontWeight: FontWeight.w400, + ), ), ), ), ), - ), - SizedBox( - width: Get.width * 0.4, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ElevatedButton( - onPressed: _rejectKyc, - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: - const Color(0xFF910000), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), + SizedBox( + width: Get.width * 0.4, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: _rejectKyc, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: const Color(0xFF910000), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), ), - ), - child: Text( - "Reject", - style: GoogleFonts.roboto( - fontSize: 14, - fontWeight: FontWeight.w400, + child: Text( + "Reject", + style: GoogleFonts.roboto( + fontSize: 14, + fontWeight: FontWeight.w400, + ), ), ), ), ), - ), - ], - ), + ], + ), + ], ], ), ), ), + SizedBox(height: Get.height * 0.01), - Card( - child: SizedBox( - width: Get.width*0.9, - height: Get.height * 0.2, - child: Padding( - padding: const EdgeInsets.all(12), - child: Text( - "Comment:${widget.kycModel!.notes}", - style: GoogleFonts.roboto( - fontSize: Get.width * 0.04, - fontWeight: FontWeight.w700, + //SizedBox(height: Get.height * 0.01), + if (widget.kycModel!.status == "reject") ...[ + Card( + child: SizedBox( + width: Get.width * 0.9, + height: Get.height * 0.2, + child: Padding( + padding: const EdgeInsets.all(12), + child: Text( + "Comment: ${widget.kycModel!.notes != null ? widget.kycModel!.notes!.map((note) => note.message).join(", ") : 'No comments'}", + style: GoogleFonts.roboto( + fontSize: Get.width * 0.04, + fontWeight: FontWeight.w700, + ), ), ), ), ), - ), + ], ], ), ), diff --git a/lib/screens/kyc/kyc_retailer_info_screen.dart b/lib/screens/kyc/kyc_retailer_info_screen.dart index f7e11dc..f6aadf1 100644 --- a/lib/screens/kyc/kyc_retailer_info_screen.dart +++ b/lib/screens/kyc/kyc_retailer_info_screen.dart @@ -32,12 +32,12 @@ class _KycRetailerInfoScreenState extends State { @override void initState() { super.initState(); - _kycController.loadKycFromLocalStorage(); + // _kycController.loadKycFromLocalStorage(); getKycData(); } Future _onRefresh() async { - // await getKycData(); + //navigateToKycDetail(_kycController.kycList as KycModel); await Future.delayed(Duration(seconds: 1)); } @@ -62,22 +62,7 @@ class _KycRetailerInfoScreenState extends State { - Future navigateToKycDetail(KycModel kycModel) async { - var result = await Get.to(() => KycRetailerDetailScreen(kycModel: kycModel)); - if (result != null) { - // Update the list or filter based on the result - KycModel updatedKycModel = result; - setState(() { - // Find and update the KYC in your list - int index = _kycController.kycList.indexWhere((kyc) => kyc.status == updatedKycModel.status); - if (index != -1) { - _kycController.kycList[index] = updatedKycModel; - _kycController.saveKycToLocalStorage(); // Persist updates - } - }); - } - } @override Widget build(BuildContext context) { return Scaffold( @@ -207,6 +192,7 @@ class _KycRetailerInfoScreenState extends State { itemCount: filteredOrders.length, itemBuilder: (context, index) { final order = filteredOrders[index]; + final kyc = _kycController.kycList[index]; return Padding( padding: const EdgeInsets.symmetric( @@ -321,7 +307,9 @@ class _KycRetailerInfoScreenState extends State { padding: const EdgeInsets.all(8.0), child: ElevatedButton( - onPressed: () => navigateToKycDetail(kyc), // KycRetailerDetailScreen( + onPressed: () { + Get.to(KycRetailerDetailScreen(kycModel: order)); + }, // KycRetailerDetailScreen( // kycModel: // _kycController // .kycList[ diff --git a/lib/utils/api_urls.dart b/lib/utils/api_urls.dart index 338a6a3..4cb5822 100644 --- a/lib/utils/api_urls.dart +++ b/lib/utils/api_urls.dart @@ -37,4 +37,8 @@ class ApiUrls { //============================== Kyc Details ==============================// static const String getKycUrl = '${baseUrl}/api/kyc/getAll'; + static const String updateKycUrl = '${baseUrl}/api/kyc/update'; + +//============================== Rd Order Details ==============================// + static const String getRdOrderUrl = '${baseUrl}/api/pd-get-new-orders'; }