From d691e51ba44803a8e748e7f9903723c8074af2d8 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Fri, 7 Aug 2026 06:04:46 +0300 Subject: [PATCH] Update: 2026-08-07 06:04:46 --- .../migrations/2026_08_07_verify_food.sql | 12 +++ .../home/map/ride_lifecycle_controller.dart | 80 +++++++++++++++++++ .../cash_confirm_bottom_page.dart | 40 +++++++--- 3 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 backend/food/migrations/2026_08_07_verify_food.sql diff --git a/backend/food/migrations/2026_08_07_verify_food.sql b/backend/food/migrations/2026_08_07_verify_food.sql new file mode 100644 index 00000000..3b3a6d2c --- /dev/null +++ b/backend/food/migrations/2026_08_07_verify_food.sql @@ -0,0 +1,12 @@ +-- 2026_08_07_verify_food.sql — فحص حالة ترحيلات الطعام +-- +-- ‏قراءة خالصة لا تُعدّل شيئاً. +-- sirodb siro_food < backend/food/migrations/2026_08_07_verify_food.sql + +SELECT 'TABLE food_courier_settlements' AS item, + COUNT(*) AS ok FROM information_schema.TABLES + WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='food_courier_settlements' +UNION ALL SELECT 'food_order_payments.settlement_id', COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='food_order_payments' AND COLUMN_NAME='settlement_id' +UNION ALL SELECT 'food_order_payments.idx_settlement', COUNT(*) FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='food_order_payments' AND INDEX_NAME='idx_settlement'; diff --git a/siro_rider/lib/controller/home/map/ride_lifecycle_controller.dart b/siro_rider/lib/controller/home/map/ride_lifecycle_controller.dart index 20334791..a0176fa2 100644 --- a/siro_rider/lib/controller/home/map/ride_lifecycle_controller.dart +++ b/siro_rider/lib/controller/home/map/ride_lifecycle_controller.dart @@ -30,6 +30,8 @@ import '../../../services/ride_live_notification.dart'; import '../../../views/home/map_page_passenger.dart'; import '../../../views/Rate/rate_captain.dart'; import '../../../views/Rate/rating_driver_bottom.dart'; +import '../../../views/scheduled/scheduled_rides_page.dart'; +import '../../scheduled/scheduled_rides_controller.dart'; import '../../../views/widgets/mydialoug.dart'; import '../../../views/widgets/elevated_btn.dart'; import '../../../views/home/map_widget.dart/car_details_widget_to_go.dart'; @@ -759,6 +761,84 @@ class RideLifecycleController extends GetxController { bool _isRideBeginLogicExecuted = false; String driversStatusForSearchWindow = ''; + /// ‏يفتح منتقي الموعد ثم يُنشئ حجزاً بدل رحلة فورية. + /// + /// ‏المسار موازٍ لـ startSearchingForDriver لا بديل عنه: الحجز لا يفتح + /// ‏نافذة بحث ولا يوصل السوكِت ولا ينتظر سائقاً — يسجّل نيّة سفر فقط، + /// ‏ويتولّى الكرون تحويلها لرحلة قبل الموعد بهامش. + Future scheduleRideForLater() async { + if (mapEngine.polylineCoordinates.isEmpty) { + mySnackbarWarning('حدّد وجهتك أولاً'.tr); + return; + } + + final ctrl = Get.put(ScheduledRidesController()); + final picked = await _pickScheduleTime(ctrl); + if (picked == null) return; + + final startLoc = mapEngine.polylineCoordinates.first; + final endLoc = mapEngine.polylineCoordinates.last; + + final ok = await ctrl.create( + startLocation: '${startLoc.latitude},${startLoc.longitude}', + endLocation: '${endLoc.latitude},${endLoc.longitude}', + startName: startNameAddress, + endName: endNameAddress, + carType: box.read(BoxName.carType)?.toString() ?? 'Speed', + distanceKm: double.tryParse(distance.toString()) ?? 0, + // ‏duration بالثواني (سطر 102) — نفس ما يُرسل في postRideDetailsToServer. + durationSeconds: duration.round(), + estimatedPrice: double.tryParse(totalPassenger.toString()) ?? 0, + when: picked, + ); + + if (ok) { + // ‏نعيد الخريطة لحالتها الخاملة: الحجز ليس رحلة جارية، وإبقاء + // ‏المسار مرسوماً يوهم الراكب أن سائقاً في طريقه إليه الآن. + restCounter(); + currentRideState.value = RideState.noRide; + update(); + Get.to(() => const ScheduledRidesPage()); + } + } + + /// ‏منتقي التاريخ ثم الوقت، محصور بحدود الخادم. + /// + /// ‏الحصر في المنتقي نفسه لا بعده: عرض مواعيد يرفضها الخادم ثم إظهار + /// ‏خطأ تجربة سيئة، ومنعها من الأساس أوضح. + Future _pickScheduleTime(ScheduledRidesController ctrl) async { + final now = DateTime.now(); + + final date = await showDatePicker( + context: Get.context!, + initialDate: ctrl.earliest, + firstDate: now, + lastDate: ctrl.latest, + helpText: 'موعد الرحلة'.tr, + ); + if (date == null) return null; + + final time = await showTimePicker( + context: Get.context!, + initialTime: TimeOfDay.fromDateTime(ctrl.earliest), + helpText: 'وقت الانطلاق'.tr, + ); + if (time == null) return null; + + final picked = + DateTime(date.year, date.month, date.day, time.hour, time.minute); + + // ‏منتقي التاريخ يحصر اليوم لا الساعة، فقد يختار الراكب يوماً صالحاً + // ‏بساعة ماضية أو قريبة جداً. + if (picked.isBefore(ctrl.earliest)) { + mySnackbarWarning( + 'اختر موعداً بعد ${ScheduledRidesController.minLeadMinutes} دقيقة على الأقل'.tr); + return null; + } + + return picked; + } + void startSearchingForDriver() async { if (currentRideState.value == RideState.searching) return; diff --git a/siro_rider/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart b/siro_rider/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart index e6bd63dd..b40470d0 100644 --- a/siro_rider/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart +++ b/siro_rider/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart @@ -120,15 +120,37 @@ class CashConfirmPageShown extends StatelessWidget { } // في كل الحالات الأخرى (كاش، أو محفظة برصيد كافٍ) else { - return MyElevatedButton( - title: 'Confirm & Find a Ride'.tr, - onPressed: () { - // --- نفس منطقك القديم بالضبط --- - controller.changeCashConfirmPageShown(); - // controller.isSearchingWindow = true; - controller.startSearchingForDriver(); - // controller.update(); - }, + return Column( + children: [ + MyElevatedButton( + title: 'Confirm & Find a Ride'.tr, + onPressed: () { + // --- نفس منطقك القديم بالضبط --- + controller.changeCashConfirmPageShown(); + // controller.isSearchingWindow = true; + controller.startSearchingForDriver(); + // controller.update(); + }, + ), + const SizedBox(height: 6), + // ‏مسار موازٍ لا بديل: الحجز لا يفتح نافذة بحث ولا + // ‏ينتظر سائقاً — يسجّل موعداً ويتولّاه الخادم. + // ‏ثانوي بصرياً عمداً: الرحلة الفورية تبقى الافتراض. + TextButton.icon( + onPressed: () { + controller.changeCashConfirmPageShown(); + controller.scheduleRideForLater(); + }, + icon: Icon(Icons.schedule, + size: 18, color: AppColor.primaryColor), + label: Text( + 'احجزها لوقت لاحق'.tr, + style: TextStyle( + color: AppColor.primaryColor, + fontWeight: FontWeight.w600), + ), + ), + ], ); } }),