Refactoring
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user