364 lines
11 KiB
Dart
364 lines
11 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import '../../../../core/models/cotisation_model.dart';
|
|
import '../../../../core/services/wave_payment_service.dart';
|
|
import '../../../../core/di/injection.dart';
|
|
import '../../../../shared/theme/app_theme.dart';
|
|
import '../../../../shared/widgets/buttons/primary_button.dart';
|
|
import '../pages/wave_payment_page.dart';
|
|
|
|
/// Widget d'intégration Wave Money pour les cotisations
|
|
/// Affiche les options de paiement Wave avec calcul des frais
|
|
class WavePaymentWidget extends StatefulWidget {
|
|
final CotisationModel cotisation;
|
|
final VoidCallback? onPaymentInitiated;
|
|
final bool showFullInterface;
|
|
|
|
const WavePaymentWidget({
|
|
super.key,
|
|
required this.cotisation,
|
|
this.onPaymentInitiated,
|
|
this.showFullInterface = false,
|
|
});
|
|
|
|
@override
|
|
State<WavePaymentWidget> createState() => _WavePaymentWidgetState();
|
|
}
|
|
|
|
class _WavePaymentWidgetState extends State<WavePaymentWidget>
|
|
with SingleTickerProviderStateMixin {
|
|
late WavePaymentService _wavePaymentService;
|
|
late AnimationController _animationController;
|
|
late Animation<double> _scaleAnimation;
|
|
late Animation<double> _fadeAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_wavePaymentService = getIt<WavePaymentService>();
|
|
|
|
_animationController = AnimationController(
|
|
duration: const Duration(milliseconds: 600),
|
|
vsync: this,
|
|
);
|
|
|
|
_scaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
|
|
CurvedAnimation(parent: _animationController, curve: Curves.elasticOut),
|
|
);
|
|
|
|
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
|
CurvedAnimation(parent: _animationController, curve: Curves.easeOut),
|
|
);
|
|
|
|
_animationController.forward();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animationController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FadeTransition(
|
|
opacity: _fadeAnimation,
|
|
child: ScaleTransition(
|
|
scale: _scaleAnimation,
|
|
child: widget.showFullInterface
|
|
? _buildFullInterface()
|
|
: _buildCompactInterface(),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildFullInterface() {
|
|
final remainingAmount = widget.cotisation.montantDu - widget.cotisation.montantPaye;
|
|
final fees = _wavePaymentService.calculateWaveFees(remainingAmount);
|
|
final total = remainingAmount + fees;
|
|
|
|
return Container(
|
|
margin: const EdgeInsets.all(16),
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
colors: [Color(0xFF00D4FF), Color(0xFF0099CC)],
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
),
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: const Color(0xFF00D4FF).withOpacity(0.3),
|
|
blurRadius: 12,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Header Wave
|
|
Row(
|
|
children: [
|
|
Container(
|
|
width: 50,
|
|
height: 50,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(25),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.1),
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: const Icon(
|
|
Icons.waves,
|
|
size: 28,
|
|
color: Color(0xFF00D4FF),
|
|
),
|
|
),
|
|
const SizedBox(width: 16),
|
|
const Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'Wave Money',
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
Text(
|
|
'Paiement mobile instantané',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.white70,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: const Text(
|
|
'🇨🇮 CI',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Détails du paiement
|
|
Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.15),
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
_buildPaymentRow('Montant', '${remainingAmount.toStringAsFixed(0)} XOF'),
|
|
_buildPaymentRow('Frais Wave', '${fees.toStringAsFixed(0)} XOF'),
|
|
const Divider(color: Colors.white30, height: 20),
|
|
_buildPaymentRow(
|
|
'Total',
|
|
'${total.toStringAsFixed(0)} XOF',
|
|
isTotal: true,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Avantages Wave
|
|
_buildAdvantages(),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
// Bouton de paiement
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: PrimaryButton(
|
|
text: 'Payer avec Wave',
|
|
icon: Icons.payment,
|
|
onPressed: _navigateToWavePayment,
|
|
backgroundColor: Colors.white,
|
|
textColor: const Color(0xFF00D4FF),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildCompactInterface() {
|
|
final remainingAmount = widget.cotisation.montantDu - widget.cotisation.montantPaye;
|
|
final fees = _wavePaymentService.calculateWaveFees(remainingAmount);
|
|
|
|
return Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12),
|
|
border: Border.all(color: const Color(0xFF00D4FF).withOpacity(0.3)),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: const Color(0xFF00D4FF).withOpacity(0.1),
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 40,
|
|
height: 40,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF00D4FF).withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: const Icon(
|
|
Icons.waves,
|
|
size: 24,
|
|
color: Color(0xFF00D4FF),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'Wave Money',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.textPrimary,
|
|
),
|
|
),
|
|
Text(
|
|
'Frais: ${fees.toStringAsFixed(0)} XOF • Instantané',
|
|
style: const TextStyle(
|
|
fontSize: 12,
|
|
color: AppTheme.textSecondary,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
PrimaryButton(
|
|
text: 'Payer',
|
|
onPressed: _navigateToWavePayment,
|
|
backgroundColor: const Color(0xFF00D4FF),
|
|
isCompact: true,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPaymentRow(String label, String value, {bool isTotal = false}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: isTotal ? 16 : 14,
|
|
fontWeight: isTotal ? FontWeight.bold : FontWeight.normal,
|
|
color: Colors.white70,
|
|
),
|
|
),
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: isTotal ? 16 : 14,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildAdvantages() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'Pourquoi choisir Wave ?',
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
_buildAdvantageItem('⚡', 'Paiement instantané'),
|
|
_buildAdvantageItem('🔒', 'Sécurisé et fiable'),
|
|
_buildAdvantageItem('💰', 'Frais les plus bas'),
|
|
_buildAdvantageItem('📱', 'Simple et rapide'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildAdvantageItem(String icon, String text) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
icon,
|
|
style: const TextStyle(fontSize: 12),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
text,
|
|
style: const TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.white70,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
void _navigateToWavePayment() {
|
|
// Feedback haptique
|
|
HapticFeedback.lightImpact();
|
|
|
|
// Callback si fourni
|
|
widget.onPaymentInitiated?.call();
|
|
|
|
// Navigation vers la page de paiement Wave
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => WavePaymentPage(cotisation: widget.cotisation),
|
|
),
|
|
);
|
|
}
|
|
}
|