import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../shared/widgets/core_card.dart'; /// Page Aide & Support - UnionFlow Mobile /// /// Page complète d'aide avec FAQ, guides, support technique, /// et ressources pour les utilisateurs. class HelpSupportPage extends StatefulWidget { const HelpSupportPage({super.key}); @override State createState() => _HelpSupportPageState(); } class _HelpSupportPageState extends State { final TextEditingController _searchController = TextEditingController(); String _searchQuery = ''; int _selectedCategoryIndex = 0; final List _categories = [ 'Tout', 'Connexion', 'Membres', 'Organisations', 'Événements', 'Technique', ]; @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: const UFAppBar(title: 'AIDE & SUPPORT'), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header harmonisé _buildHeader(), const SizedBox(height: 16), // Barre de recherche _buildSearchSection(), const SizedBox(height: 16), // Actions rapides _buildQuickActionsSection(), const SizedBox(height: 16), // Catégories FAQ _buildCategoriesSection(), const SizedBox(height: 16), // FAQ _buildFAQSection(), const SizedBox(height: 16), // Guides et tutoriels _buildGuidesSection(), const SizedBox(height: 16), // Contact support _buildContactSection(), const SizedBox(height: 80), ], ), ), ); } /// Header épuré Widget _buildHeader() { return Center( child: Column( children: [ Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.primaryGreen.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: const Icon( Icons.help_outline, color: AppColors.primaryGreen, size: 48, ), ), const SizedBox(height: 16), Text( 'COMMENT POUVONS-NOUS VOUS AIDER ?', style: AppTypography.headerSmall.copyWith(fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 4), Text( 'Documentation, FAQ et support technique', style: AppTypography.subtitleSmall, ), ], ), ); } /// Section de recherche Widget _buildSearchSection() { return CoreCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.search, color: AppColors.primaryGreen, size: 18), const SizedBox(width: 8), Text( 'RECHERCHER DANS L\'AIDE', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ], ), const SizedBox(height: 12), Container( decoration: BoxDecoration( color: AppColors.lightSurface, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppColors.lightBorder), ), child: TextField( controller: _searchController, onChanged: (value) => setState(() => _searchQuery = value), style: AppTypography.bodyTextSmall, decoration: InputDecoration( hintText: 'Une question, un mot-clé...', hintStyle: AppTypography.subtitleSmall, prefixIcon: const Icon(Icons.search, color: AppColors.textSecondaryLight, size: 18), suffixIcon: _searchQuery.isNotEmpty ? IconButton( onPressed: () { _searchController.clear(); setState(() => _searchQuery = ''); }, icon: const Icon(Icons.clear, color: AppColors.textSecondaryLight, size: 18), ) : null, border: InputBorder.none, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ), ), ], ), ); } /// Section actions rapides Widget _buildQuickActionsSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 4, bottom: 12), child: Text( 'ACTIONS RAPIDES', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ), Row( children: [ Expanded( child: _buildQuickActionCard( 'CHAT', 'Support Direct', Icons.chat_bubble_outline, AppColors.primaryGreen, () => _startLiveChat(), ), ), const SizedBox(width: 12), Expanded( child: _buildQuickActionCard( 'BUG', 'Signaler', Icons.bug_report_outlined, AppColors.error, () => _reportBug(), ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: _buildQuickActionCard( 'IDÉE', 'Suggérer', Icons.lightbulb_outline, AppColors.warning, () => _requestFeature(), ), ), const SizedBox(width: 12), Expanded( child: _buildQuickActionCard( 'EMAIL', 'Support Tech', Icons.mark_email_read_outlined, AppColors.info, () => _contactByEmail(), ), ), ], ), ], ); } /// Carte d'action rapide Widget _buildQuickActionCard(String title, String subtitle, IconData icon, Color color, VoidCallback onTap) { return CoreCard( padding: const EdgeInsets.all(12), onTap: onTap, child: Column( children: [ Icon(icon, color: color, size: 24), const SizedBox(height: 8), Text( title, style: AppTypography.actionText.copyWith(fontSize: 11), textAlign: TextAlign.center, ), Text( subtitle, style: AppTypography.subtitleSmall.copyWith(fontSize: 9), textAlign: TextAlign.center, ), ], ), ); } /// Section catégories Widget _buildCategoriesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 4, bottom: 8), child: Text( 'PAR CATÉGORIE', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: _categories.asMap().entries.map((entry) { final isSelected = _selectedCategoryIndex == entry.key; return Padding( padding: const EdgeInsets.only(right: 8), child: _buildCategoryChip(entry.value, isSelected, () { setState(() => _selectedCategoryIndex = entry.key); }), ); }).toList(), ), ), ], ); } /// Chip de catégorie Widget _buildCategoryChip(String label, bool isSelected, VoidCallback onTap) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(4), child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: isSelected ? AppColors.primaryGreen.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(4), border: Border.all( color: isSelected ? AppColors.primaryGreen : AppColors.lightBorder, ), ), child: Text( label.toUpperCase(), style: AppTypography.badgeText.copyWith( color: isSelected ? AppColors.primaryGreen : AppColors.textSecondaryLight, fontSize: 9, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ), ); } /// Section FAQ Widget _buildFAQSection() { final faqs = _getFilteredFAQs(); if (faqs.isEmpty) return const SizedBox.shrink(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 4, bottom: 12), child: Text( 'QUESTIONS FRÉQUENTES', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ), ...faqs.map((faq) => Padding( padding: const EdgeInsets.only(bottom: 8), child: _buildFAQItem(faq), )), ], ); } /// Élément FAQ Widget _buildFAQItem(Map faq) { return CoreCard( padding: EdgeInsets.zero, child: ExpansionTile( title: Text( faq['question'], style: AppTypography.actionText.copyWith(fontSize: 12), ), leading: Icon( faq['icon'] as IconData, color: AppColors.primaryGreen, size: 18, ), iconColor: AppColors.primaryGreen, collapsedIconColor: AppColors.textSecondaryLight, shape: const RoundedRectangleBorder(side: BorderSide.none), children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), child: Text( faq['answer'], style: AppTypography.subtitleSmall.copyWith(fontSize: 11, height: 1.4), ), ), ], ), ); } /// Section guides Widget _buildGuidesSection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 4, bottom: 12), child: Text( 'GUIDES & TUTORIELS', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ), _buildGuideItem('Introduction', 'Démarrer avec UnionFlow', Icons.play_circle_outline, AppColors.success, () => _openGuide('getting-started')), _buildGuideItem('Membres', 'Gérer vos adhérents', Icons.people_outline, AppColors.primaryGreen, () => _openGuide('members')), _buildGuideItem('Organisations', 'Structures & Syndicats', Icons.business_outlined, AppColors.info, () => _openGuide('organizations')), ], ); } /// Élément de guide Widget _buildGuideItem(String title, String description, IconData icon, Color color, VoidCallback onTap) { return CoreCard( margin: const EdgeInsets.only(bottom: 8), onTap: onTap, child: Row( children: [ Icon(icon, color: color, size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: AppTypography.actionText.copyWith(fontSize: 12)), Text(description, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)), ], ), ), const Icon(Icons.chevron_right, color: AppColors.textSecondaryLight, size: 16), ], ), ); } /// Section contact Widget _buildContactSection() { return CoreCard( backgroundColor: AppColors.primaryGreen, // Correction: color -> backgroundColor child: Column( children: [ const Icon(Icons.headset_mic_outlined, color: Colors.white, size: 32), const SizedBox(height: 12), Text( 'BESOIN D\'AIDE SUPPLÉMENTAIRE ?', style: AppTypography.headerSmall.copyWith(color: Colors.white, fontSize: 14), textAlign: TextAlign.center, ), const SizedBox(height: 4), Text( 'Disponible lun-ven, 9h-18h', style: AppTypography.subtitleSmall.copyWith(color: Colors.white.withOpacity(0.8)), textAlign: TextAlign.center, ), const SizedBox(height: 20), Row( children: [ Expanded( child: UFPrimaryButton( label: 'EMAIL', // Correction: text -> label onPressed: () => _contactByEmail(), backgroundColor: Colors.white, textColor: AppColors.primaryGreen, ), ), const SizedBox(width: 12), Expanded( child: UFPrimaryButton( label: 'CHAT', // Correction: text -> label onPressed: () => _startLiveChat(), backgroundColor: Colors.white.withOpacity(0.2), textColor: Colors.white, ), ), ], ), ], ), ); } /// Obtenir les FAQs filtrées List> _getFilteredFAQs() { final allFAQs = [ { 'question': 'Comment me connecter à UnionFlow ?', 'answer': 'Utilisez vos identifiants fournis par votre organisation. La connexion se fait via Keycloak pour une sécurité optimale.', 'category': 'Connexion', 'icon': Icons.login, }, { 'question': 'Comment ajouter un nouveau membre ?', 'answer': 'Allez dans la section Membres, cliquez sur le bouton + et remplissez les informations requises. Vous devez avoir les permissions appropriées.', 'category': 'Membres', 'icon': Icons.person_add, }, { 'question': 'Comment créer une nouvelle organisation ?', 'answer': 'Dans la section Organisations, utilisez le bouton "Nouvelle organisation" et suivez les étapes du formulaire.', 'category': 'Organisations', 'icon': Icons.business, }, { 'question': 'Comment planifier un événement ?', 'answer': 'Accédez à la section Événements, cliquez sur "Nouvel événement" et configurez les détails, date, lieu et participants.', 'category': 'Événements', 'icon': Icons.event, }, { 'question': 'L\'application ne se synchronise pas', 'answer': 'Vérifiez votre connexion internet. Si le problème persiste, déconnectez-vous et reconnectez-vous.', 'category': 'Technique', 'icon': Icons.sync_problem, }, { 'question': 'Comment modifier mes informations personnelles ?', 'answer': 'Allez dans Plus > Profil pour modifier vos informations personnelles et préférences.', 'category': 'Tout', 'icon': Icons.edit, }, ]; if (_selectedCategoryIndex == 0) return allFAQs; // Tout final selectedCategory = _categories[_selectedCategoryIndex]; return allFAQs.where((faq) => faq['category'] == selectedCategory).toList(); } // ==================== MÉTHODES D'ACTION ==================== /// Démarrer un chat en direct void _startLiveChat() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Chat en direct'), content: const Text( 'Contacter le support par email pour toute question. ' 'Notre équipe vous répondra dans les meilleurs délais.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _contactByEmail(); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6C5CE7), foregroundColor: Colors.white, ), child: const Text('Envoyer un email'), ), ], ), ); } /// Signaler un bug void _reportBug() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Signaler un bug'), content: const Text( 'Décrivez le problème rencontré et les étapes pour le reproduire. ' 'Notre équipe technique vous répondra rapidement.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _launchUrl('mailto:support@unionflow.com?subject=Rapport de bug - UnionFlow Mobile'); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFE17055), foregroundColor: Colors.white, ), child: const Text('Signaler'), ), ], ), ); } /// Demander une fonctionnalité void _requestFeature() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Demander une fonctionnalité'), content: const Text( 'Partagez vos idées d\'amélioration ! ' 'Nous étudions toutes les suggestions pour améliorer UnionFlow.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _launchUrl('mailto:support@unionflow.com?subject=Demande de fonctionnalité - UnionFlow Mobile'); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF0984E3), foregroundColor: Colors.white, ), child: const Text('Envoyer'), ), ], ), ); } /// Contacter par email void _contactByEmail() { _launchUrl('mailto:support@unionflow.com?subject=Support UnionFlow Mobile'); } /// Ouvrir un guide void _openGuide(String guideId) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Guide'), content: Text( 'Consultez notre documentation en ligne pour le guide "$guideId".', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _launchUrl('https://docs.unionflow.com/$guideId'); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6C5CE7), foregroundColor: Colors.white, ), child: const Text('Voir en ligne'), ), ], ), ); } /// Afficher la visite guidée void _showHelpTour() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Visite guidée'), content: const Text( 'Parcourez les onglets de l\'application pour découvrir les fonctionnalités. ' 'En cas de question, contactez le support par email.', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ElevatedButton( onPressed: () { Navigator.of(context).pop(); _contactByEmail(); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6C5CE7), foregroundColor: Colors.white, ), child: const Text('Contacter le support'), ), ], ), ); } /// Lancer une URL Future _launchUrl(String url) async { try { final uri = Uri.parse(url); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } else { _showErrorSnackBar('Impossible d\'ouvrir le lien'); } } catch (e) { _showErrorSnackBar('Erreur lors de l\'ouverture du lien'); } } /// Afficher un message d'erreur void _showErrorSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: const Color(0xFFE74C3C), behavior: SnackBarBehavior.floating, ), ); } /// Afficher un message de succès void _showSuccessSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: const Color(0xFF00B894), behavior: SnackBarBehavior.floating, ), ); } }