import 'package:flutter/material.dart'; import 'package:prosapp_web_app/providers/auth_provider.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:intl/intl.dart'; import 'package:prosapp_web_app/models/message_entity.dart'; import 'package:prosapp_web_app/providers/chat_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/services/navigation_service.dart'; import 'package:provider/provider.dart'; class ChatView extends StatelessWidget { final String type; final String serviceId; final String professionalId; const ChatView({ super.key, required this.type, required this.serviceId, required this.professionalId, }); @override Widget build(BuildContext context) { final chatProvider = Provider.of(context); final servicesProvider = Provider.of(context, listen: false); final scoreProvider = Provider.of(context, listen: false); scoreProvider.loadReputation(professionalId); return StreamBuilder( stream: chatProvider.getChat(serviceId, professionalId), builder: (context, snapshot) { if (!snapshot.hasData) { return const Center(child: CircularProgressIndicator()); } final chat = snapshot.data; if (chat == null) { return const Center( child: Text('Chat no encontrado'), ); } final service = servicesProvider.service?.service; final user = servicesProvider.service?.user; final reputation = scoreProvider.reputation; if (service == null || user == null) { return const Center(child: CircularProgressIndicator()); } final image = (user.picture == '' || user.picture == null) ? const Image(image: AssetImage('no-image.jpg')) : FadeInImage.assetNetwork( placeholder: 'loader.gif', fit: BoxFit.cover, image: user.picture!, ); return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 800), child: Column( children: [ Container( padding: const EdgeInsets.symmetric(vertical: 15), color: const Color(0xFFD6F4FF), alignment: Alignment.topCenter, child: Row( children: [ const SizedBox(width: 20), SizedBox( width: 85, height: 85, child: ClipOval(child: image), ), const SizedBox(width: 20), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( user.name, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), Row( children: [ RatingBar.builder( initialRating: type == 'user' ? calculoRating(reputation.averagePro) : calculoRating(reputation.average), minRating: 1, direction: Axis.horizontal, allowHalfRating: true, itemCount: 5, itemSize: 25, maxRating: 5, itemBuilder: (context, _) => const Icon( Icons.star, color: Color(0xFF2BA4EC), ), onRatingUpdate: (rating) {}, ignoreGestures: true, ), const SizedBox(width: 5), if (type == 'user') Text( '${reputation.averagePro.toStringAsFixed(1)} (${reputation.totalPro.toString()})', ), if (type == 'professional') Text( '${reputation.average.toStringAsFixed(1)} (${reputation.total.toString()})', ), ], ) ], ) ], ), ), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.only(top: 10), reverse: true, child: Column( children: _messagesList(chat.messages, Provider.of(context, listen: false).user!.id), ), ), ), _MessageInput( serviceId: serviceId, userId: Provider.of(context, listen: false).user!.id), ], ), ), ); }, ); } double calculoRating(double average) { String numeroString = average.toString(); List partes = numeroString.split('.'); int parteEntera = int.parse(partes[0]); int parteFraccionaria = partes.length > 1 ? int.parse(partes[1]) : 0; if (parteFraccionaria >= 3) { parteFraccionaria = 5; } else { parteFraccionaria = 0; } // Unir la parte entera y fraccionaria y convertirlo nuevamente a double double resultado = double.parse('$parteEntera.$parteFraccionaria'); return resultado; } List _messagesList(List messages, String currentUserId) { return messages .map( (e) => e.ownerId != currentUserId ? ListTile( title: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: const EdgeInsets.only(right: 60), padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 16), decoration: BoxDecoration( color: Colors.grey.shade300, borderRadius: const BorderRadius.only( topRight: Radius.circular(20), bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20), ), ), child: Text( e.content, style: const TextStyle(fontSize: 16), ), ), const SizedBox(width: 5), Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( _getFechaHoraFormateada(e.createdAt), style: const TextStyle(color: Colors.grey, fontSize: 11), ), ), ], ), ) : ListTile( title: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( margin: const EdgeInsets.only(left: 60), padding: const EdgeInsets.symmetric( vertical: 10, horizontal: 16, ), decoration: const BoxDecoration( color: Color(0xFFD5EFFF), borderRadius: BorderRadius.only( topLeft: Radius.circular(20), bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20), ), ), child: Text( e.content, style: const TextStyle(fontSize: 16), ), ), const SizedBox(width: 5), Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( _getFechaHoraFormateada(e.createdAt), style: const TextStyle( color: Colors.grey, fontSize: 11, ), ), ), ], ), ), ) .toList(); } String _getFechaHoraFormateada(DateTime fecha) { final now = DateTime.now(); final yesterday = now.subtract(const Duration(days: 1)); final formatter = DateFormat('h:mm a'); if (fecha.day == now.day && fecha.month == now.month && fecha.year == now.year) { return 'Hoy - ${formatter.format(fecha)}'; } else if (fecha.day == yesterday.day && fecha.month == yesterday.month && fecha.year == yesterday.year) { return 'Ayer - ${formatter.format(fecha)}'; } else { return '${DateFormat('dd/MM/yyyy').format(fecha)} - ${formatter.format(fecha)}'; } } void navigateTo(String routeName) { NavigationService.replaceTo(routeName); SideMenuProvider.closeMenu(); } } class _MessageInput extends StatefulWidget { final String serviceId; final String userId; const _MessageInput({ required this.serviceId, required this.userId, }); @override State<_MessageInput> createState() => _MessageInputState(); } class _MessageInputState extends State<_MessageInput> { final _controller = TextEditingController(); @override Widget build(BuildContext context) { final chatProvider = Provider.of(context, listen: false); void sendMessage() { if (_controller.text.trim().isNotEmpty) { final message = MessageEntity( ownerId: widget.userId, content: _controller.text.trim(), createdAt: DateTime.now(), ); chatProvider.sendMessage(widget.serviceId, message); _controller.clear(); } } return Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _controller, decoration: InputDecoration( hintText: 'Mensaje', hintStyle: TextStyle(color: Colors.grey[600], fontSize: 16), border: OutlineInputBorder( borderSide: const BorderSide(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(50)), focusedBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.grey, width: 1.0), borderRadius: BorderRadius.circular(50)), contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15), filled: true, fillColor: Colors.grey[200], ), onSubmitted: (value) => sendMessage(), ), ), const SizedBox(width: 12), GestureDetector( onTap: () => sendMessage(), child: Container( height: 50, width: 50, decoration: BoxDecoration( color: const Color(0xFF2BA4EC), borderRadius: BorderRadius.circular(30), ), child: const Center( child: Icon( Icons.send, color: Colors.white, ), ), ), ), ], ), ); } }