// route_approval_page.dart — اعتماد خطوط مواصلاتي المسودة (لوحة سيرو آدمن) import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../constant/colors.dart'; import '../../controller/transit/transit_admin_controller.dart'; class RouteApprovalPage extends StatefulWidget { const RouteApprovalPage({super.key}); @override State createState() => _RouteApprovalPageState(); } class _RouteApprovalPageState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Get.find().fetchPendingRoutes(); }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.bg, appBar: AppBar( backgroundColor: AppColor.bg, elevation: 0, title: const Text( 'مواصلاتي — اعتماد الخطوط', style: TextStyle(color: AppColor.textPrimary, fontWeight: FontWeight.bold), ), iconTheme: const IconThemeData(color: AppColor.textPrimary), actions: [ IconButton( icon: const Icon(Icons.refresh_rounded, color: AppColor.accent), onPressed: () => Get.find().fetchPendingRoutes(), ), ], ), body: GetBuilder( builder: (c) { if (c.isLoadingPendingRoutes) { return const Center( child: CircularProgressIndicator(color: AppColor.accent)); } if (c.pendingRoutes.isEmpty) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.check_circle_outline_rounded, size: 64, color: AppColor.success.withOpacity(0.6)), const SizedBox(height: 16), const Text( 'لا توجد خطوط تنتظر الاعتماد', style: TextStyle( color: AppColor.textSecondary, fontSize: 16, fontWeight: FontWeight.w600), ), ], ), ); } return ListView.builder( padding: const EdgeInsets.all(16), itemCount: c.pendingRoutes.length, itemBuilder: (_, i) => _RouteCard( route: c.pendingRoutes[i], onApprove: (action) async { final routeId = int.tryParse(c.pendingRoutes[i]['id'].toString()) ?? 0; if (routeId == 0) return; final ok = await c.approveRoute(routeId, action); if (ok && mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(action == 'approve' ? 'تم اعتماد الخط ✓' : 'تم رفض الخط'), backgroundColor: action == 'approve' ? AppColor.success : AppColor.danger, ), ); } }, ), ); }, ), ); } } class _RouteCard extends StatelessWidget { final Map route; final void Function(String action) onApprove; const _RouteCard({required this.route, required this.onApprove}); @override Widget build(BuildContext context) { final stops = (route['stops'] is List) ? route['stops'] as List : []; final stopsCount = int.tryParse(route['stops_count']?.toString() ?? '0') ?? stops.length; final distKm = route['distance_km']?.toString() ?? '—'; final durMin = route['duration_min']?.toString() ?? '—'; final direction = route['direction']?.toString() ?? ''; final orgName = route['org_name']?.toString() ?? ''; return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: AppColor.surface, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColor.divider), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── هيدر الكارد ────────────────────────────────── Padding( padding: const EdgeInsets.all(16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 44, height: 44, decoration: BoxDecoration( color: AppColor.accentSoft, borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.route_rounded, color: AppColor.accent, size: 24), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( route['name_ar']?.toString() ?? '', style: const TextStyle( color: AppColor.textPrimary, fontWeight: FontWeight.bold, fontSize: 15), ), if (orgName.isNotEmpty) ...[ const SizedBox(height: 2), Text(orgName, style: const TextStyle( color: AppColor.accent, fontSize: 12, fontWeight: FontWeight.w500)), ], ], ), ), _TagChip( label: direction == 'outbound' ? 'ذهاب' : 'إياب', color: direction == 'outbound' ? AppColor.info : AppColor.warning, ), ], ), ), // ── إحصائيات ───────────────────────────────────── Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ _StatChip( icon: Icons.location_on_rounded, label: '$stopsCount محطة'), const SizedBox(width: 8), if (distKm != '—') _StatChip(icon: Icons.straighten_rounded, label: '$distKm كم'), const SizedBox(width: 8), if (durMin != '—') _StatChip(icon: Icons.timer_rounded, label: '$durMin د'), ], ), ), // ── قائمة المحطات ────────────────────────────── if (stops.isNotEmpty) ...[ const SizedBox(height: 12), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text('المحطات:', style: TextStyle( color: AppColor.textSecondary.withOpacity(0.8), fontSize: 12, fontWeight: FontWeight.w600)), ), SizedBox( height: 32, child: ListView.separated( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), itemCount: stops.length, separatorBuilder: (_, __) => const Padding( padding: EdgeInsets.symmetric(horizontal: 4), child: Icon(Icons.arrow_forward_ios_rounded, size: 10, color: AppColor.textMuted), ), itemBuilder: (_, i) => Text( stops[i]['name_ar']?.toString() ?? '•', style: const TextStyle( color: AppColor.textSecondary, fontSize: 12), ), ), ), ], // ── أزرار الإجراءات ────────────────────────────── Padding( padding: const EdgeInsets.all(12), child: Row( children: [ Expanded( child: OutlinedButton( onPressed: () => onApprove('reject'), style: OutlinedButton.styleFrom( side: const BorderSide(color: AppColor.danger), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), child: const Text('رفض', style: TextStyle(color: AppColor.danger)), ), ), const SizedBox(width: 10), Expanded( flex: 2, child: ElevatedButton( onPressed: () => onApprove('approve'), style: ElevatedButton.styleFrom( backgroundColor: AppColor.success, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), child: const Text('اعتماد الخط', style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold)), ), ), ], ), ), ], ), ); } } class _TagChip extends StatelessWidget { final String label; final Color color; const _TagChip({required this.label, required this.color}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: color.withOpacity(0.12), borderRadius: BorderRadius.circular(20), border: Border.all(color: color.withOpacity(0.3)), ), child: Text(label, style: TextStyle(color: color, fontSize: 11, fontWeight: FontWeight.bold)), ); } } class _StatChip extends StatelessWidget { final IconData icon; final String label; const _StatChip({required this.icon, required this.label}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppColor.surfaceElevated, borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: AppColor.textMuted), const SizedBox(width: 4), Text(label, style: const TextStyle(color: AppColor.textSecondary, fontSize: 11)), ], ), ); } }