Files
tripz-llc/dashboards/admin/lib/views/transit/org_details_page.dart
T

252 lines
9.7 KiB
Dart

// org_details_page.dart — تفاصيل وتحليلات مؤسسة (لوحة إدارة تريبز)
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../controller/transit/transit_admin_controller.dart';
import 'org_admins_page.dart';
class TransitOrgDetailsPage extends StatefulWidget {
final int orgId;
final String orgName;
const TransitOrgDetailsPage({super.key, required this.orgId, required this.orgName});
@override
State<TransitOrgDetailsPage> createState() => _TransitOrgDetailsPageState();
}
class _TransitOrgDetailsPageState extends State<TransitOrgDetailsPage> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Get.find<TransitAdminController>().loadOrgDetails(widget.orgId);
});
}
@override
Widget build(BuildContext context) {
return GetBuilder<TransitAdminController>(
builder: (c) => Scaffold(
backgroundColor: AppColor.bg,
appBar: AppBar(
backgroundColor: AppColor.bg,
elevation: 0,
title: Text(widget.orgName, style: const TextStyle(color: AppColor.textPrimary)),
actions: [
IconButton(
tooltip: 'إدارة المشرفين',
icon: const Icon(Icons.admin_panel_settings_outlined, color: AppColor.accent),
onPressed: () => Get.to(
() => TransitOrgAdminsPage(orgId: widget.orgId, orgName: widget.orgName),
),
),
PopupMenuButton<String>(
icon: const Icon(Icons.more_vert, color: AppColor.textSecondary),
color: AppColor.surface,
onSelected: (action) => _handleContractAction(action),
itemBuilder: (_) => [
_menuItem('active', 'تفعيل العقد', Icons.check_circle_outline, AppColor.success),
_menuItem('trial', 'وضع تجريبي', Icons.science_outlined, AppColor.info),
_menuItem('suspended', 'تعليق العقد', Icons.pause_circle_outline, AppColor.warning),
_menuItem('terminated', 'إنهاء العقد', Icons.cancel_outlined, AppColor.danger),
],
),
],
),
body: c.isLoadingDetails
? const Center(child: CircularProgressIndicator(color: AppColor.accent))
: c.selectedOrgDetails == null
? const Center(
child: Text('تعذّر تحميل البيانات', style: TextStyle(color: AppColor.textSecondary)))
: _content(c),
),
);
}
PopupMenuItem<String> _menuItem(String value, String label, IconData icon, Color color) {
return PopupMenuItem<String>(
value: value,
child: Row(
children: [
Icon(icon, color: color, size: 18),
const SizedBox(width: 10),
Text(label, style: TextStyle(color: color, fontSize: 13)),
],
),
);
}
Future<void> _handleContractAction(String contractStatus) async {
final labels = {
'active': 'تفعيل العقد',
'trial': 'وضع تجريبي',
'suspended': 'تعليق العقد',
'terminated': 'إنهاء العقد',
};
final confirm = await showDialog<bool>(
context: context,
builder: (_) => AlertDialog(
backgroundColor: AppColor.surface,
title: Text(labels[contractStatus] ?? contractStatus,
style: const TextStyle(color: AppColor.textPrimary)),
content: Text(
contractStatus == 'terminated'
? 'سيتم إنهاء العقد وإبطال جميع جلسات المشرفين. هذا الإجراء خطير.'
: 'هل أنت متأكد من تغيير حالة العقد إلى "${labels[contractStatus]}"؟',
style: const TextStyle(color: AppColor.textSecondary),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('إلغاء', style: TextStyle(color: AppColor.textSecondary)),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(
labels[contractStatus] ?? contractStatus,
style: TextStyle(
color: contractStatus == 'terminated' ? AppColor.danger : AppColor.accent,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
if (confirm != true) return;
final c = Get.find<TransitAdminController>();
final ok = await c.updateContractStatus(widget.orgId, contractStatus);
if (ok && mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('تم تحديث حالة العقد إلى: ${labels[contractStatus]}'),
backgroundColor: contractStatus == 'terminated'
? AppColor.danger
: contractStatus == 'suspended'
? AppColor.warning
: AppColor.success,
));
c.loadOrgDetails(widget.orgId);
}
}
Widget _content(TransitAdminController c) {
final d = c.selectedOrgDetails!;
final counts = d.counts;
final trips = d.trips;
return ListView(
padding: const EdgeInsets.all(16),
children: [
_sectionTitle('الأسطول'),
Row(
children: [
_statCard('السائقون', '${counts['drivers_active'] ?? 0}/${counts['drivers_total'] ?? 0}',
Icons.badge_outlined),
const SizedBox(width: 10),
_statCard('المركبات', '${counts['vehicles_active'] ?? 0}/${counts['vehicles_total'] ?? 0}',
Icons.directions_bus_outlined),
],
),
const SizedBox(height: 10),
Row(
children: [
_statCard('الخطوط النشطة', '${counts['routes_active'] ?? 0}', Icons.route_outlined),
const SizedBox(width: 10),
_statCard('عضويات نشطة', '${counts['enrollments_active'] ?? 0}', Icons.people_outline),
],
),
if ((int.tryParse(counts['enrollments_pending']?.toString() ?? '0') ?? 0) > 0) ...[
const SizedBox(height: 10),
_statCard('طلبات بانتظار الموافقة', '${counts['enrollments_pending']}',
Icons.pending_actions_outlined, color: AppColor.warning),
],
const SizedBox(height: 24),
_sectionTitle('الرحلات'),
Row(
children: [
_statCard('اليوم', '${trips['today'] ?? 0}', Icons.today_outlined),
const SizedBox(width: 10),
_statCard('هذا الأسبوع', '${trips['this_week'] ?? 0}', Icons.date_range_outlined),
],
),
const SizedBox(height: 10),
Row(
children: [
_statCard('هذا الشهر', '${trips['this_month'] ?? 0}', Icons.calendar_month_outlined),
const SizedBox(width: 10),
_statCard('ساعات القيادة', '${trips['total_hours_driven'] ?? 0}', Icons.timer_outlined),
],
),
const SizedBox(height: 10),
Row(
children: [
_statCard('مكتملة', '${trips['completed'] ?? 0}', Icons.check_circle_outline,
color: AppColor.success),
const SizedBox(width: 10),
_statCard('متوسط التأخير', '${trips['avg_delay_minutes'] ?? 0} د', Icons.timelapse,
color: AppColor.warning),
],
),
const SizedBox(height: 24),
_sectionTitle('الخطوط'),
...d.routes.map((r) => Card(
color: AppColor.surface,
margin: const EdgeInsets.only(bottom: 8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
title: Text(r['name_ar']?.toString() ?? '',
style: const TextStyle(color: AppColor.textPrimary)),
subtitle: Text(
'${r['stops_count'] ?? 0} محطة · ${r['completed_trips'] ?? 0} رحلة مكتملة',
style: const TextStyle(color: AppColor.textSecondary, fontSize: 12),
),
trailing: Text(
r['status']?.toString() ?? '',
style: TextStyle(
color: r['status'] == 'active' ? AppColor.success : AppColor.textSecondary,
fontSize: 12,
),
),
),
)),
],
);
}
Widget _sectionTitle(String text) => Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Text(text,
style: const TextStyle(
color: AppColor.textPrimary, fontSize: 16, fontWeight: FontWeight.bold)),
);
Widget _statCard(String label, String value, IconData icon, {Color? color}) {
return Expanded(
child: Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(14),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: color ?? AppColor.accent, size: 20),
const SizedBox(height: 8),
Text(value,
style: TextStyle(
color: color ?? AppColor.textPrimary,
fontSize: 18,
fontWeight: FontWeight.bold)),
const SizedBox(height: 2),
Text(label, style: const TextStyle(color: AppColor.textSecondary, fontSize: 11)),
],
),
),
);
}
}