import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../controller/scheduled/scheduled_rides_controller.dart'; /// شاشة حجوزات الراكب المسبقة. /// /// تعرض القادم فقط: الحجز الفائت لا يفيد، والراكب يفتح الشاشة ليرى ما /// ينتظره لا ليتصفّح أرشيفه. class ScheduledRidesPage extends StatelessWidget { const ScheduledRidesPage({super.key}); @override Widget build(BuildContext context) { final c = Get.put(ScheduledRidesController()); return Directionality( textDirection: TextDirection.rtl, child: Scaffold( appBar: AppBar(title: Text('رحلاتي المحجوزة'.tr)), body: Obx(() { if (c.isLoading.value && c.bookings.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (c.bookings.isEmpty) { return _Empty(maxDays: ScheduledRidesController.maxDaysAhead); } return RefreshIndicator( onRefresh: c.fetch, child: ListView.builder( padding: const EdgeInsets.all(16), itemCount: c.bookings.length, itemBuilder: (_, i) => _BookingCard(b: c.bookings[i], c: c), ), ); }), ), ); } } class _Empty extends StatelessWidget { const _Empty({required this.maxDays}); final int maxDays; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return ListView( padding: const EdgeInsets.all(32), children: [ const SizedBox(height: 80), Icon(Icons.event_available_outlined, size: 64, color: cs.primary.withOpacity(0.4)), const SizedBox(height: 20), Text('لا حجوزات قادمة'.tr, textAlign: TextAlign.center, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 10), Text( 'احجز رحلتك للمطار أو موعدك الطبي أو دوامك الصباحي' ' حتى $maxDays يومين مقدماً، ونرسل لك سائقاً في وقته.', textAlign: TextAlign.center, style: TextStyle(fontSize: 13, height: 1.6, color: cs.onSurfaceVariant), ), ], ); } } class _BookingCard extends StatelessWidget { const _BookingCard({required this.b, required this.c}); final Map b; final ScheduledRidesController c; @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; final when = DateTime.tryParse('${b['scheduled_at']}'); return Card( margin: const EdgeInsets.only(bottom: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.schedule, size: 18, color: Color(0xFF6A5ACD)), const SizedBox(width: 8), Text( when == null ? '${b['scheduled_at']}' : _when(when), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 15), ), const Spacer(), if (when != null) _Countdown(when: when), ], ), const Divider(height: 20), _row(context, '🟢', b['start_name'] ?? 'موقع الانطلاق'), const SizedBox(height: 6), _row(context, '🔴', b['end_name'] ?? 'الوجهة'), const SizedBox(height: 12), Row( children: [ Text('${b['car_type'] ?? ''}', style: TextStyle(fontSize: 12, color: cs.onSurfaceVariant)), const Spacer(), // ‏نصرّح بأن السعر تقديري: التسعير النهائي لحظة إنشاء // ‏الرحلة، فرقم اليوم قد لا يطابق رقم الغد. Text( 'تقديري: ${b['estimated_price'] ?? '—'}', style: TextStyle(fontSize: 12, color: cs.onSurfaceVariant), ), ], ), const SizedBox(height: 8), Align( alignment: Alignment.centerLeft, child: TextButton.icon( onPressed: () => _confirmCancel(context), icon: Icon(Icons.close, size: 16, color: cs.error), label: Text('إلغاء الحجز'.tr, style: TextStyle(color: cs.error, fontSize: 13)), ), ), ], ), ), ); } void _confirmCancel(BuildContext context) { Get.defaultDialog( title: 'إلغاء الحجز'.tr, // ‏بلا رسم: لا سائق قُبِل ولا أحد تحرّك. نقولها صراحةً ليطمئن الراكب. middleText: 'سيُلغى الحجز بلا أي رسوم — لم يُسند سائق بعد.'.tr, textConfirm: 'تأكيد'.tr, textCancel: 'تراجع'.tr, onConfirm: () { Get.back(); final id = int.tryParse('${b['id']}'); if (id != null) c.cancel(id); }, ); } Widget _row(BuildContext context, String dot, dynamic text) => Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(dot, style: const TextStyle(fontSize: 12)), const SizedBox(width: 8), Expanded( child: Text('$text', style: const TextStyle(fontSize: 13, height: 1.4)), ), ], ); String _when(DateTime d) { final now = DateTime.now(); final isToday = d.year == now.year && d.month == now.month && d.day == now.day; final tomorrow = now.add(const Duration(days: 1)); final isTomorrow = d.year == tomorrow.year && d.month == tomorrow.month && d.day == tomorrow.day; final hh = d.hour.toString().padLeft(2, '0'); final mm = d.minute.toString().padLeft(2, '0'); if (isToday) return 'اليوم $hh:$mm'; if (isTomorrow) return 'غداً $hh:$mm'; return '${d.day}/${d.month} — $hh:$mm'; } } /// كم تبقّى للموعد. يجعل الحجز محسوساً بدل تاريخ جامد. class _Countdown extends StatelessWidget { const _Countdown({required this.when}); final DateTime when; @override Widget build(BuildContext context) { final diff = when.difference(DateTime.now()); if (diff.isNegative) return const SizedBox.shrink(); final label = diff.inHours >= 1 ? 'بعد ${diff.inHours} ساعة' : 'بعد ${diff.inMinutes} دقيقة'; return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFF6A5ACD).withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text(label, style: const TextStyle(fontSize: 11, color: Color(0xFF6A5ACD))), ); } }