import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../constant/colors.dart'; import '../../../controller/insurance/driver_insurance_controller.dart'; /// شاشة التأمين: الوثيقة النشطة ودفترها، أو الخطط المتاحة. /// /// الحالتان لا تظهران معاً — من له وثيقة يرى وثيقته، ومن لا وثيقة له /// يرى الخطط. عرض الاثنين كان سيوحي أن الاشتراك في ثانية ممكن، وهو /// ليس كذلك: تبديل الخطة يمرّ بإلغاء صريح ليبقى في السجل أثر. class DriverInsurancePage extends StatelessWidget { const DriverInsurancePage({super.key}); @override Widget build(BuildContext context) { final c = Get.put(DriverInsuranceController()); return Scaffold( appBar: AppBar(title: Text('Insurance'.tr), centerTitle: true), body: Obx(() { if (c.isLoading.value) { return const Center(child: CircularProgressIndicator()); } return RefreshIndicator( onRefresh: c.refreshAll, child: ListView( padding: const EdgeInsets.all(16), children: c.hasPolicy ? _policyView(context, c) : _plansView(context, c), ), ); }), ); } // ── الوثيقة النشطة ───────────────────────────────────────── List _policyView(BuildContext context, DriverInsuranceController c) { final p = c.policy.value!; return [ Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.verified_user, color: Colors.green), const SizedBox(width: 8), Expanded( child: Text( '${p['plan'] ?? ''}', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), ], ), const SizedBox(height: 4), Text('${p['provider'] ?? ''}', style: TextStyle(color: Colors.grey.shade600)), 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: TextStyle(color: Colors.grey.shade700)), ], ], ), ), ), const SizedBox(height: 16), // ── دفتر الأقساط ── // يظهر في نفس الشاشة لا في أخرى: الخصم الذي لا يرى السائق مقابله // مفاجأة تُفقد الثقة، مهما كان مشروحاً في مكان آخر. Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Premium ledger'.tr, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 12), _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: TextStyle(color: Colors.grey.shade700)), Text('${e['amount']} ${e['currency']}', style: TextStyle( color: e['status'] == 'settled' ? Colors.green : Colors.orange.shade800, fontWeight: FontWeight.w600, )), ], ), )), ], ], ), ), ), const SizedBox(height: 24), OutlinedButton.icon( onPressed: c.isSubmitting.value ? null : () => _confirmCancel(context, c), icon: const Icon(Icons.cancel_outlined, color: Colors.red), label: Text('Cancel policy'.tr, style: const TextStyle(color: Colors.red)), style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), minimumSize: const Size.fromHeight(48), ), ), ]; } // ── الخطط المتاحة ────────────────────────────────────────── List _plansView(BuildContext context, DriverInsuranceController c) { if (c.plans.isEmpty) { // ‏الصفحة كانت تبدو "معطّلة" لأنها تعرض عنواناً واحداً بلا سبب. // ‏الحالة الحقيقية: لا خطط مُفعّلة بعد لدى الشركاء — لا خطأ ولا // ‏نقص أهلية — ونقولها صراحة حتى لا يظن الكابتن أن التطبيق خربان. return [ const SizedBox(height: 72), Icon(Icons.health_and_safety_outlined, size: 80, color: Colors.grey.shade400), const SizedBox(height: 16), Text('No insurance plans available yet'.tr, textAlign: TextAlign.center, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: Colors.grey)), const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Text( 'Insurance plans have not been launched in your area yet. Once a partner plan is available it will appear here automatically.' .tr, textAlign: TextAlign.center, style: TextStyle( fontSize: 14, height: 1.5, color: Colors.grey.shade600), ), ), const SizedBox(height: 20), Center( child: TextButton.icon( onPressed: c.isLoading.value ? null : () => c.refreshAll(), icon: const Icon(Icons.refresh_rounded, size: 18), label: Text('Refresh'.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 Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), margin: const EdgeInsets.only(bottom: 16), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('${plan['name'] ?? ''}', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), Text('${plan['provider'] ?? ''}', style: TextStyle(color: Colors.grey.shade600)), const SizedBox(height: 8), Text( '${plan['premium']} ${plan['currency']} / ' '${plan['billing_cycle'] == 'monthly' ? 'Monthly'.tr : 'Daily'.tr}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: AppColor.primaryColor), ), if ((plan['coverage'] ?? '').toString().isNotEmpty) ...[ const SizedBox(height: 8), Text('${plan['coverage']}', style: TextStyle(color: Colors.grey.shade700)), ], // شريط التقدّم نحو الشرط — الرقم وحده لا يحرّك أحداً، // ورؤية القرب من الهدف تفعل. if (!eligible && required > 0) ...[ const SizedBox(height: 12), LinearProgressIndicator( value: required == 0 ? 0 : (progress / required).clamp(0, 1), backgroundColor: Colors.grey.shade300, ), const SizedBox(height: 6), Text('$progress / $required ${'rides'.tr}', style: TextStyle( fontSize: 12, color: Colors.grey.shade600)), ], if (!eligible && missing.isNotEmpty) ...[ const SizedBox(height: 8), ...missing.map((m) => Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.lock_outline, size: 14, color: Colors.orange), const SizedBox(width: 6), Expanded( child: Text('$m', style: TextStyle( fontSize: 12, color: Colors.orange.shade900)), ), ], )), ], const SizedBox(height: 12), ElevatedButton( onPressed: (!eligible || c.isSubmitting.value) ? null : () => c.subscribe(plan['id'] as int), style: ElevatedButton.styleFrom( backgroundColor: AppColor.primaryColor, foregroundColor: Colors.white, minimumSize: const Size.fromHeight(44), ), 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: Colors.red)), ), ], ), ); } static String ledgerNum(dynamic v) => (double.tryParse('${v ?? 0}') ?? 0).toStringAsFixed(2); Widget _row(String label, String value) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label, style: TextStyle(color: Colors.grey.shade700)), Flexible( child: Text(value, textAlign: TextAlign.end, style: const TextStyle(fontWeight: FontWeight.w600)), ), ], ), ); }