import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:sefer_driver/views/widgets/error_snakbar.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:sefer_driver/constant/colors.dart'; import 'package:sefer_driver/constant/style.dart'; import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart'; import 'package:sefer_driver/controller/payment/payment_controller.dart'; import '../../../constant/box_name.dart'; import '../../../constant/links.dart'; import '../../../controller/functions/crud.dart'; import '../../../main.dart'; import '../../widgets/my_textField.dart'; class PointsCaptain extends StatefulWidget { final Color kolor; final String countPoint; final double pricePoint; const PointsCaptain({ super.key, required this.kolor, required this.countPoint, required this.pricePoint, }); @override State createState() => _PointsCaptainState(); } class _PointsCaptainState extends State { final PaymentController paymentController = Get.put(PaymentController()); final CaptainWalletController captainWalletController = Get.put(CaptainWalletController()); // متغيرات لحالة التحميل العامة bool isCardLoading = false; bool isWalletLoading = false; @override Widget build(BuildContext context) { return InkWell( borderRadius: BorderRadius.circular(16), onTap: () async { // تم التعديل: إزالة شرط الدولة وتشغيل قائمة Paymob للجميع // لأنها تدعم البطاقات الدولية الآن _showPaymentBottomSheet(context); }, child: Container( width: Get.width * .28, height: Get.width * .28, margin: const EdgeInsets.all(6), decoration: BoxDecoration( gradient: LinearGradient( colors: [ widget.kolor.withOpacity(0.4), widget.kolor, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: widget.kolor.withOpacity(0.3), blurRadius: 8, offset: const Offset(2, 4), ) ], borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.white.withOpacity(0.5), width: 1), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.stars_rounded, color: Colors.white, size: 28), const SizedBox(height: 5), Text( '${widget.countPoint} ${"points".tr}', style: AppStyle.subtitle.copyWith( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 16, ), ), Container( margin: const EdgeInsets.only(top: 5), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(10), ), child: Text( '${widget.pricePoint} ${box.read(BoxName.countryCode) == 'Jordan' ? 'JOD'.tr : 'L.E'.tr}', style: AppStyle.title.copyWith( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), textAlign: TextAlign.center, ), ), ], ), ), ); } void _showPaymentBottomSheet(BuildContext context) { // تصفير الحالات عند فتح القائمة isCardLoading = false; isWalletLoading = false; // التحقق مما إذا كان المستخدم في مصر (لعرض خيار المحفظة) bool isEgypt = box.read(BoxName.countryCode) == 'Egypt'; Get.bottomSheet( StatefulBuilder(builder: (context, setStateSheet) { return Container( padding: const EdgeInsets.all(20), decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(25)), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 50, height: 5, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(10), ), ), const SizedBox(height: 20), Text( 'Choose Payment Method'.tr, style: AppStyle.headTitle2, ), const SizedBox(height: 10), Text( '${'You will pay'.tr}: ${widget.pricePoint} ${isEgypt ? 'LE'.tr : 'currency_unit'.tr}', // تحسين بسيط للعملة style: AppStyle.title.copyWith(color: Colors.grey), ), const SizedBox(height: 25), // --- إضافة تنبيه بخصوص البطاقات الدولية --- Container( margin: const EdgeInsets.only(bottom: 15), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.08), borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColor.primaryColor.withOpacity(0.3)), ), child: Row( children: [ Icon(Icons.public, color: AppColor.primaryColor, size: 24), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Global Payment".tr, style: TextStyle( color: AppColor.primaryColor, fontWeight: FontWeight.bold, fontSize: 14, ), ), Text( "We accept all international Credit/Debit cards." .tr, style: TextStyle( color: AppColor.primaryColor.withOpacity(0.8), fontSize: 12, ), ), ], ), ), ], ), ), // --- زر الدفع بالبطاقة --- _buildPaymentButton( title: 'Pay with Credit Card'.tr, icon: Icons.credit_card, color: AppColor.primaryColor, isLoading: isCardLoading, onTap: () async { setStateSheet(() => isCardLoading = true); try { var res = await CRUD().postWallet( link: AppLink.payWithPayMobCardDriver, payload: _getPayload(), ); if (res != null && res['message'] != null) { Get.back(); // إغلاق القائمة Get.to(() => GenericPaymentWebView( iframeUrl: res['message'], countPrice: widget.countPoint, isWallet: false, )); } else { setStateSheet(() => isCardLoading = false); mySnackeBarError("Failed to get payment link".tr); } } catch (e) { setStateSheet(() => isCardLoading = false); mySnackeBarError("Failed to initialize card payment".tr); } }, ), // عرض خيار المحفظة فقط إذا كان المستخدم في مصر if (isEgypt) ...[ const SizedBox(height: 15), _buildPaymentButton( title: 'Pay with Wallet'.tr, icon: Icons.account_balance_wallet, color: const Color(0xffE60000), isLoading: isWalletLoading, onTap: () { Get.back(); _showWalletNumberDialog(); }, ), ], const SizedBox(height: 20), ], ), ); }), isScrollControlled: true, ); } Map _getPayload() { return { "amount": widget.pricePoint.toStringAsFixed(2), "email": box.read(BoxName.emailDriver).toString(), "first_name": box.read(BoxName.nameDriver).toString().split(' ')[0], "last_name": box.read(BoxName.nameDriver).toString().split(' ').length > 1 ? box.read(BoxName.nameDriver).toString().split(' ')[1] : "Driver", "phone_number": box.read(BoxName.phoneDriver), }; } Widget _buildPaymentButton({ required String title, required IconData icon, required Color color, required bool isLoading, required VoidCallback onTap, }) { return SizedBox( width: double.infinity, height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: color, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 0, ), onPressed: isLoading ? null : onTap, child: isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2), ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: Colors.white), const SizedBox(width: 10), Text(title, style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)), ], ), ), ); } void _showWalletNumberDialog() { bool isDialogLoading = false; Get.defaultDialog( barrierDismissible: false, title: 'E-Wallet Number'.tr, contentPadding: const EdgeInsets.all(20), content: StatefulBuilder(builder: (context, setStateDialog) { return Column( children: [ Form( key: paymentController.formKey, child: MyTextForm( controller: paymentController.walletphoneController, label: 'Phone Number'.tr, hint: '01xxxxxxxxx', type: TextInputType.phone, ), ), const SizedBox(height: 20), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppColor.primaryColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), onPressed: isDialogLoading ? null : () async { if (paymentController.formKey.currentState! .validate()) { setStateDialog(() => isDialogLoading = true); box.write(BoxName.phoneWallet, paymentController.walletphoneController.text); try { var payload = _getPayload(); payload['phone_number'] = paymentController.walletphoneController.text; var res = await CRUD().postWallet( link: AppLink.payWithWallet, payload: payload, ); if (res != null && res['message'] != null) { Get.back(); Get.to(() => GenericPaymentWebView( iframeUrl: res['message'], countPrice: widget.countPoint, isWallet: true, )); } else { setStateDialog(() => isDialogLoading = false); mySnackeBarError("Failed to get payment link".tr); } } catch (e) { if (mounted) { setStateDialog(() => isDialogLoading = false); } mySnackeBarError( "Failed to initialize wallet payment".tr); } } }, child: isDialogLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2)) : Text('Confirm & Pay'.tr, style: const TextStyle(color: Colors.white)), ), ), const SizedBox(height: 10), if (!isDialogLoading) TextButton( onPressed: () => Get.back(), child: Text("Cancel".tr, style: const TextStyle(color: Colors.grey)), ) ], ); }), ); } } // ----------------------------------------------------------------------------- // صفحة الويب (WebView) مع اللودينج الخاص بها // ----------------------------------------------------------------------------- class GenericPaymentWebView extends StatefulWidget { final String iframeUrl; final String countPrice; final bool isWallet; const GenericPaymentWebView({ Key? key, required this.iframeUrl, required this.countPrice, required this.isWallet, }) : super(key: key); @override State createState() => _GenericPaymentWebViewState(); } class _GenericPaymentWebViewState extends State { late final WebViewController _controller; final controller = Get.find(); bool isLoadingPage = true; @override void initState() { super.initState(); _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate(NavigationDelegate( onPageStarted: (_) { if (mounted) setState(() => isLoadingPage = true); }, onPageFinished: (url) { if (mounted) setState(() => isLoadingPage = false); if (url.contains("success")) { _fetchPaymentStatus(); } else if (url.contains("failed") || url.contains("error")) { showCustomDialog( title: "Error".tr, message: 'Payment Failed'.tr, isSuccess: false, ); } }, onWebResourceError: (error) { if (mounted) setState(() => isLoadingPage = false); }, )) ..loadRequest(Uri.parse(widget.iframeUrl)); } Future _fetchPaymentStatus() async { final String userId = widget.isWallet ? '+2${box.read(BoxName.phoneWallet)}' : box.read(BoxName.phoneDriver); Get.dialog(const Center(child: CircularProgressIndicator()), barrierDismissible: false); try { final response = await CRUD().postWallet( link: AppLink.paymetVerifyDriver, payload: { 'user_id': userId, 'driverID': box.read(BoxName.driverID), 'paymentMethod': 'visa-in', }, ); Get.back(); // إغلاق لودينج التحقق if (response != 'failure' && response != 'token_expired') { if (response['status'] == 'success') { final payment = response['message']; final amount = payment['amount'].toString(); final bonus = payment['bonus'].toString(); final paymentID = payment['paymentID'].toString(); await controller.refreshCaptainWallet(); showCustomDialog( title: "payment_success".tr, message: "${"transaction_id".tr}: $paymentID\n${"amount_paid".tr}: $amount EGP\n${"bonus_added".tr}: $bonus ${"points".tr}", isSuccess: true, shouldCloseScreen: true, ); } else { showCustomDialog( title: "transaction_failed".tr, message: response['message'].toString(), isSuccess: false, ); } } else { showCustomDialog( title: "connection_failed".tr, message: "Could not verify payment status".tr, isSuccess: false, ); } } catch (e) { Get.back(); showCustomDialog( title: "server_error".tr, message: "server_error_message".tr, isSuccess: false, ); } } void showCustomDialog({ required String title, required String message, required bool isSuccess, bool shouldCloseScreen = false, }) { Get.dialog( Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), child: Padding( padding: const EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(15), decoration: BoxDecoration( shape: BoxShape.circle, color: isSuccess ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1), ), child: Icon( isSuccess ? Icons.check_circle : Icons.error_outline, color: isSuccess ? Colors.green : Colors.red, size: 40, ), ), const SizedBox(height: 15), Text( title, style: AppStyle.headTitle2.copyWith( color: isSuccess ? Colors.green : Colors.red, ), ), const SizedBox(height: 10), Text( message, textAlign: TextAlign.center, style: AppStyle.title, ), const SizedBox(height: 25), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isSuccess ? Colors.green : Colors.red, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), onPressed: () { Get.back(); if (shouldCloseScreen) { Get.back(); } }, child: Text("OK".tr, style: const TextStyle(color: Colors.white)), ), ) ], ), ), ), barrierDismissible: false, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Secure Payment'.tr), centerTitle: true, leading: IconButton( icon: const Icon(Icons.close), onPressed: () => Get.back(), ), ), body: Stack( children: [ WebViewWidget(controller: _controller), if (isLoadingPage) Container( color: Colors.white, width: double.infinity, height: double.infinity, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const CircularProgressIndicator(), const SizedBox(height: 20), Text("Loading Payment Page...".tr, style: const TextStyle( color: Colors.grey, fontWeight: FontWeight.bold, fontSize: 16)), ], ), ), ), ], ), ); } }