import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:generp/Notifiers/HomeScreenNotifier.dart'; import 'package:generp/Utils/SharedpreferencesService.dart'; import 'package:generp/Utils/app_colors.dart'; import 'package:generp/services/api_calling.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import '../Models/TechnicianLoadNumbersResponse.dart'; import '../Utils/commonServices.dart'; import '../screens/splash.dart'; import 'package:pin_code_fields/pin_code_fields.dart'; class Paymentdetailsprovider extends ChangeNotifier { TextEditingController Amountcontroller = TextEditingController(); TextEditingController Referencecontroller = TextEditingController(); TextEditingController nameController = TextEditingController(); TextEditingController designationController = TextEditingController(); TextEditingController mobController = TextEditingController(); TextEditingController altMobController = TextEditingController(); TextEditingController telController = TextEditingController(); TextEditingController emailController = TextEditingController(); String? nameError; String? designationError; String? mobError; String? altMobError; String? telError; String? emailError; String? selectContactError; String? selectPaymentError; String? selectAmountError; String? ReferenceError; String? imageError; List _payment_mode_drop_down = []; List _contacts_drop_down = []; String _paymentModeID = ""; String _PaymentMode = ""; String _contactID = ""; String _contact = ""; String _enteredOtp = ""; PaymentModeList? _selectPaymentModeList; Contacts? _selectContact; var _type = ""; var _refType = ""; var _refId = ""; final _account_id = ""; var _CollectionId = 0; var _image_picked = 0; final ImagePicker _picker = ImagePicker(); File? _image; File? _imageName; final bool _isLoading = true; List get paymentModeDropDown => _payment_mode_drop_down; List get contactsDropDown => _contacts_drop_down; PaymentModeList? get selectPaymentMode => _selectPaymentModeList; Contacts? get selectContact => _selectContact; String get paymentModeID => _paymentModeID; String get PaymentMode => _PaymentMode; String get contactID => _contactID; String get contact => _contact; String get enteredOtp => _enteredOtp; get type => _type; get refType => _refType; get refId => _refId; get account_id => _account_id; get CollectionId => _CollectionId; get image_picked => _image_picked; bool get isLoading => _isLoading; File? get imagePath => _imageName; File? get imageFilePath => _image; get imagePicked => _image_picked; set imagePath(File? value) { _imageName = value; notifyListeners(); } set imageFilePath(File? value) { _image = value; notifyListeners(); } set imagePicked(value) { _image_picked = value; notifyListeners(); } set enteredOtp(String value) { _enteredOtp = value; notifyListeners(); } set selectContact(value) { _selectContact = value; _contact = value?.name; _contactID = value?.mob1; selectContactError = null; notifyListeners(); } set selectPaymentMode(value) { _selectPaymentModeList = value; _PaymentMode = value?.name ?? ""; _paymentModeID = value?.id ?? ""; selectPaymentError = null; notifyListeners(); } set paymentModeID(value) { _paymentModeID = value; selectPaymentError = null; notifyListeners(); } set PaymentMode(value) { _PaymentMode = value; notifyListeners(); } set contact(value) { _contact = value; notifyListeners(); } set contactID(value) { _contactID = value; selectContactError = null; notifyListeners(); } Future LoadNumbersAPI( BuildContext context, accountName, referenceID, generatorID, ) async { if (accountName == "Generator") { _type = "generator"; _refType = "Complaint"; _refId = referenceID; } else { _type = "account"; _refType = "Account"; _refId = referenceID; } try { var homeProvider = Provider.of( context, listen: false, ); // print("${type}"); final data = await ApiCalling.LoadContactsTechnicianAPI( homeProvider.empId, homeProvider.session, _type, generatorID, _refId, ); if (data != null) { if (data.sessionExists == 1) { if (data.error == 0) { _contacts_drop_down = data.contacts!; _payment_mode_drop_down = data.paymentModeList!; if (_selectContact != null && !_contacts_drop_down.contains(_selectContact)) { _selectContact = null; _contact = ""; _contactID = ""; } if (_selectPaymentModeList != null && !_payment_mode_drop_down.contains(_selectPaymentModeList)) { _selectPaymentModeList = null; _PaymentMode = ""; _paymentModeID = ""; } Amountcontroller.clear(); Referencecontroller.clear(); _image = null; _imageName = null; _image_picked = 0; resetErrors(); notifyListeners(); } else {} } else { // SharedpreferencesService().clearPreferences(); // Navigator.push( // context, // MaterialPageRoute(builder: (context) => Splash()), // ); } } } on Error catch (e) { debugPrint(e.toString()); } } bool _isPaymentUpdating = false; bool get isPaymentUpdating => _isPaymentUpdating; set isPaymentUpdating(bool value) { _isPaymentUpdating = value; notifyListeners(); } Future PaymentUpdateAPI( BuildContext context, reference, amount, ) async { if (_isPaymentUpdating) return; // 🛑 prevent re-tap _isPaymentUpdating = true; notifyListeners(); try { if (!validateSubmit(context)) { _isPaymentUpdating = false; notifyListeners(); return; } var homeProvider = Provider.of(context, listen: false); final data = await ApiCalling.TechnicianUpdatepaymentAPI( homeProvider.empId, homeProvider.session, _refType, _refId, _paymentModeID, reference, amount, _contact, _contactID, _image, ); if (data != null) { if (data.sessionExists == 1 && data.error == 0) { _CollectionId = data.paymentCollectionId ?? 0; notifyListeners(); Future.delayed(const Duration(milliseconds: 200), () { if (_CollectionId != 0 && context.mounted) { showOTPSheetSheet(context); } }); } else if (context.mounted) { toast(context, data.message ?? "Payment update failed"); } } else { if (context.mounted) toast(context, "No response from server"); } } catch (e, s) { debugPrint("💥 PaymentUpdateAPI error: $e\n$s"); if (context.mounted) toast(context, "Something went wrong"); } finally { _isPaymentUpdating = false; notifyListeners(); } } bool _isOtpProcessing = false; bool get isOtpProcessing => _isOtpProcessing; set isOtpProcessing(bool value) { _isOtpProcessing = value; notifyListeners(); } Future showOTPSheetSheet(BuildContext context) { return showModalBottomSheet( useSafeArea: true, isDismissible: true, isScrollControlled: true, showDragHandle: true, backgroundColor: Colors.white, enableDrag: true, context: context, builder: (context) { return StatefulBuilder( builder: (context, setState) { return SafeArea( child: Padding( padding: EdgeInsets.only( bottom: MediaQuery.of( context, ).viewInsets.bottom, // This handles keyboard ), child: Container( margin: EdgeInsets.only( bottom: 15, left: 15, right: 15, top: 10, ), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Align( alignment: Alignment.center, child: Text( "Enter OTP", style: TextStyle( color: AppColors.app_blue, fontSize: 16, ), ), ), SizedBox(height: 15), Column( children: [ Container( alignment: Alignment.center, height: 50, margin: EdgeInsets.only(left: 5.0, right: 5.0), child: PinCodeTextField( appContext: context, pastedTextStyle: TextStyle( fontWeight: FontWeight.bold, ), length: 4, blinkWhenObscuring: true, animationType: AnimationType.fade, // validator: (v) { // if (v!.length < 3) { // return "I'm from validator"; // } else { // return null; // } // }, pinTheme: PinTheme( shape: PinCodeFieldShape.underline, borderRadius: BorderRadius.circular(16), fieldHeight: 60, fieldWidth: 60, activeFillColor: AppColors.text_field_color, activeColor: AppColors.app_blue, selectedColor: AppColors.text_field_color, selectedFillColor: AppColors.text_field_color, inactiveFillColor: AppColors.text_field_color, inactiveColor: AppColors.text_field_color, fieldOuterPadding: EdgeInsets.only( left: 5, right: 5, ), inactiveBorderWidth: 0, activeBorderWidth: 0.5, ), enableActiveFill: true, keyboardType: TextInputType.number, boxShadows: const [ BoxShadow( offset: Offset(0, 1), color: Colors.black12, blurRadius: 10, ), ], onCompleted: (String enteredCode) { enteredOtp = enteredCode; // clearText = true; OTPVerifyAPI(context); debugPrint("Completed"); }, // onTap: () { // print("Pressed"); // }, onChanged: (String enteredCode) { debugPrint(enteredCode); enteredOtp = enteredCode; }, onSubmitted: (String enteredCode) { enteredOtp = enteredCode; // clearText = true; // Verify_otp(); }, enablePinAutofill: true, useExternalAutoFillGroup: true, beforeTextPaste: (text) { debugPrint("Allowing to paste $text"); //if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen. //but you can show anything you want here, like your pop up saying wrong paste format or etc return true; }, ), ), SizedBox(height: 15), Container( alignment: Alignment.center, height: 45, margin: EdgeInsets.only( left: 5.0, right: 5.0, top: 5.0, bottom: 5.0, ), child: InkResponse( onTap: () { ResendOtpAPI(context); }, child: Center( child: Text( "Resend", style: TextStyle( fontWeight: FontWeight.w300, ), ), ), ), ), InkResponse( onTap: () { Navigator.of(context).pop(false); OTPVerifyAPI(context); }, child: Container( alignment: Alignment.center, height: 45, margin: EdgeInsets.only( left: 5.0, right: 5.0, top: 5.0, bottom: 5.0, ), decoration: BoxDecoration( color: AppColors.app_blue, //1487C9 borderRadius: BorderRadius.circular(15.0), ), child: Center( child: Text( "Submit", textAlign: TextAlign.center, style: TextStyle( fontSize: 15, fontFamily: "JakartaMedium", color: Colors.white, ), ), ), ), ), ], ), ], ), ), ), ), ); }, ); }, ); } bool validateSubmit(context) { selectContactError = null; selectPaymentError = null; selectAmountError = null; ReferenceError = null; imageError = null; bool isValid = true; print("clickedw"); if (_selectContact == null || _contactID.isEmpty) { selectContactError = "Please Select Contact"; isValid = false; } if (_selectPaymentModeList == null) { selectPaymentError = "Please Select Payment Type"; isValid = false; } if (Amountcontroller.text.trim().isEmpty) { selectAmountError = "Please Enter Amount"; isValid = false; } if (Referencecontroller.text.trim().isEmpty) { ReferenceError = "Please Enter Reference Number"; isValid = false; } if (_image_picked == 0) { imageError = "Please add attachment"; isValid = false; } notifyListeners(); return isValid; } bool _isResendingOtp = false; bool get isResendingOtp => _isResendingOtp; bool _isVerifyingOtp = false; bool get isVerifyingOtp => _isVerifyingOtp; void setResendingOtp(bool value) { print("🔄 setResendingOtp: $_isResendingOtp → $value"); _isResendingOtp = value; notifyListeners(); } void setVerifyingOtp(bool value) { print("🔄 setVerifyingOtp: $_isVerifyingOtp → $value"); _isVerifyingOtp = value; notifyListeners(); } Future OTPVerifyAPI(BuildContext context) async { if (_isVerifyingOtp) return; print("🎯 OTPVerifyAPI STARTED"); setVerifyingOtp(true); try { var homeProvider = Provider.of(context, listen: false); final data = await ApiCalling.TechnicianPaymentOTPValidateAPI( homeProvider.empId, homeProvider.session, _CollectionId, _enteredOtp, ); print("📡 OTP API Response: ${data?.error} - ${data?.message}"); if (data != null && data.sessionExists == 1) { if (data.error == 0) { print("✅ OTP SUCCESS"); toast(context, "✅ ${data.message}"); // Keep the loading visible for success feedback await Future.delayed(const Duration(milliseconds: 1000)); // Reset data _selectContact = null; Amountcontroller.clear(); Referencecontroller.clear(); notifyListeners(); // Only close the sheet after showing success if (context.mounted && Navigator.canPop(context)) { print("🚪 Closing sheet on success"); Navigator.pop(context, true); } } else { print("❌ OTP ERROR: ${data.message}"); toast(context, "❌ ${data.message}"); // Don't close the sheet - let user try again } } else { print("❌ API ERROR: Null response or session issue"); toast(context, "Something went wrong"); } } catch (e) { print("💥 OTP EXCEPTION: $e"); toast(context, "Something went wrong"); } finally { print("🏁 OTPVerifyAPI COMPLETED"); setVerifyingOtp(false); } } Future ResendOtpAPI(BuildContext context) async { if (_isResendingOtp) return; print("🎯 ResendOtpAPI STARTED"); setResendingOtp(true); try { var homeProvider = Provider.of(context, listen: false); final data = await ApiCalling.TechnicianPaymentOTPResendAPI( homeProvider.empId, homeProvider.session, _CollectionId, ); print("📡 Resend API Response: ${data?.message}"); if (data != null && data.sessionExists == 1) { toast(context, data.message ?? "OTP resent successfully"); } else { toast(context, "Failed to resend OTP"); } } catch (e) { print("💥 Resend EXCEPTION: $e"); toast(context, "Something went wrong"); } finally { print("🏁 ResendOtpAPI COMPLETED"); setResendingOtp(false); } } imgFromCamera(context, reference, amount) async { // Capture a photo try { final XFile? galleryImage = await _picker.pickImage( source: ImageSource.camera, imageQuality: 50, ); debugPrint("added"); _image = File(galleryImage!.path); _imageName = File(galleryImage.name); _image_picked = 1; imageError = null; notifyListeners(); } catch (e) { debugPrint("mmmm: ${e.toString()}"); } } imgFromGallery(context, reference, amount) async { // Pick an image try { final XFile? galleryImage = await _picker.pickImage( source: ImageSource.gallery, ); final bytes = (await galleryImage?.readAsBytes())?.lengthInBytes; final kb = bytes! / 1024; final mb = kb / 1024; debugPrint("Jenny: bytes:$bytes, kb:$kb, mb: $mb"); _image = File(galleryImage!.path); _imageName = File(galleryImage.name); _image_picked = 1; imageError = null; notifyListeners(); } catch (e) { debugPrint("mmmm: ${e.toString()}"); } } bool CheckValidations(BuildContext context, reference, amount) { bool isValid = true; if (_contactID == "") { toast(context, "Select Phone Number"); isValid = false; } if (_paymentModeID == "") { toast(context, "Select Payment Mode"); isValid = false; } if (amount.isEmpty) { toast(context, "Enter Amount"); isValid = false; } if (_image == "" || _image == null || _image_picked == 0) { toast(context, "Select Attachment"); isValid = false; } notifyListeners(); return isValid; } String _saveAgainst = ""; String _genId = ""; String _accountId = ""; String get saveAgainst => _saveAgainst; String get genId => _genId; String get accountId => _accountId; set saveAgainst(value) { _saveAgainst = value; notifyListeners(); } set genId(value) { _genId = value; notifyListeners(); } set accountId(value) { _accountId = value; } Future AddContactAPIFunction( BuildContext context, actName, generatorID, accountName, referenceID, genId, ) async { if (actName == "Generator") { _saveAgainst = "generator"; _genId = generatorID; } else { _saveAgainst = "account"; _accountId = generatorID; } notifyListeners(); if (!validAddContact(context)) { return; } try { var homeProvider = Provider.of( context, listen: false, ); final data = await ApiCalling.AddContactAPI( homeProvider.empId, homeProvider.session, _genId, nameController.text, designationController.text, mobController.text, altMobController.text, telController.text, emailController.text, _saveAgainst, _accountId, ); if (data != null) { if (data.sessionExists == 1) { if (data.error == 0) { toast(context, "Added Successfully"); resetAddContect(); LoadNumbersAPI(context, _saveAgainst, referenceID, genId); Navigator.pop(context, true); } else if (data.error == 1) { toast(context, data.message); } } else { // SharedpreferencesService().clearPreferences(); // Navigator.push( // context, // MaterialPageRoute( // builder: (context) => Splash())); } } } on Error catch (e) { print(e.toString()); } } void resetErrors() { nameError = null; designationError = null; mobError = null; altMobError = null; telError = null; emailError = null; selectContactError = null; selectPaymentError = null; selectAmountError = null; ReferenceError = null; imageError = null; notifyListeners(); } resetAddContect() { Amountcontroller.clear(); Referencecontroller.clear(); nameController.clear(); designationController.clear(); mobController.clear(); altMobController.clear(); telController.clear(); emailController.clear(); nameError = null; designationError = null; mobError = null; altMobError = null; telError = null; emailError = null; notifyListeners(); } bool validAddContact(context) { bool isValid = true; nameError = null; designationError = null; mobError = null; altMobError = null; telError = null; emailError = null; if (nameController.text.trim().toString().isEmpty) { nameError = "Please Enter Name"; isValid = false; } if (mobController.text.trim().toString().isEmpty) { mobError = "Please Enter Mobile Number"; isValid = false; } notifyListeners(); return isValid; } }