From 092f4de7d32c8a39d62fce15637b3eec9a481467 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Thu, 9 Oct 2025 23:31:28 +0300 Subject: [PATCH] 25-10-9/1 --- android/app/build.gradle | 4 +- ios/Runner/Info.plist | 4 +- lib/constant/notification.dart | 42 +- lib/controller/auth/login_controller.dart | 2 +- lib/controller/auth/otp_controller.dart | 21 +- .../payment/payment_controller.dart | 493 +++++++++--------- .../my_wallet/passenger_wallet_dialoge.dart | 125 ++--- 7 files changed, 344 insertions(+), 347 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8562203..e7fc4f0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -47,8 +47,8 @@ android { // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = 29 targetSdk = 36 - versionCode = 22 - versionName = '1.0.22' + versionCode = 25 + versionName = '1.0.25' multiDexEnabled = true ndk { abiFilters "armeabi-v7a", "arm64-v8a" diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 189283c..300fb74 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -33,11 +33,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 10 + 12 CFBundleSignature ???? CFBundleVersion - 1.0.10 + 1.0.12 FirebaseAppDelegateProxyEnabled NO GMSApiKey diff --git a/lib/constant/notification.dart b/lib/constant/notification.dart index 0a69066..5da2bf8 100644 --- a/lib/constant/notification.dart +++ b/lib/constant/notification.dart @@ -1,31 +1,31 @@ List passengerMessages = [ // --- رسائل العروض والتوفير --- - "مشاويرك علينا بأحلى الأسعار! 🚗 فوت على تطبيق انطلق وشوف العروض الجديدة اللي ناطرتك. 🌟", - "بدك توفّر بمشاويرك؟ 🤔 افتح تطبيق انطلق هلأ! أسعارنا ما بتلاقي متلها.", - "خصم خاص الك اليوم! 🎁 افتح تطبيق انطلق واحجز مشوارك الجاي بسعر أقل.", - "لا تحمل هم المصاريف! 💸 مع انطلق، كل مشاويرك اقتصادية ومريحة.", + "وفر على حالك: 🚗 أسعار انطلق نازلة كتير! شوف العروض الجديدة وفوت هلأ قبل ما تخلص. 🌟", + "خصم اليوم: 🤔 لا تفوّت الفرصة! افتح تطبيق انطلق وشوف الأسعار يلي ما بتنعاد.", + "عروض نارية: 🎁 اليوم خصم خاص إلك، احجز مشوارك الجاي بسعر ولا أروع!", + "مشاوير اقتصادية: 💸 مع انطلق بتتحرك براحتك وبتدفع أقل، جرب وشوف الفرق!", // --- رسائل السهولة والراحة --- - "كبسة زر ومشوارك صار عندك! 📲 افتح تطبيق انطلق واحجز بسهولة.", - "ليش معجوق بالمواصلات؟ 🤔 انطلق بيوصلك وين ما بدك براحة وسرعة.", - "سيارتك ناطرتك! 🚕 وين ما كنت، اطلب من انطلق وبنوصلك بأسرع وقت.", - "مشوارك الجاي مع انطلق! 🛣️ استرخي واستمتع بالطريق، نحنا بنهتم بالتفاصيل.", + "مشوار بكبسة زر: 📲 افتح تطبيق انطلق، وخلِّي السيارة توصلك لعندك بثواني.", + "ارتاح من المواصلات: 🤔 خلّي انطلق يريحك من الانتظار والزحمة، وانطلق وين ما بدك.", + "سيارتك جاهزة: 🚕 الكابتن ناطر طلبك، حدد وجهتك وخلّي الطريق علينا.", + "رحلة مريحة: 🛣️ ارتاح بالكرسي، نحنا منهتم بكل التفاصيل من الباب للباب.", // --- رسائل الأمان والثقة --- - "مشوارك آمن ومريح مع انطلق. 🙏 كباتنّا محترفين و بيهمنا توصل بالسلامة.", - "انطلق بقلب مطمن! 🔒 سلامتك أولويتنا بكل رحلة بتطلعها معنا.", - "مع انطلق، فيك تشارك تفاصيل رحلتك مع اللي بتحبن ليضل بالك مرتاح. ❤️", - "كل رحلاتنا مسجّلة لضمان أمانك. سافر بثقة مع انطلق. ✅", + "رحلتك بأمان: 🙏 كل كباتنّا مدرّبين وملتزمين، وسلامتك أولويتنا.", + "سافر وانت مطمّن: 🔒 مع انطلق كل شي موثوق ومسجّل لتكون مرتاح البال.", + "شارك رحلتك: ❤️ فيك تبعت تفاصيل المشوار لأهلك أو رفقاتك بخطوة وحدة.", + "انطلق بثقة: ✅ كل الرحلات مراقبة لتضمن تجربة آمنة ومريحة 100%.", - // --- رسائل تفاعلية ومناسبات خاصة --- - "الويكند بلّش! 🥳 مشاويرك مع الصحبة صارت أسهل وأوفر. اطلب انطلق.", - "رايح عالشغل؟ 💼 خلي انطلق يوصلك بلا عجقة السير وخليك مرتاح.", - "الدنيا شوب؟ ☀️ اطلب من انطلق والكابتن بيوصل لعندك.", - "تأخرت؟ لا تاكل هم! 🏃‍♂️ تطبيق انطلق هو أسرع طريق لتوصل عبكير.", + // --- رسائل تفاعلية ومناسبات --- + "الويكند بلّش: 🥳 خلي مشاويرك مع الأصحاب علينا، وفر وقتك وفلوسك مع انطلق.", + "رايح عالشغل: 💼 لا تتأخر، افتح التطبيق وخلي الكابتن يوصلك بلا تعب.", + "الشمس مولّعة: ☀️ لا تمشي تحت الحر، خلي السيارة تجي لعندك.", + "مستعجل: 🏃‍♂️ لا تقلق، انطلق أسرع طريق لتوصل عموعدك.", // --- رسائل تشجيعية عامة --- - "وين وجهتك اليوم؟ 🗺️ مدينة كاملة بانتظارك، وخلي مشوارك على انطلق.", - "جرّبت فئات سيارات انطلق الجديدة؟ 🚘 دلّل حالك بتجربة مميزة اليوم.", - "شكراً لاختيارك انطلق! ⭐ منتمنى الك دايماً رحلات سعيدة ومريحة.", - "عند انطلق كل شي جديد! ✨ فوت عالبرنامج وضلّك على اطلاع بآخر خدماتنا وعروضنا." + "وين رايح اليوم؟ 🗺️ وين ما كانت وجهتك، انطلق بيخدمك بكل مكان وبأي وقت.", + "جرب شي جديد: 🚘 شوف فئات السيارات الجديدة وخلي رحلتك أريح وأجمل.", + "شكراً لاختيارك: ⭐ وجودك معنا بيفرحنا، ونتمنى دايماً تكون رحلتك مريحة وسعيدة.", + "كل يوم جديد: ✨ فوت عالتطبيق وتابع آخر التحديثات والعروض يلي نازلة خصيصاً إلك." ]; diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index 4068bed..c2847e6 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -48,7 +48,7 @@ class LoginController extends GetxController { var dev = ''; @override void onInit() async { - // await getAppTester(); + await getJWT(); // Log.print('box.read(BoxName.isTest): ${box.read(BoxName.isTest)}'); box.write(BoxName.countryCode, 'Syria'); FirebaseMessagesController().getToken(); diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart index cc0aa2c..185b2a5 100644 --- a/lib/controller/auth/otp_controller.dart +++ b/lib/controller/auth/otp_controller.dart @@ -22,26 +22,29 @@ class PhoneAuthHelper { /// Sends an OTP to the provided phone number. static Future sendOtp(String phoneNumber) async { try { + // Log.print('_sendOtpUrl: ${_sendOtpUrl}'); + // Log.print('phoneNumber: ${phoneNumber}'); + final response = await CRUD().post( link: _sendOtpUrl, payload: {'receiver': phoneNumber}, ); - Log.print('response: ${response}'); + // Log.print('response: ${response}'); if (response != 'failure') { final data = (response); - // if (data['status'] == 'success') { - mySnackbarSuccess('An OTP has been sent to your WhatsApp number.'.tr); - return true; - // } else { - // mySnackeBarError(data['message'] ?? 'Failed to send OTP.'); - // return false; - // } + if (data['status'] == 'success') { + mySnackbarSuccess('An OTP has been sent to your WhatsApp number.'.tr); + return true; + } else { + mySnackeBarError(data['message'] ?? 'Failed to send OTP.'); + return false; + } } else { mySnackeBarError('Server error. Please try again.'.tr); return false; } } catch (e) { - Log.print('e: ${e}'); + // Log.print('e: ${e}'); // mySnackeBarError('An error occurred: $e'); return false; } diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart index fef6975..7cd292d 100644 --- a/lib/controller/payment/payment_controller.dart +++ b/lib/controller/payment/payment_controller.dart @@ -673,312 +673,305 @@ class PaymentController extends GetxController { /// شاشة جديدة ومبسطة خاصة بدفع السائقين عبر ecash - Future payWithMTNWallet( - BuildContext context, String amount, String currency) async { - // خزن سياق علوي آمن من البداية - final BuildContext safeContext = - Get.overlayContext ?? Get.context ?? context; + // Future payWithMTNWallet( + // BuildContext context, String amount, String currency) async { + // // خزن سياق علوي آمن من البداية + // final BuildContext safeContext = + // Get.overlayContext ?? Get.context ?? context; - // سبينر تحميل - if (!(Get.isDialogOpen ?? false)) { - Get.dialog(const Center(child: CircularProgressIndicator()), - barrierDismissible: false); + // // سبينر تحميل + // if (!(Get.isDialogOpen ?? false)) { + // Get.dialog(const Center(child: CircularProgressIndicator()), + // barrierDismissible: false); + // } + + // try { + // final phone = box.read(BoxName.phoneWallet) as String; + // final passengerID = box.read(BoxName.passengerID).toString(); + // final formattedAmount = double.parse(amount).toStringAsFixed(0); + + // print("🚀 بدء عملية دفع MTN"); + // print( + // "📦 Payload: passengerID: $passengerID, amount: $formattedAmount, phone: $phone"); + + // // التحقق بالبصمة (اختياري) + حماية من الـ await + // final localAuth = LocalAuthentication(); + // final isAuthSupported = await localAuth.isDeviceSupported(); + // if (isAuthSupported) { + // final didAuth = await localAuth.authenticate( + // localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع', + // ); + // if (!didAuth) { + // if (Get.isDialogOpen == true) Get.back(); + // print("❌ المستخدم لم يؤكد بالبصمة/الوجه"); + // return; + // } + // } + + // // 1) بدء الدفع + // final responseData = await CRUD().postWalletMtn( + // link: AppLink.payWithMTNStart, + // payload: { + // "amount": formattedAmount, + // "passengerId": passengerID, + // "phone": phone, + // "lang": box.read(BoxName.lang) ?? 'ar', + // }, + // ); + + // // print("✅ استجابة الخادم (mtn_start_payment.php):"); + // // print(responseData); + // Log.print('responseData: ${responseData}'); + + // // فحص الاستجابة بقوة + // late final Map startRes; + // if (responseData is Map) { + // startRes = responseData; + // } else if (responseData is String) { + // startRes = json.decode(responseData) as Map; + // } else { + // throw Exception("تم استلام نوع بيانات غير متوقع من الخادم."); + // } + + // if (startRes['status'] != 'success') { + // final errorMsg = startRes['message']['Error']?.toString().tr ?? + // "فشل بدء عملية الدفع. حاول مرة أخرى."; + // throw Exception(errorMsg); + // } + + // final messageData = startRes["message"] as Map; + // final invoiceNumber = messageData["invoiceNumber"].toString(); + // final operationNumber = messageData["operationNumber"].toString(); + // final guid = messageData["guid"].toString(); + + // // print( + // // "📄 invoiceNumber: $invoiceNumber, 🔢 operationNumber: $operationNumber, 🧭 guid: $guid"); + + // // أغلق السبينر قبل إظهار حوار OTP + // if (Get.isDialogOpen == true) Get.back(); + + // // 2) إدخال OTP بـ Get.defaultDialog (لا يستخدم context قابل للتلف) + // String otpInput = ""; + // await Get.defaultDialog( + // title: "أدخل كود التحقق", + // barrierDismissible: false, + // content: TextField( + // keyboardType: TextInputType.number, + // decoration: const InputDecoration(hintText: "كود OTP"), + // onChanged: (v) => otpInput = v, + // ), + // confirm: TextButton( + // onPressed: () { + // if (otpInput.isEmpty || + // otpInput.length < 4 || + // otpInput.length > 8) { + // Get.snackbar("تنبيه", "أدخل كود OTP صحيح (4–8 أرقام)"); + // return; + // } + // Get.back(result: otpInput); + // }, + // child: const Text("تأكيد"), + // ), + // cancel: TextButton( + // onPressed: () => Get.back(result: null), + // child: const Text("إلغاء"), + // ), + // ).then((res) => otpInput = (res ?? "") as String); + + // if (otpInput.isEmpty) { + // print("❌ لم يتم إدخال OTP"); + // return; + // } + // print("🔐 تم إدخال OTP: $otpInput"); + + // // سبينر أثناء التأكيد + // Get.dialog(const Center(child: CircularProgressIndicator()), + // barrierDismissible: false); + + // // 3) تأكيد الدفع + // final confirmRes = await CRUD().postWalletMtn( + // link: AppLink.payWithMTNConfirm, + // payload: { + // "invoiceNumber": invoiceNumber, + // "operationNumber": operationNumber, + // "guid": guid, + // "otp": otpInput, + // "phone": phone, + // "lang": box.read(BoxName.lang) ?? 'ar', + // }, + // ); + + // if (Get.isDialogOpen == true) Get.back(); + + // // print("✅ استجابة mtn_confirm.php:"); + // // Log.print('confirmRes: ${confirmRes}'); + + // final ok = (confirmRes is Map && confirmRes['status'] == 'success'); + // if (ok) { + // Get.defaultDialog( + // title: "✅ نجاح", + // content: const Text("تمت عملية الدفع وإضافة الرصيد إلى محفظتك."), + // ); + // await getPassengerWallet(); + // } else { + // final errorMsg = (confirmRes['message']['message']?.toString()) ?? + // "فشل في تأكيد الدفع"; + // Get.defaultDialog(title: "❌ فشل", content: Text(errorMsg.tr)); + // } + // } catch (e, s) { + // print("🔥 خطأ أثناء الدفع عبر MTN:"); + // print(e); + // print(s); + // if (Get.isDialogOpen == true) Get.back(); + // Get.defaultDialog( + // title: 'حدث خطأ', + // content: Text(e.toString().replaceFirst("Exception: ", "")), + // ); + // } + // } + + Future payWithSyriaTelWallet(String amount, String currency) async { + // helper لفتح لودينغ بأمان + Future _showLoading() async { + if (!(Get.isDialogOpen ?? false)) { + Get.dialog(const Center(child: CircularProgressIndicator()), + barrierDismissible: false); + } } + // helper لإغلاق أي حوار مفتوح + void _closeAnyDialog() { + if (Get.isDialogOpen ?? false) { + Get.back(); + } + } + + await _showLoading(); try { final phone = box.read(BoxName.phoneWallet) as String; - final passengerID = box.read(BoxName.passengerID).toString(); + final passengerId = box.read(BoxName.passengerID).toString(); final formattedAmount = double.parse(amount).toStringAsFixed(0); - print("🚀 بدء عملية دفع MTN"); + print("🚀 Syriatel payment start"); print( - "📦 Payload: passengerID: $passengerID, amount: $formattedAmount, phone: $phone"); + "📦 Payload => passengerId:$passengerId amount:$formattedAmount phone:$phone"); - // التحقق بالبصمة (اختياري) + حماية من الـ await - final localAuth = LocalAuthentication(); - final isAuthSupported = await localAuth.isDeviceSupported(); - if (isAuthSupported) { - final didAuth = await localAuth.authenticate( + // مصادقة حيوية (اختياري) + final auth = LocalAuthentication(); + if (await auth.isDeviceSupported()) { + final ok = await auth.authenticate( localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع', ); - if (!didAuth) { - if (Get.isDialogOpen == true) Get.back(); - print("❌ المستخدم لم يؤكد بالبصمة/الوجه"); + if (!ok) { + _closeAnyDialog(); + print("❌ User did not authenticate"); return; } } - // 1) بدء الدفع - final responseData = await CRUD().postWalletMtn( - link: AppLink.payWithMTNStart, + // 1) بدء عملية الدفع + final startRaw = await CRUD().postWalletMtn( + link: AppLink.payWithSyriatelStart, payload: { "amount": formattedAmount, - "passengerId": passengerID, + "passengerId": passengerId, "phone": phone, "lang": box.read(BoxName.lang) ?? 'ar', }, ); - // print("✅ استجابة الخادم (mtn_start_payment.php):"); - // print(responseData); - Log.print('responseData: ${responseData}'); + print("✅ Server response (start): $startRaw"); - // فحص الاستجابة بقوة + // تحويل الاستجابة إلى Map late final Map startRes; - if (responseData is Map) { - startRes = responseData; - } else if (responseData is String) { - startRes = json.decode(responseData) as Map; + if (startRaw is Map) { + startRes = startRaw; + } else if (startRaw is String) { + startRes = json.decode(startRaw) as Map; } else { - throw Exception("تم استلام نوع بيانات غير متوقع من الخادم."); + throw Exception("Unexpected start response type"); } if (startRes['status'] != 'success') { - final errorMsg = startRes['message']['Error']?.toString().tr ?? - "فشل بدء عملية الدفع. حاول مرة أخرى."; - throw Exception(errorMsg); + final msg = + (startRes['message'] ?? 'Failed to start payment').toString(); + throw Exception(msg); } - final messageData = startRes["message"] as Map; - final invoiceNumber = messageData["invoiceNumber"].toString(); - final operationNumber = messageData["operationNumber"].toString(); - final guid = messageData["guid"].toString(); + final messageData = startRes['message'] as Map; + final transactionID = messageData['transactionID'].toString(); + print("📄 transactionID: $transactionID"); - // print( - // "📄 invoiceNumber: $invoiceNumber, 🔢 operationNumber: $operationNumber, 🧭 guid: $guid"); - - // أغلق السبينر قبل إظهار حوار OTP - if (Get.isDialogOpen == true) Get.back(); - - // 2) إدخال OTP بـ Get.defaultDialog (لا يستخدم context قابل للتلف) - String otpInput = ""; - await Get.defaultDialog( - title: "أدخل كود التحقق", - barrierDismissible: false, - content: TextField( - keyboardType: TextInputType.number, - decoration: const InputDecoration(hintText: "كود OTP"), - onChanged: (v) => otpInput = v, - ), - confirm: TextButton( - onPressed: () { - if (otpInput.isEmpty || - otpInput.length < 4 || - otpInput.length > 8) { - Get.snackbar("تنبيه", "أدخل كود OTP صحيح (4–8 أرقام)"); - return; - } - Get.back(result: otpInput); - }, - child: const Text("تأكيد"), - ), - cancel: TextButton( - onPressed: () => Get.back(result: null), - child: const Text("إلغاء"), - ), - ).then((res) => otpInput = (res ?? "") as String); - - if (otpInput.isEmpty) { - print("❌ لم يتم إدخال OTP"); - return; - } - print("🔐 تم إدخال OTP: $otpInput"); - - // سبينر أثناء التأكيد - Get.dialog(const Center(child: CircularProgressIndicator()), - barrierDismissible: false); - - // 3) تأكيد الدفع - final confirmRes = await CRUD().postWalletMtn( - link: AppLink.payWithMTNConfirm, - payload: { - "invoiceNumber": invoiceNumber, - "operationNumber": operationNumber, - "guid": guid, - "otp": otpInput, - "phone": phone, - "lang": box.read(BoxName.lang) ?? 'ar', - }, - ); - - if (Get.isDialogOpen == true) Get.back(); - - // print("✅ استجابة mtn_confirm.php:"); - // Log.print('confirmRes: ${confirmRes}'); - - final ok = (confirmRes is Map && confirmRes['status'] == 'success'); - if (ok) { - Get.defaultDialog( - title: "✅ نجاح", - content: const Text("تمت عملية الدفع وإضافة الرصيد إلى محفظتك."), - ); - await getPassengerWallet(); - } else { - final errorMsg = (confirmRes['message']['message']?.toString()) ?? - "فشل في تأكيد الدفع"; - Get.defaultDialog(title: "❌ فشل", content: Text(errorMsg.tr)); - } - } catch (e, s) { - print("🔥 خطأ أثناء الدفع عبر MTN:"); - print(e); - print(s); - if (Get.isDialogOpen == true) Get.back(); - Get.defaultDialog( - title: 'حدث خطأ', - content: Text(e.toString().replaceFirst("Exception: ", "")), - ); - } - } - - Future payWithSyriaTelWallet( - BuildContext context, String amount, String currency) async { - // Show a loading indicator for better user experience - Get.dialog(const Center(child: CircularProgressIndicator()), - barrierDismissible: false); - - try { - String phone = box.read(BoxName.phoneWallet); - String driverID = box.read(BoxName.driverID).toString(); - String formattedAmount = double.parse(amount).toStringAsFixed(0); - - // --- CHANGE 1: Updated log messages for clarity --- - print("🚀 Starting Syriatel payment process"); - print( - "📦 Payload: driverID: $driverID, amount: $formattedAmount, phone: $phone"); - - // Optional: Biometric authentication - bool isAuthSupported = await LocalAuthentication().isDeviceSupported(); - if (isAuthSupported) { - bool didAuthenticate = await LocalAuthentication().authenticate( - localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع', - ); - if (!didAuthenticate) { - if (Get.isDialogOpen ?? false) Get.back(); - print("❌ User did not authenticate with biometrics"); - return; - } - } - - // --- CHANGE 2: Updated API link and payload for starting payment --- - // Make sure you have defined `payWithSyriatelStart` in your AppLink class - var responseData = await CRUD().postWalletMtn( - link: AppLink.payWithSyriatelStart, // Use the new Syriatel start link - payload: { - "amount": formattedAmount, - "driverId": driverID, // Key changed from 'passengerId' to 'driverId' - "phone": phone, - "lang": box.read(BoxName.lang) ?? 'ar', - }, - ); - - print("✅ Server response (start_payment.php):"); - print(responseData); - - // Robustly parse the server's JSON response - Map startRes; - if (responseData is Map) { - startRes = responseData; - } else if (responseData is String) { - try { - startRes = json.decode(responseData); - } catch (e) { - throw Exception( - "Failed to parse server response. Response: $responseData"); - } - } else { - throw Exception("Received an unexpected data type from the server."); - } - - if (startRes['status'] != 'success') { - String errorMsg = startRes['message']?.toString() ?? - "Failed to start the payment process. Please try again."; - throw Exception(errorMsg); - } - - // --- CHANGE 3: Extract `transactionID` from the response --- - // The response structure is now simpler. We only need the transaction ID. - final messageData = startRes["message"]; - final transactionID = messageData["transactionID"].toString(); - - print("📄 TransactionID: $transactionID"); - - if (Get.isDialogOpen == true) Get.back(); // Close loading indicator - - // Show the OTP input dialog - String? otp = await showDialog( - context: context, - barrierDismissible: false, - builder: (context) { - String input = ""; - return AlertDialog( - title: const Text("أدخل كود التحقق"), - content: TextField( - keyboardType: TextInputType.number, - decoration: const InputDecoration(hintText: "كود OTP"), - onChanged: (val) => input = val, + // 2) اطلب من المستخدم إدخال OTP عبر Get.dialog (بدون context) + _closeAnyDialog(); // أغلق اللودينغ أولاً + final otpController = TextEditingController(); + final otp = await Get.dialog( + AlertDialog( + title: const Text("أدخل كود التحقق"), + content: TextField( + controller: otpController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(hintText: "كود OTP"), + ), + actions: [ + TextButton( + child: const Text("تأكيد"), + onPressed: () => Get.back(result: otpController.text.trim()), ), - actions: [ - TextButton( - child: const Text("تأكيد"), - onPressed: () => Navigator.of(context).pop(input), - ), - TextButton( - child: const Text("إلغاء"), - onPressed: () => Navigator.of(context).pop(), - ), - ], - ); - }, + TextButton( + child: const Text("إلغاء"), + onPressed: () => Get.back(result: null), + ), + ], + ), + barrierDismissible: false, ); if (otp == null || otp.isEmpty) { - print("❌ OTP was not entered."); + print("❌ OTP not provided"); return; } - print("🔐 OTP entered: $otp"); + print("🔐 OTP: $otp"); - Get.dialog(const Center(child: CircularProgressIndicator()), - barrierDismissible: false); + await _showLoading(); - // --- CHANGE 4: Updated API link and payload for confirming payment --- - // Make sure you have defined `payWithSyriatelConfirm` in your AppLink class - var confirmRes = await CRUD().postWallet( - // Changed from postWalletMtn if they are different - link: - AppLink.payWithSyriatelConfirm, // Use the new Syriatel confirm link + // 3) تأكيد الدفع + final confirmRaw = await CRUD().postWallet( + link: AppLink.payWithSyriatelConfirm, payload: { - "transactionID": transactionID, // Use the transaction ID + "transactionID": transactionID, "otp": otp, - // The other parameters (phone, guid, etc.) are no longer needed }, ); - if (Get.isDialogOpen ?? false) Get.back(); + _closeAnyDialog(); // أغلق اللودينغ - print("✅ Response from confirm_payment.php:"); - Log.print('confirmRes: ${confirmRes}'); + print("✅ Response (confirm): $confirmRaw"); - if (confirmRes != null && confirmRes['status'] == 'success') { + late final Map confirmRes; + if (confirmRaw is Map) { + confirmRes = confirmRaw; + } else if (confirmRaw is String) { + confirmRes = json.decode(confirmRaw) as Map; + } else { + throw Exception("Unexpected confirm response type"); + } + + if (confirmRes['status'] == 'success') { Get.defaultDialog( title: "✅ نجاح", content: const Text("تمت عملية الدفع وإضافة الرصيد إلى محفظتك."), ); } else { - // --- CHANGE 5: Simplified error message extraction --- - // The new PHP script sends the error directly in the 'message' field. - String errorMsg = - confirmRes?['message']?.toString() ?? "فشل في تأكيد الدفع"; + final msg = (confirmRes['message'] ?? 'فشل في تأكيد الدفع').toString(); Get.defaultDialog( title: "❌ فشل", - content: Text(errorMsg.tr), + content: Text(msg), ); } } catch (e, s) { - // --- CHANGE 6: Updated general error log message --- - print("🔥 Error during Syriatel Wallet payment:"); - print(e); - print(s); - if (Get.isDialogOpen ?? false) Get.back(); + print("🔥 Error during Syriatel Wallet payment:\n$e\n$s"); + _closeAnyDialog(); Get.defaultDialog( title: 'حدث خطأ', content: Text(e.toString().replaceFirst("Exception: ", "")), diff --git a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart index d71d6e9..01a67f8 100644 --- a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart +++ b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart @@ -338,68 +338,69 @@ void showPaymentOptions(BuildContext context, PaymentController controller) { // ); // }, // ), - GestureDetector( - onTap: () async { - Get.back(); - Get.defaultDialog( - barrierDismissible: false, - title: 'Insert Wallet phone number'.tr, - content: Form( - key: controller.formKey, - child: MyTextForm( - controller: controller.walletphoneController, - label: 'Insert Wallet phone number'.tr, - hint: '963941234567', - type: TextInputType.phone)), - confirm: MyElevatedButton( - title: 'OK'.tr, - onPressed: () async { - Get.back(); - if (controller.formKey.currentState!.validate()) { - if (controller.selectedAmount != 0) { - controller.isLoading = true; - controller.update(); - box.write(BoxName.phoneWallet, - (controller.walletphoneController.text)); - Get.back(); - await controller.payWithMTNWallet( - context, - controller.selectedAmount.toString(), - 'SYP', - ); - await controller.getPassengerWallet(); + // GestureDetector( + // onTap: () async { + // Get.back(); + // Get.defaultDialog( + // barrierDismissible: false, + // title: 'Insert Wallet phone number'.tr, + // content: Form( + // key: controller.formKey, + // child: MyTextForm( + // controller: controller.walletphoneController, + // label: 'Insert Wallet phone number'.tr, + // hint: '963941234567', + // type: TextInputType.phone)), + // confirm: MyElevatedButton( + // title: 'OK'.tr, + // onPressed: () async { + // Get.back(); + // if (controller.formKey.currentState!.validate()) { + // if (controller.selectedAmount != 0) { + // controller.isLoading = true; + // controller.update(); + // box.write(BoxName.phoneWallet, + // (controller.walletphoneController.text)); + // Get.back(); + // await controller.payWithMTNWallet( + // context, + // controller.selectedAmount.toString(), + // 'SYP', + // ); + // await controller.getPassengerWallet(); + + // controller.isLoading = false; + // controller.update(); + // } else { + // Toast.show( + // context, + // '⚠️ You need to choose an amount!'.tr, + // AppColor.redColor, + // ); + // } + // } + // })); + // }, + // child: Padding( + // padding: const EdgeInsets.all(8.0), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // 'Pay by MTN Wallet'.tr, + // style: AppStyle.title, + // ), + // const SizedBox(width: 10), + // Image.asset( + // 'assets/images/cashMTN.png', + // width: 70, + // height: 70, + // fit: BoxFit.contain, + // ), + // ], + // ), + // )), - controller.isLoading = false; - controller.update(); - } else { - Toast.show( - context, - '⚠️ You need to choose an amount!'.tr, - AppColor.redColor, - ); - } - } - })); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Pay by MTN Wallet'.tr, - style: AppStyle.title, - ), - const SizedBox(width: 10), - Image.asset( - 'assets/images/cashMTN.png', - width: 70, - height: 70, - fit: BoxFit.contain, - ), - ], - ), - )), GestureDetector( onTap: () async { Get.back(); @@ -420,7 +421,7 @@ void showPaymentOptions(BuildContext context, PaymentController controller) { if (controller.formKey.currentState!.validate()) { box.write(BoxName.phoneWallet, controller.walletphoneController.text); - await controller.payWithSyriaTelWallet(context, + await controller.payWithSyriaTelWallet( controller.selectedAmount.toString(), 'SYP'); } }));