import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../bloc/onboarding_bloc.dart'; import '../../data/models/souscription_status_model.dart'; import '../../../../shared/design_system/tokens/app_colors.dart'; import '../../../../shared/design_system/tokens/unionflow_colors.dart'; /// Écran de sélection du moyen de paiement class PaymentMethodPage extends StatefulWidget { final SouscriptionStatusModel souscription; const PaymentMethodPage({super.key, required this.souscription}); @override State createState() => _PaymentMethodPageState(); } class _PaymentMethodPageState extends State { String? _selected; // Couleurs de marque Wave et Orange Money — volontairement hardcodées static const _waveBlue = Color(0xFF00B9F1); static const _orangeOrange = Color(0xFFFF6600); static const _methods = [ _PayMethod( id: 'WAVE', name: 'Wave Mobile Money', description: 'Paiement rapide via votre compte Wave', logoAsset: 'assets/images/payment_methods/wave/logo.png', color: _waveBlue, available: true, badge: 'Recommandé', ), _PayMethod( id: 'ORANGE_MONEY', name: 'Orange Money', description: 'Paiement via Orange Money', logoAsset: 'assets/images/payment_methods/orange_money/logo-black.png', color: _orangeOrange, available: false, badge: 'Prochainement', ), ]; @override Widget build(BuildContext context) { final montant = widget.souscription.montantTotal ?? 0; final isDark = Theme.of(context).brightness == Brightness.dark; final bgCard = isDark ? AppColors.surfaceDark : AppColors.surface; final borderColor = isDark ? AppColors.borderDark : AppColors.border; final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary; final textSecondary = isDark ? AppColors.textSecondaryDark: AppColors.textSecondary; return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, body: Column( children: [ // Header gradient — toujours sombre, texte blanc intentionnel Container( decoration: const BoxDecoration(gradient: UnionFlowColors.primaryGradient), child: SafeArea( bottom: false, child: Padding( padding: const EdgeInsets.fromLTRB(20, 16, 20, 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ IconButton( onPressed: () => Navigator.of(context).maybePop(), icon: const Icon(Icons.arrow_back_rounded, color: Colors.white), padding: EdgeInsets.zero, constraints: const BoxConstraints(), ), const SizedBox(height: 12), const Text( 'Moyen de paiement', style: TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.w800), ), const SizedBox(height: 4), Text( 'Choisissez comment régler votre souscription', style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 13), ), ], ), ), ), ), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 24, 20, 100), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Rappel montant Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: bgCard, borderRadius: BorderRadius.circular(14), border: Border.all(color: borderColor), boxShadow: isDark ? null : UnionFlowColors.softShadow, ), child: Row( children: [ Container( width: 44, height: 44, decoration: BoxDecoration( gradient: UnionFlowColors.goldGradient, borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.receipt_rounded, color: Colors.white, size: 22), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Montant total', style: TextStyle(color: textSecondary, fontSize: 12)), Text( '${_formatPrix(montant)} FCFA', style: TextStyle( color: textPrimary, fontSize: 20, fontWeight: FontWeight.w900, ), ), ], ), ), if (widget.souscription.organisationNom != null) Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text('Organisation', style: TextStyle(color: textSecondary, fontSize: 11)), Text( widget.souscription.organisationNom!, style: TextStyle( color: textPrimary, fontSize: 12, fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, ), ], ), ), ], ), ), const SizedBox(height: 24), Text( 'Sélectionnez un moyen de paiement', style: TextStyle( color: textPrimary, fontWeight: FontWeight.w700, fontSize: 15, ), ), const SizedBox(height: 12), ..._methods.map((m) => _MethodCard( method: m, selected: _selected == m.id, onTap: m.available ? () => setState(() => _selected = m.id) : null, )), const SizedBox(height: 20), // Bandeau sécurité — fond vert pâle adaptatif Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: isDark ? UnionFlowColors.unionGreen.withOpacity(0.1) : UnionFlowColors.unionGreenPale, borderRadius: BorderRadius.circular(12), border: Border.all(color: UnionFlowColors.unionGreen.withOpacity(0.25)), ), child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.lock_rounded, color: UnionFlowColors.unionGreen, size: 18), SizedBox(width: 10), Expanded( child: Text( 'Vos informations de paiement sont sécurisées et ne sont jamais stockées sur nos serveurs. La transaction est traitée directement par Wave.', style: TextStyle( fontSize: 12, color: UnionFlowColors.unionGreen, height: 1.4), ), ), ], ), ), ], ), ), ), ], ), bottomNavigationBar: Container( padding: EdgeInsets.fromLTRB( 20, 12, 20, MediaQuery.of(context).padding.bottom + 12), decoration: BoxDecoration( color: bgCard, border: Border(top: BorderSide(color: borderColor)), boxShadow: [ BoxShadow(color: AppColors.shadow, blurRadius: 12, offset: const Offset(0, -4)), ], ), child: SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: _selected == 'WAVE' ? () => context.read().add(const OnboardingPaiementInitie()) : null, icon: const Icon(Icons.open_in_new_rounded), label: Text( _selected == 'WAVE' ? 'Payer avec Wave' : 'Sélectionnez un moyen de paiement', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700), ), style: ElevatedButton.styleFrom( backgroundColor: _waveBlue, disabledBackgroundColor: isDark ? AppColors.borderDark : AppColors.border, foregroundColor: AppColors.onPrimary, disabledForegroundColor: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), elevation: _selected == 'WAVE' ? 3 : 0, shadowColor: _waveBlue.withOpacity(0.4), ), ), ), ), ); } String _formatPrix(double prix) { if (prix >= 1000000) return '${(prix / 1000000).toStringAsFixed(1)} M'; final s = prix.toStringAsFixed(0); if (s.length > 3) return '${s.substring(0, s.length - 3)} ${s.substring(s.length - 3)}'; return s; } } class _PayMethod { final String id, name, description, logoAsset; final Color color; final bool available; final String badge; const _PayMethod({ required this.id, required this.name, required this.description, required this.logoAsset, required this.color, required this.available, required this.badge, }); } class _MethodCard extends StatelessWidget { final _PayMethod method; final bool selected; final VoidCallback? onTap; const _MethodCard({required this.method, required this.selected, this.onTap}); @override Widget build(BuildContext context) { final disabled = onTap == null; final isDark = Theme.of(context).brightness == Brightness.dark; final bgSurface = isDark ? AppColors.surfaceDark : AppColors.surface; final bgDisabled = isDark ? AppColors.surfaceVariantDark : AppColors.surfaceVariant; final borderDefault = isDark ? AppColors.borderDark : AppColors.border; final textPrimary = isDark ? AppColors.textPrimaryDark : AppColors.textPrimary; final textTertiary = isDark ? AppColors.textSecondaryDark : AppColors.textTertiary; final textSecondary = isDark ? AppColors.textSecondaryDark : AppColors.textSecondary; return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.only(bottom: 10), decoration: BoxDecoration( color: disabled ? bgDisabled : selected ? method.color.withOpacity(isDark ? 0.12 : 0.06) : bgSurface, border: Border.all( color: selected ? method.color : borderDefault, width: selected ? 2 : 1, ), borderRadius: BorderRadius.circular(14), boxShadow: disabled ? [] : selected ? [BoxShadow(color: method.color.withOpacity(0.15), blurRadius: 16, offset: const Offset(0, 6))] : isDark ? null : UnionFlowColors.softShadow, ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( children: [ // Logo — fond blanc intentionnel (logos de marque) Container( width: 56, height: 48, decoration: BoxDecoration( color: disabled ? bgDisabled : Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color: borderDefault), ), padding: const EdgeInsets.all(6), child: Image.asset( method.logoAsset, fit: BoxFit.contain, color: disabled ? textTertiary : null, colorBlendMode: disabled ? BlendMode.srcIn : null, errorBuilder: (_, __, ___) => Icon( Icons.account_balance_wallet_rounded, color: disabled ? textTertiary : method.color, size: 24, ), ), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( method.name, style: TextStyle( fontWeight: FontWeight.w700, fontSize: 14, color: disabled ? textTertiary : textPrimary, ), ), Text( method.description, style: TextStyle( fontSize: 12, color: disabled ? textTertiary : textSecondary, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: disabled ? borderDefault : method.available ? method.color.withOpacity(isDark ? 0.2 : 0.1) : isDark ? AppColors.surfaceVariantDark : AppColors.surfaceVariant, borderRadius: BorderRadius.circular(20), ), child: Text( method.badge, style: TextStyle( fontSize: 10, fontWeight: FontWeight.w700, color: disabled ? textTertiary : method.available ? method.color : textSecondary, ), ), ), if (!disabled) ...[ const SizedBox(height: 6), Icon( selected ? Icons.check_circle_rounded : Icons.radio_button_unchecked, color: selected ? method.color : borderDefault, size: 20, ), ], ], ), ], ), ), ), ); } }