import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:injector/injector.dart'; import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart'; import 'package:prosappco/blocs/score_bloc/score_bloc.dart'; import 'package:prosappco/components/drawer_reputation.dart'; import 'package:prosappco/components/general_drawer_header.dart'; import 'package:prosappco/components/general_drawer_item.dart'; import 'package:prosappco/screens/configuration/configuration_screen.dart'; import 'package:prosappco/screens/configuration/configuration_support_screen.dart'; import 'package:prosappco/screens/lists/professional_score_list_screen.dart'; import 'package:prosappco/screens/lists/professional_service_history_list_screen.dart'; import 'package:prosappco/screens/lists/professional_service_list_screen.dart'; import 'package:prosappco/screens/lists/user_score_list_screen.dart'; import 'package:prosappco/screens/lists/user_service_history_list_screen.dart'; import 'package:prosappco/screens/lists/user_service_list_screen.dart'; import 'package:prosappco/screens/professional/professional_calendar_screen.dart'; import 'package:prosappco/screens/professional/professional_denied_screen.dart'; import 'package:prosappco/screens/professional/professional_form_screen.dart'; import 'package:prosappco/screens/professional/professional_pending_screen.dart'; import 'package:prosappco/screens/professional/professional_profile_screen.dart'; import 'package:prosappco/screens/profile/profile_screen.dart'; import 'package:prosappco/screens/suggestions/suggestion_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:user_repository/user_repository.dart'; const _kPro = Color(0xFF0D9488); const _kUser = Color(0xFF1565C0); class GeneralDrawer extends StatelessWidget { const GeneralDrawer({super.key}); Future _irSugerencias() async { const url = 'https://admin.prosapp.co/sugerencias'; final Uri uri = Uri.parse(url); if (await canLaunchUrl(uri)) { await launchUrl(uri); } } @override Widget build(BuildContext context) { return BlocProvider( create: (context) => Injector.appInstance.get(), child: BlocBuilder( builder: (context, userState) { return BlocBuilder( builder: (context, professionalState) { final isProMode = _isProModeActive(professionalState); return Drawer( backgroundColor: Theme.of(context).colorScheme.surface, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const GeneralDrawerHeader(), Divider( color: Theme.of(context) .colorScheme .onSurface .withOpacity(0.1), thickness: 0.5, height: 1, ), Expanded( child: SingleChildScrollView( child: Column( children: [ if (isProMode) GeneralDrawerItem( leading: Icons.person_outline_rounded, label: 'Perfil profesional', onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalProfileScreen(), ), ), ), GeneralDrawerItem( leading: Icons.checklist_outlined, label: 'Mis servicios', onTap: () => isProMode ? Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalServiceListScreen()), ) : Navigator.push( context, CupertinoPageRoute( builder: (_) => const UserServiceListScreen()), ), ), GeneralDrawerItem( leading: Icons.access_time_outlined, label: 'Historial', onTap: () => isProMode ? Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalServiceHistoryListScreen()), ) : Navigator.push( context, CupertinoPageRoute( builder: (_) => const UserServiceHistoryListScreen()), ), ), if (isProMode) GeneralDrawerItem( leading: Icons.calendar_month_outlined, label: 'Calendario', onTap: () { if (professionalState is LoadedModeProState && professionalState.proInfo != null) { Navigator.push( context, CupertinoPageRoute( builder: (_) => ProfessionalCalendarScreen( userProfessional: professionalState.proInfo!, ), ), ); } else { ScaffoldMessenger.of(context) .clearSnackBars(); ScaffoldMessenger.of(context) .showSnackBar(const SnackBar( content: Text( 'Cargando tu información de profesional, intenta de nuevo en un momento'), )); } }, ), GeneralDrawerItem( leading: Icons.settings_outlined, label: 'Configuración', onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => const ConfigurationScreen()), ), ), GeneralDrawerItem( leading: Icons.help_outline, label: 'Soporte', onTap: () => Navigator.push( context, CupertinoPageRoute( builder: (_) => const ConfigurationSupportScreen()), ), ), GeneralDrawerItem( leading: Icons.campaign_outlined, label: 'Sugerencias', onTap: () { if (kIsWeb) { _irSugerencias(); } else { Navigator.push( context, CupertinoPageRoute( builder: (_) => const SuggestionScreen(), ), ); } }, ), // CTA item — go to main action _CtaItem( isProMode: isProMode, professionalState: professionalState, ), // Rating row DrawerReputation(builder: (reputation) { final total = isProMode ? reputation.totalPro : reputation.total; final average = isProMode ? reputation.averagePro : reputation.average; return _RatingRow( average: average, total: total, isProMode: isProMode, professionalState: professionalState, ); }), const Divider(height: 1, thickness: 0.5), Padding( padding: const EdgeInsets.only(top: 10, bottom: 4), child: Text( 'Prosapp ® todos los derechos reservados', textAlign: TextAlign.center, style: TextStyle( fontSize: 10, color: Theme.of(context) .colorScheme .onSurface .withOpacity(0.4), ), ), ), ], ), ), ), Divider( color: Theme.of(context) .colorScheme .onSurface .withOpacity(0.1), thickness: 0.5, height: 1, ), const SizedBox(height: 15), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: _ModeButton( professionalState: professionalState, userState: userState, isProMode: isProMode, ), ), const SizedBox(height: 15), ], ), ); }, ); }, ), ); } bool _isProModeActive(ProfessionalState state) => (state is LoadedModeProState) ? state.isProModeActive : false; } // CTA tile navigating to solicitudes / solicitar servicio class _CtaItem extends StatelessWidget { final bool isProMode; final ProfessionalState professionalState; _CtaItem( {required this.isProMode, required this.professionalState}); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isProMode ? _kPro.withOpacity(0.1) : _kUser.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: isProMode ? _kPro.withOpacity(0.25) : _kUser.withOpacity(0.25)), ), child: ListTile( onTap: () => Navigator.pop(context), leading: Icon( isProMode ? Icons.inbox_outlined : Icons.search_rounded, color: isProMode ? _kPro : _kUser, ), title: Text( isProMode ? 'Solicitudes' : 'Solicitar servicio', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: isProMode ? _kPro : _kUser, ), ), trailing: isProMode ? FutureBuilder( future: Injector.appInstance .get() .countPendingServicesForProfessional( ApiUserRepository.currentUserId ?? ''), builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data! < 1) { return Icon(Icons.keyboard_arrow_right, color: _kPro.withOpacity(0.5)); } return Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(12), ), child: Text( snapshot.data! > 9 ? '+9' : snapshot.data!.toString(), style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600), ), ); }, ) : Icon(Icons.keyboard_arrow_right, color: _kUser.withOpacity(0.5)), ), ); } } class _RatingRow extends StatelessWidget { final double average; final int total; final bool isProMode; final ProfessionalState professionalState; _RatingRow( {required this.average, required this.total, required this.isProMode, required this.professionalState}); double _calcRating(double avg) { final parts = avg.toString().split('.'); final frac = parts.length > 1 ? int.parse(parts[1]) : 0; return double.parse( '${parts[0]}.${frac >= 3 ? 5 : 0}'); } @override Widget build(BuildContext context) { return ListTile( onTap: () { isProMode ? Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalScoreListScreen())) : Navigator.push( context, CupertinoPageRoute( builder: (_) => const UserScoreListScreen())); }, leading: Icon(Icons.star_outline_rounded, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6)), trailing: Icon(Icons.keyboard_arrow_right, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.4)), title: Row( children: [ RatingBar.builder( initialRating: _calcRating(average), minRating: 1, direction: Axis.horizontal, allowHalfRating: true, itemCount: 5, itemSize: 20, maxRating: 5, itemBuilder: (_, __) => const Icon(Icons.star, color: Color(0xFF1565C0)), onRatingUpdate: (_) {}, ignoreGestures: true, ), const SizedBox(width: 6), Text( '${average.toStringAsFixed(1)} ($total)', style: TextStyle( fontSize: 13, color: Theme.of(context) .colorScheme .onSurface .withOpacity(0.7)), ), ], ), ); } } class _ModeButton extends StatelessWidget { final ProfessionalState professionalState; final MyUserState userState; final bool isProMode; _ModeButton({ required this.professionalState, required this.userState, required this.isProMode, }); @override Widget build(BuildContext context) { return Stack( children: [ SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: () { if (userState.status == MyUserStatus.success) { final user = userState.user!; if (user.name != null && user.city != null && user.phone != null) { switch (user.proState) { case ProState.active: Navigator.pop(context); context .read() .add(const SwitchProModeEvent()); break; case ProState.inactive: Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalFormScreen()), ); break; case ProState.pending: Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalPendingScreen()), ); break; case ProState.denied: Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfessionalDeniedScreen()), ); break; } } else { final missing = [ if (user.name == null) 'nombre', if (user.city == null) 'ciudad', if (user.phone == null) 'teléfono', ]; ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Completa tu perfil: falta ${missing.join(', ')}')), ); Navigator.push( context, CupertinoPageRoute( builder: (_) => const ProfileScreen()), ); } } }, icon: const Icon(Icons.swap_horiz, size: 20), label: Text( isProMode ? 'Cambiar a modo cliente' : 'Cambiar a modo profesional', style: const TextStyle(fontSize: 15), ), style: ElevatedButton.styleFrom( backgroundColor: isProMode ? _kPro : _kUser, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ), if (!isProMode && professionalState is LoadedModeProState) Positioned( top: 0, right: 0, child: FutureBuilder( future: Injector.appInstance .get() .countPendingServicesForProfessional( ApiUserRepository.currentUserId ?? ''), builder: (context, snapshot) { if (!snapshot.hasData || snapshot.data! < 1) { return const SizedBox(); } return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(12), ), child: Text( snapshot.data! > 9 ? '+9' : snapshot.data!.toString(), style: const TextStyle( color: Colors.white, fontSize: 11, fontWeight: FontWeight.w600), ), ); }, ), ), ], ); } }