Commit 77774bea authored by Sai Srinivas's avatar Sai Srinivas
Browse files

Few Correction and fixes

parents 2a8fa440 3ac9e198
......@@ -20,6 +20,8 @@
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<application
android:name="${applicationName}"
......
<svg width="19" height="20" viewBox="0 0 19 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_6785)">
<path d="M18.0696 4.83764C17.9731 3.8836 17.5599 2.99266 16.8994 2.31433C16.2388 1.63599 15.3711 1.21154 14.4419 1.1122L14.4135 1.10929C13.1486 0.969881 11.8774 0.898034 10.6052 0.894043C9.33305 0.8981 8.06197 0.970921 6.79726 1.1122L6.76857 1.11511C5.83994 1.21474 4.97284 1.63891 4.31249 2.31659C3.65214 2.99427 3.23864 3.8843 3.14123 4.83764C3.10581 5.19906 3.07252 5.58848 3.04525 6.00371C2.75509 6.00153 2.46501 6.01452 2.17614 6.04261C2.01088 6.06029 1.85657 6.13577 1.73908 6.25639C1.62159 6.37701 1.54807 6.53543 1.53085 6.70509V6.71018C1.51892 6.81617 1.51253 6.92273 1.51173 7.02942C1.51178 7.15729 1.51816 7.28508 1.53085 7.41229V7.41774C1.54807 7.5874 1.62159 7.74583 1.73908 7.86644C1.85657 7.98706 2.01088 8.06254 2.17614 8.08022C2.39218 8.10313 2.63655 8.11658 2.95282 8.1184C2.93629 8.7707 2.92791 9.46529 2.92767 10.2022C2.92767 10.911 2.93534 11.5802 2.95069 12.21C2.63549 12.2125 2.39182 12.2253 2.17614 12.2485C2.01088 12.2662 1.85657 12.3417 1.73908 12.4623C1.62159 12.5829 1.54807 12.7413 1.53085 12.911V12.9161C1.51892 13.022 1.51254 13.1284 1.51173 13.235C1.51148 13.3636 1.51763 13.4921 1.53014 13.62V13.6251C1.54778 13.7946 1.62157 13.9526 1.73916 14.0729C1.85676 14.1932 2.01102 14.2683 2.17614 14.2858C2.46336 14.3138 2.75178 14.3268 3.04029 14.3247C3.06863 14.7683 3.10192 15.1835 3.14088 15.5667C3.23769 16.5207 3.65097 17.4114 4.31145 18.0897C4.97192 18.768 5.83944 19.1925 6.76857 19.2922L6.7969 19.2951C7.92775 19.4151 9.45809 19.5103 10.6052 19.5103C11.7679 19.5103 13.2834 19.4151 14.4135 19.294L14.4419 19.2911C15.371 19.1918 16.2385 18.7675 16.8991 18.0894C17.5596 17.4113 17.9728 16.5206 18.0696 15.5667C18.2112 14.1691 18.2821 12.3642 18.2821 10.2022C18.2821 8.04023 18.2112 6.23532 18.0696 4.83764ZM10.5539 4.95872C11.0429 4.95872 11.5209 5.10759 11.9275 5.3865C12.3341 5.66541 12.651 6.06184 12.8381 6.52565C13.0252 6.98946 13.0742 7.49982 12.9788 7.9922C12.8834 8.48458 12.6479 8.93686 12.3021 9.29185C11.9564 9.64683 11.5158 9.88858 11.0362 9.98652C10.5566 10.0845 10.0595 10.0342 9.60772 9.84208C9.15594 9.64996 8.7698 9.32463 8.49813 8.90721C8.22646 8.48979 8.08145 7.99903 8.08145 7.49701C8.08141 7.16366 8.14533 6.83357 8.26956 6.52559C8.3938 6.21761 8.57591 5.93777 8.8055 5.70206C9.0351 5.46635 9.30767 5.27938 9.60766 5.15184C9.90765 5.0243 10.2292 4.95867 10.5539 4.95872ZM14.6792 13.624V13.6349C14.6374 14.0088 14.4847 14.3604 14.2418 14.6421C14.0026 14.9292 13.6797 15.1296 13.3209 15.2137C12.811 15.3326 11.5388 15.4493 10.7451 15.4435C9.95108 15.4638 8.39135 15.3373 7.88171 15.213C7.52297 15.1286 7.20016 14.9281 6.96088 14.641C6.71794 14.3593 6.56524 14.0077 6.52349 13.6338V13.6226C6.49677 13.353 6.48849 13.0818 6.4987 12.811C6.4987 12.811 6.47922 12.5721 6.52349 12.1387V12.1278C6.56045 11.7718 6.71551 11.4397 6.96265 11.1872C7.21107 10.9319 7.53667 10.771 7.88596 10.7309C8.39737 10.6752 9.95321 10.6451 10.7444 10.6451C11.5356 10.6451 12.8046 10.6752 13.316 10.7309C13.6653 10.771 13.9908 10.9321 14.2389 11.1875C14.4864 11.4403 14.6415 11.7729 14.6781 12.1293V12.1402C14.7036 12.3632 14.7164 12.5876 14.7163 12.8121C14.718 13.0832 14.7056 13.3543 14.6792 13.624Z" fill="url(#paint0_linear_1_6785)"/>
<path d="M18.0696 4.83764C17.9731 3.8836 17.5599 2.99266 16.8994 2.31433C16.2388 1.63599 15.3711 1.21154 14.4419 1.1122L14.4135 1.10929C13.1486 0.969881 11.8774 0.898034 10.6052 0.894043C9.33305 0.8981 8.06197 0.970921 6.79726 1.1122L6.76857 1.11511C5.83994 1.21474 4.97284 1.63891 4.31249 2.31659C3.65214 2.99427 3.23864 3.8843 3.14123 4.83764C3.10581 5.19906 3.07252 5.58848 3.04525 6.00371C2.75509 6.00153 2.46501 6.01452 2.17614 6.04261C2.01088 6.06029 1.85657 6.13577 1.73908 6.25639C1.62159 6.37701 1.54807 6.53543 1.53085 6.70509V6.71018C1.51892 6.81617 1.51253 6.92273 1.51173 7.02942C1.51178 7.15729 1.51816 7.28508 1.53085 7.41229V7.41774C1.54807 7.5874 1.62159 7.74583 1.73908 7.86644C1.85657 7.98706 2.01088 8.06254 2.17614 8.08022C2.39218 8.10313 2.63655 8.11658 2.95282 8.1184C2.93629 8.7707 2.92791 9.46529 2.92767 10.2022C2.92767 10.911 2.93534 11.5802 2.95069 12.21C2.63549 12.2125 2.39182 12.2253 2.17614 12.2485C2.01088 12.2662 1.85657 12.3417 1.73908 12.4623C1.62159 12.5829 1.54807 12.7413 1.53085 12.911V12.9161C1.51892 13.022 1.51254 13.1284 1.51173 13.235C1.51148 13.3636 1.51763 13.4921 1.53014 13.62V13.6251C1.54778 13.7946 1.62157 13.9526 1.73916 14.0729C1.85676 14.1932 2.01102 14.2683 2.17614 14.2858C2.46336 14.3138 2.75178 14.3268 3.04029 14.3247C3.06863 14.7683 3.10192 15.1835 3.14088 15.5667C3.23769 16.5207 3.65097 17.4114 4.31145 18.0897C4.97192 18.768 5.83944 19.1925 6.76857 19.2922L6.7969 19.2951C7.92775 19.4151 9.45809 19.5103 10.6052 19.5103C11.7679 19.5103 13.2834 19.4151 14.4135 19.294L14.4419 19.2911C15.371 19.1918 16.2385 18.7675 16.8991 18.0894C17.5596 17.4113 17.9728 16.5206 18.0696 15.5667C18.2112 14.1691 18.2821 12.3642 18.2821 10.2022C18.2821 8.04023 18.2112 6.23532 18.0696 4.83764ZM10.5539 4.95872C11.0429 4.95872 11.5209 5.10759 11.9275 5.3865C12.3341 5.66541 12.651 6.06184 12.8381 6.52565C13.0252 6.98946 13.0742 7.49982 12.9788 7.9922C12.8834 8.48458 12.6479 8.93686 12.3021 9.29185C11.9564 9.64683 11.5158 9.88858 11.0362 9.98652C10.5566 10.0845 10.0595 10.0342 9.60772 9.84208C9.15594 9.64996 8.7698 9.32463 8.49813 8.90721C8.22646 8.48979 8.08145 7.99903 8.08145 7.49701C8.08141 7.16366 8.14533 6.83357 8.26956 6.52559C8.3938 6.21761 8.57591 5.93777 8.8055 5.70206C9.0351 5.46635 9.30767 5.27938 9.60766 5.15184C9.90765 5.0243 10.2292 4.95867 10.5539 4.95872ZM14.6792 13.624V13.6349C14.6374 14.0088 14.4847 14.3604 14.2418 14.6421C14.0026 14.9292 13.6797 15.1296 13.3209 15.2137C12.811 15.3326 11.5388 15.4493 10.7451 15.4435C9.95108 15.4638 8.39135 15.3373 7.88171 15.213C7.52297 15.1286 7.20016 14.9281 6.96088 14.641C6.71794 14.3593 6.56524 14.0077 6.52349 13.6338V13.6226C6.49677 13.353 6.48849 13.0818 6.4987 12.811C6.4987 12.811 6.47922 12.5721 6.52349 12.1387V12.1278C6.56045 11.7718 6.71551 11.4397 6.96265 11.1872C7.21107 10.9319 7.53667 10.771 7.88596 10.7309C8.39737 10.6752 9.95321 10.6451 10.7444 10.6451C11.5356 10.6451 12.8046 10.6752 13.316 10.7309C13.6653 10.771 13.9908 10.9321 14.2389 11.1875C14.4864 11.4403 14.6415 11.7729 14.6781 12.1293V12.1402C14.7036 12.3632 14.7164 12.5876 14.7163 12.8121C14.718 13.0832 14.7056 13.3543 14.6792 13.624Z" fill="url(#paint1_linear_1_6785)"/>
<path d="M18.0696 4.83764C17.9731 3.8836 17.5599 2.99266 16.8994 2.31433C16.2388 1.63599 15.3711 1.21154 14.4419 1.1122L14.4135 1.10929C13.1486 0.969881 11.8774 0.898034 10.6052 0.894043C9.33305 0.8981 8.06197 0.970921 6.79726 1.1122L6.76857 1.11511C5.83994 1.21474 4.97284 1.63891 4.31249 2.31659C3.65214 2.99427 3.23864 3.8843 3.14123 4.83764C3.10581 5.19906 3.07252 5.58848 3.04525 6.00371C2.75509 6.00153 2.46501 6.01452 2.17614 6.04261C2.01088 6.06029 1.85657 6.13577 1.73908 6.25639C1.62159 6.37701 1.54807 6.53543 1.53085 6.70509V6.71018C1.51892 6.81617 1.51253 6.92273 1.51173 7.02942C1.51178 7.15729 1.51816 7.28508 1.53085 7.41229V7.41774C1.54807 7.5874 1.62159 7.74583 1.73908 7.86644C1.85657 7.98706 2.01088 8.06254 2.17614 8.08022C2.39218 8.10313 2.63655 8.11658 2.95282 8.1184C2.93629 8.7707 2.92791 9.46529 2.92767 10.2022C2.92767 10.911 2.93534 11.5802 2.95069 12.21C2.63549 12.2125 2.39182 12.2253 2.17614 12.2485C2.01088 12.2662 1.85657 12.3417 1.73908 12.4623C1.62159 12.5829 1.54807 12.7413 1.53085 12.911V12.9161C1.51892 13.022 1.51254 13.1284 1.51173 13.235C1.51148 13.3636 1.51763 13.4921 1.53014 13.62V13.6251C1.54778 13.7946 1.62157 13.9526 1.73916 14.0729C1.85676 14.1932 2.01102 14.2683 2.17614 14.2858C2.46336 14.3138 2.75178 14.3268 3.04029 14.3247C3.06863 14.7683 3.10192 15.1835 3.14088 15.5667C3.23769 16.5207 3.65097 17.4114 4.31145 18.0897C4.97192 18.768 5.83944 19.1925 6.76857 19.2922L6.7969 19.2951C7.92775 19.4151 9.45809 19.5103 10.6052 19.5103C11.7679 19.5103 13.2834 19.4151 14.4135 19.294L14.4419 19.2911C15.371 19.1918 16.2385 18.7675 16.8991 18.0894C17.5596 17.4113 17.9728 16.5206 18.0696 15.5667C18.2112 14.1691 18.2821 12.3642 18.2821 10.2022C18.2821 8.04023 18.2112 6.23532 18.0696 4.83764ZM10.5539 4.95872C11.0429 4.95872 11.5209 5.10759 11.9275 5.3865C12.3341 5.66541 12.651 6.06184 12.8381 6.52565C13.0252 6.98946 13.0742 7.49982 12.9788 7.9922C12.8834 8.48458 12.6479 8.93686 12.3021 9.29185C11.9564 9.64683 11.5158 9.88858 11.0362 9.98652C10.5566 10.0845 10.0595 10.0342 9.60772 9.84208C9.15594 9.64996 8.7698 9.32463 8.49813 8.90721C8.22646 8.48979 8.08145 7.99903 8.08145 7.49701C8.08141 7.16366 8.14533 6.83357 8.26956 6.52559C8.3938 6.21761 8.57591 5.93777 8.8055 5.70206C9.0351 5.46635 9.30767 5.27938 9.60766 5.15184C9.90765 5.0243 10.2292 4.95867 10.5539 4.95872ZM14.6792 13.624V13.6349C14.6374 14.0088 14.4847 14.3604 14.2418 14.6421C14.0026 14.9292 13.6797 15.1296 13.3209 15.2137C12.811 15.3326 11.5388 15.4493 10.7451 15.4435C9.95108 15.4638 8.39135 15.3373 7.88171 15.213C7.52297 15.1286 7.20016 14.9281 6.96088 14.641C6.71794 14.3593 6.56524 14.0077 6.52349 13.6338V13.6226C6.49677 13.353 6.48849 13.0818 6.4987 12.811C6.4987 12.811 6.47922 12.5721 6.52349 12.1387V12.1278C6.56045 11.7718 6.71551 11.4397 6.96265 11.1872C7.21107 10.9319 7.53667 10.771 7.88596 10.7309C8.39737 10.6752 9.95321 10.6451 10.7444 10.6451C11.5356 10.6451 12.8046 10.6752 13.316 10.7309C13.6653 10.771 13.9908 10.9321 14.2389 11.1875C14.4864 11.4403 14.6415 11.7729 14.6781 12.1293V12.1402C14.7036 12.3632 14.7164 12.5876 14.7163 12.8121C14.718 13.0832 14.7056 13.3543 14.6792 13.624Z" fill="url(#paint2_linear_1_6785)"/>
</g>
<defs>
<linearGradient id="paint0_linear_1_6785" x1="1.51102" y1="10.2022" x2="18.2831" y2="10.2022" gradientUnits="userSpaceOnUse">
<stop stop-color="#0080DE"/>
<stop offset="0.6" stop-color="#49BCFF"/>
<stop offset="1" stop-color="#61CAFF"/>
</linearGradient>
<linearGradient id="paint1_linear_1_6785" x1="9.89689" y1="9.14823" x2="19.7339" y2="31.5884" gradientUnits="userSpaceOnUse">
<stop stop-color="#B2B1FF"/>
<stop offset="1" stop-color="#6563FF"/>
</linearGradient>
<linearGradient id="paint2_linear_1_6785" x1="-4.27562" y1="-3.49093" x2="17.2947" y2="29.8665" gradientUnits="userSpaceOnUse">
<stop stop-color="#B2B1FF"/>
<stop offset="1" stop-color="#6563FF"/>
</linearGradient>
<clipPath id="clip0_1_6785">
<rect width="18.1332" height="18.6163" fill="white" transform="translate(0.808594 0.894043)"/>
</clipPath>
</defs>
</svg>
......@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- here is ok or not this BELOW the URL types section, NOT inside it -->
<key>NSContactsUsageDescription</key>
<string>This app needs access to your contacts to add and view contacts.</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
......
......@@ -5,7 +5,10 @@ class MissedCheckoutStripResponse {
int? sessionExists;
MissedCheckoutStripResponse(
{this.error, this.visibleText, this.message, this.sessionExists});
{this.error, this.visibleText, this.message, this.
sessionExists}
);
MissedCheckoutStripResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
......
class ContactListResponse {
String? error;
List<EmpContactList>? empContactList;
String? message;
int? sessionExists;
ContactListResponse(
{this.error, this.empContactList, this.message, this.sessionExists});
ContactListResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
if (json['emp_contact_list'] != null) {
empContactList = <EmpContactList>[];
json['emp_contact_list'].forEach((v) {
empContactList!.add(new EmpContactList.fromJson(v));
});
}
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
if (this.empContactList != null) {
data['emp_contact_list'] =
this.empContactList!.map((v) => v.toJson()).toList();
}
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
class EmpContactList {
String? name;
String? mobileNumber;
String? designation;
String? branchName;
String? profileImage;
EmpContactList(
{this.name, this.mobileNumber, this.designation, this.branchName});
EmpContactList.fromJson(Map<String, dynamic> json) {
name = json['name'];
mobileNumber = json['mobile_number'];
designation = json['designation'];
branchName = json['branch_name'];
profileImage = json['profile_image'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['mobile_number'] = this.mobileNumber;
data['designation'] = this.designation;
data['branch_name'] = this.branchName;
data['profile_image'] = this.profileImage;
return data;
}
}
......@@ -223,19 +223,31 @@ class Paymentdetailsprovider extends ChangeNotifier {
}
}
Future<void> PaymentUpdateAPI(BuildContext context, reference, amount) async {
bool _isPaymentUpdating = false;
bool get isPaymentUpdating => _isPaymentUpdating;
set isPaymentUpdating(bool value) {
_isPaymentUpdating = value;
notifyListeners();
}
Future<void> PaymentUpdateAPI(
BuildContext context,
reference,
amount,
) async {
if (_isPaymentUpdating) return; // 🛑 prevent re-tap
_isPaymentUpdating = true;
notifyListeners();
try {
// if(!CheckValidations(context,reference, amount)){
// return;
// }
if (!validateSubmit(context)) {
_isPaymentUpdating = false;
notifyListeners();
return;
}
print("came here");
var homeProvider = Provider.of<HomescreenNotifier>(
context,
listen: false,
);
var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.TechnicianUpdatepaymentAPI(
homeProvider.empId,
homeProvider.session,
......@@ -250,30 +262,40 @@ class Paymentdetailsprovider extends ChangeNotifier {
);
if (data != null) {
if (data.sessionExists == 1) {
if (data.error == 0) {
print(data.paymentCollectionId);
_CollectionId = data.paymentCollectionId ?? 0;
notifyListeners();
Future.delayed(Duration(microseconds: 200), () {
if (_CollectionId != 0) {
showOTPSheetSheet(context);
}
});
} else {}
} else {
// SharedpreferencesService().clearPreferences();
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Splash()),
// );
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");
}
} on Error catch (e) {
debugPrint(e.toString());
} 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<void> showOTPSheetSheet(BuildContext context) {
return showModalBottomSheet(
useSafeArea: true,
......@@ -502,12 +524,32 @@ class Paymentdetailsprovider extends ChangeNotifier {
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<void> OTPVerifyAPI(BuildContext context) async {
if (_isVerifyingOtp) return;
print("🎯 OTPVerifyAPI STARTED");
setVerifyingOtp(true);
try {
var homeProvider = Provider.of<HomescreenNotifier>(
context,
listen: false,
);
var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.TechnicianPaymentOTPValidateAPI(
homeProvider.empId,
homeProvider.session,
......@@ -515,81 +557,72 @@ class Paymentdetailsprovider extends ChangeNotifier {
_enteredOtp,
);
if (data != null) {
if (data.sessionExists == 1) {
if (data.error == 0) {
toast(context, data.message);
_selectContact = null;
_selectPaymentModeList = null;
_paymentModeID = "";
_PaymentMode = "";
_contactID = "";
_contact = "";
Amountcontroller.clear();
Referencecontroller.clear();
nameController.clear();
designationController.clear();
mobController.clear();
altMobController.clear();
telController.clear();
emailController.clear();
_imageName = null;
_image_picked = 0;
selectContactError = null;
selectPaymentError = null;
selectAmountError = null;
ReferenceError = null;
imageError = null;
notifyListeners();
Navigator.pop(context, true);
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 {
toast(context, data.message);
}
} else {
// SharedpreferencesService().clearPreferences();
// toast(context, data.message);
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Splash()),
// );
print("❌ OTP ERROR: ${data.message}");
toast(context, "❌ ${data.message}");
// Don't close the sheet - let user try again
}
} else {}
} on Error catch (e) {
debugPrint(e.toString());
} 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<void> ResendOtpAPI(BuildContext context) async {
if (_isResendingOtp) return;
print("🎯 ResendOtpAPI STARTED");
setResendingOtp(true);
try {
var homeProvider = Provider.of<HomescreenNotifier>(
context,
listen: false,
);
var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.TechnicianPaymentOTPResendAPI(
homeProvider.empId,
homeProvider.session,
_CollectionId,
);
if (data != null) {
if (data.sessionExists == 1) {
if (data.error == 0) {
toast(context, data.message);
} else {
toast(context, data.message);
}
} else {
// SharedpreferencesService().clearPreferences();
// toast(context, data.message);
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Splash()),
// );
}
} else {}
} on Error catch (e) {
debugPrint(e.toString());
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);
}
}
......
......@@ -21,6 +21,7 @@ import '../../Models/crmModels/GetSourceOnReferenceResponse.dart';
import '../../Models/crmModels/GetSubLocOnDistrictResponse.dart';
import '../../Models/crmModels/crmNewLeadsProspectsViewResponse.dart';
import '../../Utils/commonServices.dart';
import '../../Utils/custom_snackbar.dart';
import '../../services/api_calling.dart';
import '../HomeScreenNotifier.dart';
......@@ -614,21 +615,32 @@ class Addnewleadsandprospectsprovider extends ChangeNotifier {
} catch (e) {}
}
bool _isSubmitting = false;
bool get isSubmitting => _isSubmitting;
set isSubmitting(bool value) {
_isSubmitting = value;
notifyListeners();
}
Future<void> crmAddNewLeadsAndProspectsAPIFunction(
BuildContext context,
mode,
accManagerId,
salutationName,
district,
state,
segment,
source,
reference,
team,
subLocality,
leadStatus,
products,
) async {
BuildContext context,
mode,
accManagerId,
salutationName,
district,
state,
segment,
source,
reference,
team,
subLocality,
leadStatus,
products,
) async {
if (_isSubmitting) return; // 🛑 Prevent double taps
_isSubmitting = true;
notifyListeners();
try {
final prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.crmNewLeadsProspectsSubmitAPI(
......@@ -655,33 +667,68 @@ class Addnewleadsandprospectsprovider extends ChangeNotifier {
leadStatus,
products,
);
if (data != null) {
if (data.error == "0") {
Navigator.pushAndRemoveUntil(
context,
// ✅ Add debug print
print("🎯 API RESPONSE: $data");
if (data == null) {
print("❌ API returned null response");
if (context.mounted) toast(context, "No response from server");
return;
}
// ✅ Show debug info
print("✅ API Error Code: ${data.error}");
print("✅ Message: ${data.message}");
print("✅ Lead ID: ${data.leadId}");
if (data.error == "0") {
// 🕓 Small delay helps if widget rebuilds before navigation
await Future.delayed(const Duration(milliseconds: 200));
if (context.mounted) {
// ✅ Use root navigator so it always works
Navigator.of(context, rootNavigator: true).pushAndRemoveUntil(
MaterialPageRoute(
builder:
(context) => LeadDetailsByMode(
mode: "executive",
pageTitleName: "Lead Details",
leadId: data.leadId ?? "-",
),
settings: RouteSettings(name: "LeadDetailsByMode"),
builder: (_) => LeadDetailsByMode(
mode: "executive",
pageTitleName: "Lead Details",
leadId: data.leadId ?? "-",
),
settings: const RouteSettings(name: "LeadDetailsByMode"),
),
(Route<dynamic> route) {
return route.settings.name == 'CrmdashboardScreen';
},
(Route<dynamic> route) => route.settings.name == 'CrmdashboardScreen',
);
toast(context, data.message);
resetForm();
notifyListeners();
} else {}
} else {}
// ✅ Show success toast/snackbar AFTER navigation
Future.delayed(const Duration(milliseconds: 500), () {
if (context.mounted) {
toast(context, data.message ?? "Lead added successfully");
}
});
}
resetForm();
notifyListeners();
} else {
// ❌ Server returned an error
if (context.mounted) {
toast(context, data.message ?? "Something went wrong");
}
}
} catch (e, s) {
print("Error: $e, Stack: $s");
print("💥 Exception during CRM submit: $e");
print("📜 Stack: $s");
if (context.mounted) {
toast(context, "Unexpected error: ${e.toString()}");
}
} finally {
_isSubmitting = false;
notifyListeners();
}
}
Future<void> crmSelectedProductDetailsApiFunction(
BuildContext context,
String productId,
......
......@@ -357,20 +357,37 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
notifyListeners();
}
Future<void> paymentrequisitionRejectSubmitAPIFunction(
context,
mode,
paymentRequestId,
approveRemarks,
) async {
Future<bool> paymentrequisitionRejectSubmitAPIFunction(
context,
mode,
paymentRequestId,
approveRemarks,
) async {
print("🎯 === REJECT PROVIDER METHOD STARTED ===");
// Set loading to true at the start
_isLoading = true;
notifyListeners();
print("🔄 Loading set to TRUE in reject method");
bool success = false;
try {
print("🔍 Starting validation for rejection...");
if (approveRemarks.toString().trim().isEmpty) {
print("❌ Remarks validation failed");
remarksError = "Please Enter Remarks";
_isLoading = false;
notifyListeners();
// toast(context,"Enter Remarks");
return;
return false;
}
print("✅ Validation passed");
var provider = Provider.of<HomescreenNotifier>(context, listen: false);
print("🌐 Calling reject API...");
final data = await ApiCalling.RejectPaymentRequestSubmitAPI(
provider.empId,
provider.session,
......@@ -378,18 +395,60 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
paymentRequestId,
approveRemarks,
);
print("🌐 Reject API call completed");
if (data != null) {
print("📡 Reject API Response: error=${data.error}, message=${data.message}");
if (data.error == "0") {
paymentRequesitionDetails(context, paymentRequestId);
resetAll();
toast(context, data.message);
Navigator.pop(context);
print("✅ Reject API SUCCESS");
success = true;
if (context.mounted) {
print("🎯 Context mounted - performing UI operations");
paymentRequesitionDetails(context, paymentRequestId);
resetAll();
toast(context, data.message);
Navigator.pop(context, true); // Pass true to indicate success
}
} else {
print("❌ Reject API returned error: ${data.message}");
if (context.mounted) {
toast(context, data.message ?? "Rejection failed");
}
}
} else {
print("❌ NULL response from reject API");
if (context.mounted) {
toast(context, "No response from server");
}
}
} catch (e) {}
} catch (e) {
print("💥 EXCEPTION in reject provider method: $e");
if (context.mounted) {
toast(context, "Error: ${e.toString()}");
}
} finally {
// Always set loading to false when done
_isLoading = false;
notifyListeners();
print("🔄 Loading set to FALSE in reject method finally block");
}
print("🎯 === REJECT PROVIDER METHOD COMPLETED ===");
return success;
}
Future<void> paymentrequisitionApproveSubmitAPIFunction(
bool _isLoading = false;
bool get isLoading => _isLoading;
set isLoading(bool value) {
_isLoading = value;
notifyListeners();
}
Future<void> paymentrequisitionApproveSubmitAPIFunction(//this is
BuildContext context,
String mode,
String payment_request_id,
......@@ -399,10 +458,16 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
) async {
print("🎯 === PROVIDER METHOD STARTED ===");
// Set loading to true at the start
_isLoading = true;
notifyListeners();
try {
print("🔍 Starting validation...");
if (!validateApproval(approved_amount, approve_remarks, proposed_payment_account_id)) {
print("❌ VALIDATION FAILED - Stopping execution");
_isLoading = false;
notifyListeners();
return;
}
print("✅ Validation passed");
......@@ -462,13 +527,17 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
if (context.mounted) {
toast(context, "Error: ${e.toString()}");
}
} finally {
// Set loading to false when everything is done (success or error)
_isLoading = false;
notifyListeners();
print("🔄 Loading state set to false");
}
print("🎯 === PROVIDER METHOD COMPLETED ===");
}
editPrevalues() {
editPaymentRequestedAmountController.text =
_requestDetails.requestedAmount ?? "-";
......
import 'package:flutter/material.dart';
import '../../Models/hrmModels/contactListResponse.dart';
import '../../services/api_calling.dart';
class ContactProvider with ChangeNotifier {
bool _isLoading = false;
ContactListResponse? _contactResponse;
bool get isLoading => _isLoading;
ContactListResponse? get contactResponse => _contactResponse;
List<EmpContactList> get contactList =>
_contactResponse?.empContactList ?? [];
/// Fetch contact list from API
Future<void> fetchContactList(String session, String empId, int pageNumber) async {
_isLoading = true;
notifyListeners();
try {
final response = await ApiCalling.contactListAPI(session, empId, pageNumber);
_contactResponse = response;
} catch (e) {
debugPrint("❌ Error fetching contact list: $e");
_contactResponse = null;
} finally {
_isLoading = false;
notifyListeners();
}
}
/// Optional: To clear the list
void clearContacts() {
_contactResponse = null;
notifyListeners();
}
}
import 'package:flutter/material.dart';
class CustomSnackBar {
static void showSuccess({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 3),
}) {
_showCustomSnackBar(
context: context,
message: message,
backgroundColor: const Color(0xFF4CAF50), // Green
icon: Icons.check_circle,
duration: duration,
);
}
static void showError({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 4),
}) {
_showCustomSnackBar(
context: context,
message: message,
backgroundColor: const Color(0xFFF44336), // Red
icon: Icons.error,
duration: duration,
);
}
static void showInfo({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 3),
}) {
_showCustomSnackBar(
context: context,
message: message,
backgroundColor: const Color(0xFF2196F3), // Blue
icon: Icons.info,
duration: duration,
);
}
static void showWarning({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 4),
}) {
_showCustomSnackBar(
context: context,
message: message,
backgroundColor: const Color(0xFFFF9800), // Orange
icon: Icons.warning,
duration: duration,
);
}
static void showLoading({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 5),
}) {
_showCustomSnackBar(
context: context,
message: message,
backgroundColor: const Color(0xFF2d2d2d), // Dark gray
icon: Icons.hourglass_empty,
isLoading: true,
duration: duration,
);
}
static void _showCustomSnackBar({
required BuildContext context,
required String message,
required Color backgroundColor,
required IconData icon,
bool isLoading = false,
Duration duration = const Duration(seconds: 3),
}) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: backgroundColor,
duration: duration,
elevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.all(16),
content: Row(
children: [
if (isLoading)
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
else
Icon(
icon,
color: Colors.white,
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Text(
message,
style: const TextStyle(
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w500,
fontSize: 14,
color: Colors.white,
),
),
),
],
),
),
);
}
static void hide(BuildContext context) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
}
}
\ No newline at end of file
......@@ -423,6 +423,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => Orgprovider()),
ChangeNotifierProvider(create: (_) => AdvanceListProvider()),
ChangeNotifierProvider(create: (_) => CasualLeaveHistoryProvider()),
ChangeNotifierProvider(create: (_) => ContactProvider()),
],
child: Builder(
......
......@@ -535,7 +535,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
['S', 'M', 'T', 'W', 'T', 'F', 'S'][i],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: getResponsiveTextSize(context, 15),
fontSize: getResponsiveTextSize(context, 13),
overflow: TextOverflow.ellipsis,
color:
i == 0
......@@ -677,7 +677,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
child: Text(
currentDay.toString(),
style: TextStyle(
fontSize: getResponsiveTextSize(context, 13),
fontSize: getResponsiveTextSize(context, 12),
fontWeight: FontWeight.w400,
color:
isFutureDate
......@@ -870,8 +870,8 @@ class _AttendanceScreenState extends State<AttendanceScreen> {
Expanded(
flex: 1,
child: Container(
width: 25,
height: 25,
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors[index],
......
......@@ -11,6 +11,7 @@ import 'package:generp/Utils/commonWidgets.dart';
import '../Utils/commonServices.dart';
import 'JobDescription.dart';
import 'genTracker/ScanEnterGeneratorIDScreen.dart';
import 'hrm/ContactList.dart';
import 'hrm/HrmDashboardScreen.dart';
import 'notifierExports.dart';
import 'screensExports.dart';
......@@ -264,7 +265,7 @@ class _MyHomePageState extends State<MyHomePage> {
clipBehavior: Clip.none,
children: [
// ---------------- MISSED CHECKOUT STRIP BACKGROUND ----------------
if (profile.missedCheckoutData?.error != "1")
if (profile.missedCheckoutData?.error == "0")
Container(
height: 214, // Taller than the profile card
decoration: BoxDecoration(
......@@ -672,6 +673,7 @@ class _MyHomePageState extends State<MyHomePage> {
),
),
),
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
......@@ -835,6 +837,104 @@ class _MyHomePageState extends State<MyHomePage> {
),
),
],
SizedBox(height: 16,),
// Emp contact list
InkResponse(
onTap: () async {
HapticFeedback.selectionClick();
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) =>
ContactListScreen(),
),
);
if (res == true) {
homescreen.DashboardApiFunction(
context,
);
}
},
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 10,
),
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(14),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xFFEDF8FF),
),
child: Center(
child: SvgPicture.asset(
"assets/svg/hrm/emp_contact_list.svg",
color: Color(0xFF1487C9),
height: 24,
width: 24,
),
),
),
),
SizedBox(width: 10),
Expanded(
flex: 5,
child: SizedBox(
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
"Employee Contacts",
style: TextStyle(
fontSize: 14,
color:
AppColors
.app_blue,
fontFamily:
"JakartaMedium",
),
),
Text(
"Contact Details, Whatsapp",
style: TextStyle(
fontSize: 14,
color:
AppColors
.grey_semi,
fontFamily:
"JakartaMedium",
),
),
],
),
),
),
],
),
),
),
SizedBox(height: 4,),
Container(
margin: EdgeInsets.only(
left: 10,
......@@ -1151,6 +1251,102 @@ class _MyHomePageState extends State<MyHomePage> {
},
),
),
SizedBox(height: 16,),
// Emp contact list
InkResponse(
onTap: () async {
HapticFeedback.selectionClick();
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) =>
ContactListScreen(),
),
);
if (res == true) {
homescreen.DashboardApiFunction(
context,
);
}
},
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 10,
),
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.circular(14),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
height: 42,
width: 42,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xFFEDF8FF),
),
child: Center(
child: SvgPicture.asset(
"assets/svg/hrm/emp_contact_list.svg",
color: Color(0xFF1487C9),
height: 24,
width: 24,
),
),
),
),
SizedBox(width: 10),
Expanded(
flex: 5,
child: SizedBox(
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
"Employee Contacts",
style: TextStyle(
fontSize: 14,
color:
AppColors
.app_blue,
fontFamily:
"JakartaMedium",
),
),
Text(
"Contact Details, Whatsapp",
style: TextStyle(
fontSize: 14,
color:
AppColors
.grey_semi,
fontFamily:
"JakartaMedium",
),
),
],
),
),
),
],
),
),
),
SizedBox(height: 4,),
],
],
......
......@@ -11,6 +11,7 @@ import 'package:provider/provider.dart';
import '../../Utils/app_colors.dart';
import '../../Utils/commonServices.dart';
import '../../Utils/commonWidgets.dart';
import '../../Utils/custom_snackbar.dart';
import '../../Utils/dropdownTheme.dart';
class Addleadproductscreen extends StatefulWidget {
......@@ -286,35 +287,28 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
// Validate required fields
if (provider.selectedProducts == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please select a product"),
backgroundColor: Colors.red,
duration: Duration(seconds: 2),
),
//
CustomSnackBar.showWarning(
context: context,
message: "Please select a product",
);
return;
}
if (provider.addProductPriceController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please enter product price"),
backgroundColor: Colors.red,
duration: Duration(seconds: 2),
),
CustomSnackBar.showWarning(
context: context,
message: "Please enter product price",
);
return;
}
if (provider.addQuantityController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please enter quantity"),
backgroundColor: Colors.red,
duration: Duration(seconds: 2),
),
CustomSnackBar.showWarning(
context: context,
message: "Please enter quantity",
);
return;
}
......@@ -338,14 +332,11 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
print("Product data: ${provider.getJsonEncodedProducts()}");
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(widget.editIndex != null
? "Product updated successfully!"
: "Product added successfully!"),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
CustomSnackBar.showSuccess(
context: context,
message: widget.editIndex != null
? "Product updated successfully!"
: "Product added successfully!",
);
// Close screen after a short delay to show the success message
......
......@@ -18,6 +18,8 @@ import '../../Models/crmModels/GetSegmentOnTeamResponse.dart';
import '../../Models/crmModels/GetSourceOnReferenceResponse.dart';
import '../../Models/crmModels/GetSubLocOnDistrictResponse.dart';
import '../../Models/crmModels/crmNewLeadsProspectsViewResponse.dart';
import '../../Utils/custom_snackbar.dart';
import 'LeadDetailsByMode.dart';
import 'addLeadProductScreen.dart';
class Addleadsprospectsscreen extends StatefulWidget {
......@@ -1488,58 +1490,65 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
return Column(
children: [
if (_currentStep == 2) ...[
InkResponse(
onTap: () {
HapticFeedback.selectionClick();
if (provider.validateStep3()) {
if (provider.productRows.isNotEmpty) {
provider.crmAddNewLeadsAndProspectsAPIFunction(
context,
"",
provider.selectedEmployeesId,
provider.selectedSalutation,
provider.selectedDistrictId,
provider.selectedStatesId,
provider.selectedSegmentId,
provider.selectedSourcesId,
provider.selectedReferenceId,
provider.selectedReferenceId,
provider.selectedSubLocationId,
provider.selectedLeadStatus,
provider.getJsonEncodedProducts(),
);
} else {
toast(context, "Add min. 1 product");
}
}
InkResponse(
onTap: provider.isSubmitting
? null // disable taps while submitting
: () {
HapticFeedback.selectionClick();
if (provider.validateStep3()) {
if (provider.productRows.isNotEmpty) {
provider.crmAddNewLeadsAndProspectsAPIFunction(
context,
"",
provider.selectedEmployeesId,
provider.selectedSalutation,
provider.selectedDistrictId,
provider.selectedStatesId,
provider.selectedSegmentId,
provider.selectedSourcesId,
provider.selectedReferenceId,
provider.selectedReferenceId,
provider.selectedSubLocationId,
provider.selectedLeadStatus,
provider.getJsonEncodedProducts(),
);
} else {
toast(context, "Add min. 1 product");
}
}
details.onStepContinue;
},
child: Container(
height: 45,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15),
),
child: Text(
"Submit",
style: TextStyle(
fontSize: 15,
fontFamily: "JakartaMedium",
color: Colors.white,
),
),
),
details.onStepContinue;
},
child: Container(
height: 45,
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: provider.isSubmitting
? Colors.grey.shade400 // disable color
: AppColors.app_blue,
borderRadius: BorderRadius.circular(15),
),
child: provider.isSubmitting
? const SizedBox(
height: 22,
width: 22,
child: CircularProgressIndicator(
strokeWidth: 2.3,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: const Text(
"Submit",
style: TextStyle(
fontSize: 15,
fontFamily: "JakartaMedium",
color: Colors.white,
),
),
),
),
] else ...[
InkResponse(
onTap: () {
......
......@@ -444,9 +444,7 @@ class _AllpaymentrequesitionlistsbymodesState
_showLevelRejectionSheet(
context,
requestLists[index].id,
).then((_) {
provider.paymentRequestionListsAPIFunction(context, widget.mode, "", "");
});
);
},
backgroundColor: Color(
0xFFFFE5E5,
......@@ -524,10 +522,9 @@ class _AllpaymentrequesitionlistsbymodesState
);
_showLevelApprovalSheet(
context,
requestLists[index].id,
).then((_) {
provider.paymentRequestionListsAPIFunction(context, widget.mode, "", "");
});
requestLists[index].id.toString(),
);
},
backgroundColor: Color(
0xFFE9FFE8,
......@@ -654,7 +651,11 @@ class _AllpaymentrequesitionlistsbymodesState
);
}
Future<void> _showLevelApprovalSheet(BuildContext context, paymentID) {
Future<void> _showLevelApprovalSheet(
BuildContext context,
String paymentID
) {
return showModalBottomSheet(
useSafeArea: true,
isDismissible: true,
......@@ -859,10 +860,19 @@ class _AllpaymentrequesitionlistsbymodesState
),
),
InkWell(
onTap: () {
onTap: provider.isLoading
? null // Disable tap while loading
: () async {
HapticFeedback.selectionClick();
provider
.paymentrequisitionApproveSubmitAPIFunction(
// Immediately show loading
provider.isLoading = true;
// Small delay to ensure rebuild and show spinner before API starts
await Future.delayed(const Duration(milliseconds: 300));
// 🔄 Call API
await provider.paymentrequisitionApproveSubmitAPIFunction(
context,
widget.mode,
paymentID,
......@@ -870,25 +880,36 @@ class _AllpaymentrequesitionlistsbymodesState
remarks.text,
provider.selectedID,
);
// 🔓 Stop loading only if context is still active
if (context.mounted) {
provider.isLoading = false;
}
},
child: Container(
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
alignment: Alignment.center,
height: 45,
margin: EdgeInsets.only(
left: 5.0,
right: 5.0,
top: 5.0,
bottom: 5.0,
),
margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
decoration: BoxDecoration(
color: AppColors.app_blue, //1487C9
color: provider.isLoading ? Colors.grey : AppColors.app_blue,
borderRadius: BorderRadius.circular(14.0),
),
child: Center(
child: Text(
child: provider.isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: const Text(
"Submit",
///approve
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
......@@ -911,7 +932,7 @@ class _AllpaymentrequesitionlistsbymodesState
// Use the original context with mounted check
if (context.mounted) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
if (context.mounted) {
var provider = Provider.of<Requestionlistprovider>(
context,
......@@ -929,6 +950,13 @@ class _AllpaymentrequesitionlistsbymodesState
"",
"",
);
provider.resetPagination();
await provider.paymentRequestionListsAPIFunction(
context,
widget.mode,
"",
"",
);
}
});
}
......@@ -1000,7 +1028,10 @@ class _AllpaymentrequesitionlistsbymodesState
remarks,
"Remarks",
"Enter Remarks",
(p0) {},
(p0) {
provider.remarksError = null;
provider.notifyListeners();
},
TextInputType.text,
false,
null,
......@@ -1009,11 +1040,20 @@ class _AllpaymentrequesitionlistsbymodesState
TextInputAction.done,
),
errorWidget(context, provider.remarksError),
const SizedBox(height: 10),
InkWell(
onTap: () {
if (provider.isLoading) {
print("⏸️ Reject button is loading - ignoring tap");
return;
}
HapticFeedback.selectionClick();
provider
.paymentrequisitionRejectSubmitAPIFunction(
// Close keyboard
FocusScope.of(context).unfocus();
provider.paymentrequisitionRejectSubmitAPIFunction(
context,
widget.mode,
paymentID,
......@@ -1030,16 +1070,41 @@ class _AllpaymentrequesitionlistsbymodesState
bottom: 5.0,
),
decoration: BoxDecoration(
color: AppColors.app_blue, //1487C9
color: provider.isLoading ? Colors.grey : AppColors.app_blue,
borderRadius: BorderRadius.circular(14.0),
),
child: Center(
child: Text(
child: provider.isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
SizedBox(width: 10),
Text(
"Processing...",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
],
)
: Text(
"Submit",
///reject
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
......@@ -1077,6 +1142,8 @@ class _AllpaymentrequesitionlistsbymodesState
});
}
Future<void> _showAddPaymentSheet(BuildContext context, paymentID) {
return showModalBottomSheet(
useSafeArea: true,
......
......@@ -1326,7 +1326,6 @@ class _PaymentrequestionlistdetailsState
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -1407,73 +1406,59 @@ class _PaymentrequestionlistdetailsState
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
items:
provider.paymentsAccounts
items: provider.paymentsAccounts
.map(
(paymenents) => DropdownMenuItem<
PaymentAccounts
>(
PaymentAccounts>(
value: paymenents,
child: Text(
paymenents.name ?? '',
style: const TextStyle(
fontSize: 14,
),
overflow:
TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
),
),
)
.toList(),
value:
provider.paymentsAccounts.contains(
value: provider.paymentsAccounts.contains(
provider.selectedPaymentAccounts,
)
? provider.selectedPaymentAccounts
: null,
// value: provider.selectedPaymentAccounts,
onChanged: (PaymentAccounts? value) {
onChanged: provider.isLoading
? null // Disable dropdown when loading
: (PaymentAccounts? value) {
if (value != null) {
if (provider
.paymentsAccounts
.isNotEmpty) {
provider.selectedPaymentAccounts =
value;
if (provider.paymentsAccounts.isNotEmpty) {
provider.selectedPaymentAccounts = value;
print(
"Selected Complaint Type: ${value.name}, ID: ${value.id}",
);
provider.selectedID = value.id!;
provider.selectedValue = value.name!;
print(
"hfjkshfg" +
provider.selectedID.toString(),
"hfjkshfg" + provider.selectedID.toString(),
);
}
}
},
dropdownSearchData: DropdownSearchData(
searchInnerWidgetHeight: 50,
searchController:
provider
.paymentAccountSearchController,
searchController: provider.paymentAccountSearchController,
searchInnerWidget: Padding(
padding: const EdgeInsets.all(8),
child: TextFormField(
controller:
provider
.paymentAccountSearchController,
controller: provider.paymentAccountSearchController,
decoration: InputDecoration(
isDense: true,
contentPadding:
const EdgeInsets.symmetric(
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
hintText: 'Search account...',
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8),
),
),
),
......@@ -1486,21 +1471,16 @@ class _PaymentrequestionlistdetailsState
) ??
false;
},
// Optional: clear search text when dropdown closes
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
provider.paymentAccountSearchController
.clear();
provider.paymentAccountSearchController.clear();
}
},
buttonStyleData: ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData:
ddtheme.menuItemStyleData,
dropdownStyleData:
ddtheme.dropdownStyleData,
menuItemStyleData: ddtheme.menuItemStyleData,
dropdownStyleData: ddtheme.dropdownStyleData,
),
),
],
......@@ -1510,16 +1490,27 @@ class _PaymentrequestionlistdetailsState
context,
provider.selectpaymentAccountError,
),
const SizedBox(height: 10),
InkWell(
onTap: () {
if (provider.isLoading) {
print("⏸️ Button is loading - ignoring tap");
return;
}
print("🖱️ === SUBMIT BUTTON TAPPED ===");
print("📋 Mode: ${widget.mode}");
print("📋 Payment ID: $paymentID");
print("📋 Approved Amount: ${provider.approvedAmount.text}");
print("📋 Remarks: ${remarks.text}");
print("📋 Selected Account ID: ${provider.selectedID}");
provider
.paymentrequisitionApproveSubmitAPIFunction(
HapticFeedback.selectionClick();
// Close keyboard
FocusScope.of(context).unfocus();
provider.paymentrequisitionApproveSubmitAPIFunction(
context,
widget.mode,
paymentID,
......@@ -1538,16 +1529,41 @@ class _PaymentrequestionlistdetailsState
bottom: 5.0,
),
decoration: BoxDecoration(
color: AppColors.app_blue, //1487C9
color: provider.isLoading ? Colors.grey : AppColors.app_blue,
borderRadius: BorderRadius.circular(14.0),
),
child: Center(
child: Text(
child: provider.isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
SizedBox(width: 10),
Text(
"Processing...",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
],
)
: Text(
"Submit",
///approve
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
......@@ -1575,112 +1591,152 @@ class _PaymentrequestionlistdetailsState
enableDrag: true,
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return SafeArea(
child: Consumer<Requesitionlidtdetailsprovider>(
builder: (context, provider, child) {
return Container(
margin: EdgeInsets.only(
bottom: 15,
left: 15,
right: 15,
top: 10,
),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.mode == "apr_lvl1") ...[
Align(
alignment: Alignment.topLeft,
child: Text(
"Level 1 Rejection",
style: TextStyle(
color: AppColors.app_blue,
fontSize: 16,
),
),
// Remove StatefulBuilder and use only Provider
return SafeArea(
child: Consumer<Requesitionlidtdetailsprovider>(
builder: (context, provider, child) {
return Container(
margin: EdgeInsets.only(
bottom: 15,
left: 15,
right: 15,
top: 10,
),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.mode == "apr_lvl1") ...[
Align(
alignment: Alignment.topLeft,
child: Text(
"Level 1 Rejection",
style: TextStyle(
color: AppColors.app_blue,
fontSize: 16,
),
] else if (widget.mode == "apr_lvl2") ...[
Align(
alignment: Alignment.topLeft,
child: Text(
"Level 2 Rejection",
style: TextStyle(
color: AppColors.app_blue,
fontSize: 16,
),
),
),
),
] else if (widget.mode == "apr_lvl2") ...[
Align(
alignment: Alignment.topLeft,
child: Text(
"Level 2 Rejection",
style: TextStyle(
color: AppColors.app_blue,
fontSize: 16,
),
],
),
),
],
textControllerReadonlyWidget(
context,
provider.requestedAmount,
"Requested Amount",
textControllerReadonlyWidget(
context,
provider.requestedAmount,
"Requested Amount",
(p0) {},
),
),
textControllerWidget(
textControllerWidget(
context,
remarks,
"Remarks",
"Enter Remarks",
(p0) {
provider.remarksError = null;
provider.notifyListeners();
},
TextInputType.text,
false,
null,
focusNodes[2],
null,
TextInputAction.done,
),
errorWidget(context, provider.remarksError),
const SizedBox(height: 10),
InkWell(
onTap: () {
if (provider.isLoading) {
print("⏸️ Reject button is loading - ignoring tap");
return;
}
print("🖱️ === REJECT BUTTON TAPPED ===");
print("📋 Mode: ${widget.mode}");
print("📋 Payment ID: $paymentID");
print("📋 Remarks: ${remarks.text}");
HapticFeedback.selectionClick();
// Close keyboard
FocusScope.of(context).unfocus();
provider.paymentrequisitionRejectSubmitAPIFunction(
context,
remarks,
"Remarks",
"Enter Remarks",
(p0) {},
TextInputType.text,
false,
null,
focusNodes[2],
null,
TextInputAction.done,
widget.mode,
paymentID,
remarks.text,
);
},
child: Container(
alignment: Alignment.center,
height: 45,
margin: EdgeInsets.only(
left: 5.0,
right: 5.0,
top: 5.0,
bottom: 5.0,
),
errorWidget(context, provider.remarksError),
InkWell(
onTap: () {
provider
.paymentrequisitionRejectSubmitAPIFunction(
context,
widget.mode,
paymentID,
remarks.text,
);
},
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(14.0),
),
child: Center(
child: Text(
"Submit",
///reject
decoration: BoxDecoration(
color: provider.isLoading ? Colors.grey : AppColors.app_blue,
borderRadius: BorderRadius.circular(14.0),
),
child: Center(
child: provider.isLoading
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
SizedBox(width: 10),
Text(
"Processing...",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
],
)
: Text(
"Submit",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
);
},
),
);
},
],
),
),
);
},
),
);
},
);
......
......@@ -8,6 +8,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import '../../Notifiers/hrmProvider/attendanceListProvider.dart';
import '../../Utils/app_colors.dart';
import '../../Utils/custom_snackbar.dart';
import '../../Utils/dropdownTheme.dart';
class AddLiveAttendanceScreen extends StatefulWidget {
......@@ -224,8 +225,12 @@ class _AddLiveAttendanceScreenState extends State<AddLiveAttendanceScreen> {
}
void _showSnack(BuildContext context, String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(msg), backgroundColor: Colors.black87),
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text(msg), backgroundColor: Colors.black87),
// );
CustomSnackBar.showSuccess(
context: context,
message: "Status: $msg",
);
}
......
......@@ -16,6 +16,7 @@ import '../../Notifiers/hrmProvider/attendanceListProvider.dart';
import '../../Utils/app_colors.dart';
import '../../Utils/commonServices.dart';
import '../../Utils/commonWidgets.dart';
import '../../Utils/custom_snackbar.dart';
import '../../Utils/dropdownTheme.dart';
class AddManualAttendanceScreen extends StatefulWidget {
......@@ -397,13 +398,10 @@ class _AddManualAttendanceScreenState extends State<AddManualAttendanceScreen> {
// --- Response handling ---
if (provider.addResponse != null && provider.addResponse!.error == "0") {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
provider.addResponse!.message ??
"Attendance Submitted Successfully",
),
),
CustomSnackBar.showSuccess(
context: context,
message: provider.addResponse!.message ??
"Attendance Submitted Successfully",
);
// Reset fields
......
......@@ -398,7 +398,7 @@ class _AttendanceRequestDetailScreenState
provider.response?.requestDetails?.status !=
"Level 1 Approved" &&
provider.response?.requestDetails?.status !=
"Rejected")
"Level 1 Rejected")
? Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment