import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../constant/colors.dart'; import '../../../controller/insurance/driver_insurance_controller.dart'; import '../../widgets/ui/siro_ui.dart'; /// شاشة التأمين: الوثيقة النشطة ودفترها، أو الخطط المتاحة. /// /// الحالتان لا تظهران معاً — من له وثيقة يرى وثيقته، ومن لا وثيقة له /// يرى الخطط. عرض الاثنين كان سيوحي أن الاشتراك في ثانية ممكن، وهو /// ليس كذلك: تبديل الخطة يمرّ بإلغاء صريح ليبقى في السجل أثر. class DriverInsurancePage extends StatelessWidget { const DriverInsurancePage({super.key}); @override Widget build(BuildContext context) { final c = Get.put(DriverInsuranceController()); return SiroPage( title: 'Insurance'.tr, body: Obx(() { if (c.isLoading.value) { return const SiroLoading(); } return RefreshIndicator( onRefresh: c.refreshAll, color: SiroUi.interactive(context), child: ListView( physics: const AlwaysScrollableScrollPhysics(), padding: SiroUi.pageInsets, children: c.hasPolicy ? _policyView(context, c) : _plansView(context, c), ), ); }), ); } // ── الوثيقة النشطة ───────────────────────────────────────── List _policyView(BuildContext context, DriverInsuranceController c) { final p = c.policy.value!; return [ SiroCard( accent: AppColor.greenColor, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const SiroIconBadge(Icons.verified_user_rounded, color: AppColor.greenColor), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${p['plan'] ?? ''}', style: Theme.of(context) .textTheme .titleMedium ?.copyWith(fontWeight: FontWeight.bold), ), Text('${p['provider'] ?? ''}', style: Theme.of(context).textTheme.bodySmall), ], ), ), ], ), const Divider(height: 24), _row('Premium'.tr, '${p['premium']} ${p['currency']} / ' '${p['billing_cycle'] == 'monthly' ? 'Monthly'.tr : 'Daily'.tr}'), _row('Started on'.tr, '${p['started_at'] ?? '—'}'), if ((p['policy_number'] ?? '').toString().isNotEmpty) _row('Policy number'.tr, '${p['policy_number']}'), if ((p['coverage'] ?? '').toString().isNotEmpty) ...[ const SizedBox(height: 12), Text('${p['coverage']}', style: Theme.of(context).textTheme.bodySmall), ], ], ), ), // ── دفتر الأقساط ── // يظهر في نفس الشاشة لا في أخرى: الخصم الذي لا يرى السائق مقابله // مفاجأة تُفقد الثقة، مهما كان مشروحاً في مكان آخر. SiroCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Premium ledger'.tr, style: Theme.of(context) .textTheme .titleMedium ?.copyWith(fontWeight: FontWeight.bold)), const SizedBox(height: 8), _row('Outstanding'.tr, '${c.pendingTotal.toStringAsFixed(2)} ${c.currency}'), _row('Settled'.tr, '${ledgerNum(c.ledger['settled_total'])} ${c.currency}'), if (c.entries.isNotEmpty) ...[ const Divider(height: 24), ...c.entries.take(10).map((e) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('${e['charge_date']}', style: Theme.of(context).textTheme.bodySmall), Text('${e['amount']} ${e['currency']}', style: TextStyle( color: e['status'] == 'settled' ? AppColor.greenColor : AppColor.yellowColor, fontWeight: FontWeight.w700, )), ], ), )), ], ], ), ), const SizedBox(height: 12), OutlinedButton.icon( onPressed: c.isSubmitting.value ? null : () => _confirmCancel(context, c), icon: const Icon(Icons.cancel_outlined, size: 18), label: Text('Cancel policy'.tr), style: OutlinedButton.styleFrom( foregroundColor: AppColor.redColor, side: const BorderSide(color: AppColor.redColor), minimumSize: const Size.fromHeight(48), ), ), const SizedBox(height: 16), ]; } // ── الخطط المتاحة ────────────────────────────────────────── List _plansView(BuildContext context, DriverInsuranceController c) { if (c.plans.isEmpty) { // ‏الصفحة كانت تبدو "معطّلة" لأنها تعرض عنواناً واحداً بلا سبب. // ‏الحالة الحقيقية: لا خطط مُفعّلة بعد لدى الشركاء — لا خطأ ولا // ‏نقص أهلية — ونقولها صراحة حتى لا يظن الكابتن أن التطبيق خربان. return [ const SizedBox(height: 48), SiroEmptyState( icon: Icons.health_and_safety_outlined, title: 'No insurance plans available yet'.tr, message: 'Insurance plans have not been launched in your area yet. Once a partner plan is available it will appear here automatically.' .tr, ), ]; } return c.plans.map((plan) { final eligible = plan['eligible'] == true; final missing = (plan['missing'] as List?) ?? []; final progress = (plan['progress_rides'] ?? 0) as num; final required = (plan['required_rides'] ?? 0) as num; return SiroCard( accent: eligible ? AppColor.greenColor : null, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text('${plan['name'] ?? ''}', style: Theme.of(context) .textTheme .titleMedium ?.copyWith(fontWeight: FontWeight.bold)), ), if (eligible) SiroTag('Eligible'.tr, color: AppColor.greenColor, icon: Icons.check_circle_rounded), ], ), Text('${plan['provider'] ?? ''}', style: Theme.of(context).textTheme.bodySmall), const SizedBox(height: 8), Text( '${plan['premium']} ${plan['currency']} / ' '${plan['billing_cycle'] == 'monthly' ? 'Monthly'.tr : 'Daily'.tr}', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: SiroUi.interactive(context), ), ), if ((plan['coverage'] ?? '').toString().isNotEmpty) ...[ const SizedBox(height: 8), Text('${plan['coverage']}', style: Theme.of(context).textTheme.bodySmall), ], // شريط التقدّم نحو الشرط — الرقم وحده لا يحرّك أحداً، // ورؤية القرب من الهدف تفعل. if (!eligible && required > 0) ...[ const SizedBox(height: 12), ClipRRect( borderRadius: BorderRadius.circular(999), child: LinearProgressIndicator( minHeight: 7, value: required == 0 ? 0 : (progress / required).clamp(0, 1), backgroundColor: SiroUi.border(context), ), ), const SizedBox(height: 6), Text('$progress / $required ${'rides'.tr}', style: Theme.of(context).textTheme.bodySmall), ], if (!eligible && missing.isNotEmpty) ...[ const SizedBox(height: 8), ...missing.map((m) => Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.lock_outline, size: 14, color: AppColor.yellowColor), const SizedBox(width: 6), Expanded( child: Text('$m', style: const TextStyle( fontSize: 12, color: AppColor.yellowColor)), ), ], )), ], const SizedBox(height: 14), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: (!eligible || c.isSubmitting.value) ? null : () => c.subscribe(plan['id'] as int), child: Text(eligible ? 'Subscribe'.tr : 'Not eligible yet'.tr), ), ), ], ), ); }).toList(); } void _confirmCancel(BuildContext context, DriverInsuranceController c) { showDialog( context: context, builder: (ctx) => AlertDialog( title: Text('Cancel policy'.tr), // نصرّح بأن المستحق السابق يبقى: الإلغاء يوقف القادم ولا يمحو // أياماً استُفيد من تغطيتها فعلاً. content: Text(c.pendingTotal > 0 ? '${'Cancelling stops future premiums. Outstanding dues remain payable.'.tr}\n\n' '${'Outstanding'.tr}: ${c.pendingTotal.toStringAsFixed(2)} ${c.currency}' : 'Cancelling stops future premiums. Outstanding dues remain payable.'.tr), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text('Back'.tr), ), TextButton( onPressed: () { Navigator.pop(ctx); c.cancel(); }, child: Text('Confirm'.tr, style: const TextStyle(color: AppColor.redColor)), ), ], ), ); } static String ledgerNum(dynamic v) => (double.tryParse('${v ?? 0}') ?? 0).toStringAsFixed(2); Widget _row(String label, String value) => SiroDetailRow(label: label, value: value); }