From 1d20687a4395bf4bd1bdbc877f5b8e1aad457e78 Mon Sep 17 00:00:00 2001 From: dahoud <41957584+DahoudG@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:29:26 +0000 Subject: [PATCH] =?UTF-8?q?feat(wave-mock):=20simuler=20le=20paiement=20Wa?= =?UTF-8?q?ve=20en=20mode=20dev=20(=C3=A9pargne=20+=20cotisations)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En mode dev (URL contient 'mock' ou 'localhost', ou !AppConfig.isProd), le paiement Wave est simulé directement sans ouvrir le navigateur : - Dépôt épargne (depot_epargne_dialog.dart) : simulation 800ms + SnackBar succès - Paiement cotisation (payment_dialog.dart) : même pattern En mode prod : comportement inchangé (ouvre l'app Wave via launchUrl). Pattern identique à wave_payment_page.dart (onboarding souscription) appliqué à tous les flux Wave de l'application. --- .../presentation/widgets/payment_dialog.dart | 25 +++++++++++++++++-- .../widgets/depot_epargne_dialog.dart | 24 ++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/features/contributions/presentation/widgets/payment_dialog.dart b/lib/features/contributions/presentation/widgets/payment_dialog.dart index 8d87065..f409188 100644 --- a/lib/features/contributions/presentation/widgets/payment_dialog.dart +++ b/lib/features/contributions/presentation/widgets/payment_dialog.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../shared/design_system/tokens/color_tokens.dart'; import '../../../../shared/design_system/tokens/app_colors.dart'; +import '../../../../core/config/environment.dart'; import 'package:intl/intl.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:unionflow_mobile_apps/core/di/injection.dart'; @@ -445,9 +446,29 @@ class _PaymentDialogState extends State { numeroTelephone: phone, ); final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl; - if (url.isEmpty) { - throw Exception('URL Wave non reçue'); + if (url.isEmpty) throw Exception('URL Wave non reçue'); + + // Mode dev/mock : simuler le paiement sans ouvrir le navigateur + final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd; + if (isMock) { + await Future.delayed(const Duration(milliseconds: 800)); + if (!mounted) return; + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row(children: [ + Icon(Icons.science_rounded, color: AppColors.onPrimary, size: 16), + const SizedBox(width: 8), + const Expanded(child: Text('Paiement simulé avec succès (mode dev)')), + ]), + backgroundColor: AppColors.success, + ), + ); + context.read().add(const LoadContributions()); + return; } + + // Mode prod : ouvrir Wave final uri = Uri.parse(url); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); diff --git a/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart b/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart index f6dc730..c9c1a07 100644 --- a/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart +++ b/lib/features/epargne/presentation/widgets/depot_epargne_dialog.dart @@ -4,6 +4,7 @@ import 'package:get_it/get_it.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:file_picker/file_picker.dart'; +import '../../../../core/config/environment.dart'; import '../../../../core/constants/lcb_ft_constants.dart'; import '../../../../core/data/repositories/parametres_lcb_ft_repository.dart'; import '../../../../core/utils/error_formatter.dart'; @@ -159,6 +160,29 @@ class _DepotEpargneDialogState extends State { ); final url = result.waveLaunchUrl.isNotEmpty ? result.waveLaunchUrl : result.redirectUrl; if (url.isEmpty) throw Exception('URL Wave non reçue'); + + // Mode dev/mock : simuler le paiement au lieu d'ouvrir le navigateur + final isMock = url.contains('mock') || url.contains('localhost') || !AppConfig.isProd; + if (isMock) { + // Simulation : attendre 1s puis confirmer le succès + await Future.delayed(const Duration(milliseconds: 800)); + if (!mounted) return; + Navigator.of(context).pop(true); + widget.onSuccess?.call(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Row(children: [ + Icon(Icons.science_rounded, color: Colors.white, size: 16), + SizedBox(width: 8), + Expanded(child: Text('Dépôt simulé avec succès (mode dev)')), + ]), + backgroundColor: AppColors.success, + ), + ); + return; + } + + // Mode prod : ouvrir Wave final uri = Uri.parse(url); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication);