import 'package:flutter/material.dart'; import 'package:prosapp_web_app/providers/auth_provider.dart'; import 'package:prosapp_web_app/providers/professional_provider.dart'; import 'package:prosapp_web_app/providers/score_provider.dart'; import 'package:prosapp_web_app/providers/services_provider.dart'; import 'package:prosapp_web_app/providers/sidemenu_provider.dart'; import 'package:prosapp_web_app/providers/theme_provider.dart'; import 'package:prosapp_web_app/ui/shared/widgets/navbar_avatar.dart'; import 'package:provider/provider.dart'; class Navbar extends StatelessWidget { const Navbar({super.key}); @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final professionalProvider = Provider.of(context); final themeProvider = Provider.of(context); final scoreProvider = Provider.of(context, listen: false); final isDark = themeProvider.isDark; WidgetsBinding.instance.addPostFrameCallback((_) { scoreProvider.loadReputation(context.read().user!.id); }); return Consumer(builder: (context, scoreProvider, _) { final reputation = scoreProvider.reputation; return Container( width: double.infinity, height: 56, decoration: BoxDecoration( color: isDark ? const Color(0xFF1E293B) : Colors.white, boxShadow: [ BoxShadow( color: isDark ? Colors.black38 : Colors.black12, blurRadius: 6, ), ], ), child: Row( children: [ if (size.width <= 700) IconButton( icon: Icon(Icons.menu_outlined, color: isDark ? Colors.white70 : Colors.black87), onPressed: () => SideMenuProvider.openMenu(), ), const SizedBox(width: 8), const Spacer(), // Puntuación Row( children: [ Icon(Icons.star, color: Colors.amber[600], size: 16), const SizedBox(width: 3), Text( professionalProvider.isProModeActive ? reputation.averagePro.toStringAsFixed(1) : reputation.average.toStringAsFixed(1), style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: isDark ? Colors.white70 : Colors.black87, ), ), ], ), const SizedBox(width: 8), // Campana de notificaciones _NotificationBell(isDark: isDark), const SizedBox(width: 4), // Avatar const NavbarAvatar(), const SizedBox(width: 12), ], ), ); }); } } class _NotificationBell extends StatelessWidget { final bool isDark; const _NotificationBell({required this.isDark}); @override Widget build(BuildContext context) { final professionalProvider = Provider.of(context); return Consumer(builder: (context, servicesProvider, _) { // Cuenta servicios pendientes según el modo final pending = servicesProvider.services .where((s) => s.service.status.index == 0) // ServiceStatus.pending .length; return Stack( clipBehavior: Clip.none, children: [ IconButton( tooltip: 'Notificaciones', icon: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: Icon( pending > 0 ? Icons.notifications_active : Icons.notifications_outlined, key: ValueKey(pending > 0), color: pending > 0 ? const Color(0xFF42A4EF) : (isDark ? Colors.white54 : Colors.black54), size: 22, ), ), onPressed: () => _showNotificationsSheet(context, professionalProvider.isProModeActive, servicesProvider), ), if (pending > 0) Positioned( top: 6, right: 6, child: Container( width: 16, height: 16, decoration: const BoxDecoration( color: Color(0xFFEF4444), shape: BoxShape.circle, ), child: Center( child: Text( pending > 9 ? '9+' : '$pending', style: const TextStyle( color: Colors.white, fontSize: 9, fontWeight: FontWeight.bold, ), ), ), ), ), ], ); }); } void _showNotificationsSheet(BuildContext context, bool isPro, ServicesProvider sp) { final isDark = Theme.of(context).brightness == Brightness.dark; final pending = sp.services.where((s) => s.service.status.index == 0).toList(); showModalBottomSheet( context: context, backgroundColor: isDark ? const Color(0xFF1E293B) : Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (_) { return Padding( padding: const EdgeInsets.fromLTRB(20, 12, 20, 24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Container( width: 36, height: 4, decoration: BoxDecoration(color: Colors.grey[400], borderRadius: BorderRadius.circular(2)), ), ), const SizedBox(height: 16), Row( children: [ const Icon(Icons.notifications_outlined, size: 20), const SizedBox(width: 8), const Text('Notificaciones', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const Spacer(), if (pending.isNotEmpty) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: const Color(0xFF42A4EF), borderRadius: BorderRadius.circular(10), ), child: Text('${pending.length} nuevas', style: const TextStyle(color: Colors.white, fontSize: 11)), ), ], ), const SizedBox(height: 12), if (pending.isEmpty) Padding( padding: const EdgeInsets.symmetric(vertical: 24), child: Center( child: Column( children: [ Icon(Icons.notifications_none, size: 48, color: Colors.grey[400]), const SizedBox(height: 8), Text('Sin notificaciones pendientes', style: TextStyle(color: Colors.grey[500])), ], ), ), ) else ...pending.take(5).map((s) => ListTile( contentPadding: EdgeInsets.zero, leading: Container( width: 40, height: 40, decoration: BoxDecoration( color: const Color(0xFF42A4EF).withOpacity(0.12), shape: BoxShape.circle, ), child: const Icon(Icons.room_service_outlined, color: Color(0xFF42A4EF), size: 20), ), title: Text( isPro ? 'Nueva solicitud de servicio' : 'Servicio pendiente', style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600), ), subtitle: Text( s.service.address.isNotEmpty ? s.service.address : 'Sin dirección', style: const TextStyle(fontSize: 12), maxLines: 1, overflow: TextOverflow.ellipsis, ), trailing: const Icon(Icons.circle, color: Color(0xFF42A4EF), size: 8), )), ], ), ); }, ); } }