import 'package:intl/intl.dart'; import 'package:prosapp_web_app/models/schedules_entity.dart'; import 'package:prosapp_web_app/models/service.dart'; import 'package:prosapp_web_app/models/service_location_preferences.dart'; import 'package:prosapp_web_app/models/service_status.dart'; import 'package:prosapp_web_app/models/usuario.dart'; import 'package:prosapp_web_app/providers/services_provider.dart'; import 'package:prosapp_web_app/providers/settings_provider.dart'; import 'package:prosapp_web_app/providers/sidemenu_provider.dart'; import 'package:prosapp_web_app/router/router.dart'; import 'package:prosapp_web_app/services/navigation_service.dart'; import 'package:prosapp_web_app/ui/cards/white_card.dart'; import 'package:flutter/material.dart'; import 'package:prosapp_web_app/ui/views/no_page_found_view.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:prosapp_web_app/utils/local_notifications.dart'; class ServiceView extends StatelessWidget { final String type; final String serviceId; const ServiceView({ super.key, required this.type, required this.serviceId, }); @override Widget build(BuildContext context) { final settingsProvider = Provider.of(context); final servicesProvider = Provider.of(context, listen: false); if (type == 'user') { servicesProvider.getServiceForUser(serviceId); } if (type == 'professional') { servicesProvider.getServiceForProfessional(serviceId); } return Consumer( builder: (context, servicesProvider, child) { if (servicesProvider.isLoading) { return const Center(child: CircularProgressIndicator()); } if (servicesProvider.service == null) { // return const NoPageFoundView(); return Center(child: Text('No se encontrĂ³ el servicio.')); } final service = servicesProvider.service!.service; final user = servicesProvider.service!.user; 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 ListView( children: [ Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 900), child: WhiteCard( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( width: 100, height: 100, child: ClipOval(child: image), ), const SizedBox(height: 16.0), Text( user.name.toUpperCase(), style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 5.0), Text( '${DateFormat('dd MMMM yyyy', 'es').format(DateTime.parse(service.day))} - ${ScheduleEntity.getFormatTime(service.range1Hour1)}', style: const TextStyle( fontSize: 16, color: Colors.grey), ), const SizedBox(height: 10.0), Container( padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 5, ), decoration: BoxDecoration( color: const Color(0xFFD6F4FF), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 1, blurRadius: 5, offset: const Offset(1, 3), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon( Icons.error_outline, size: 20, color: Colors.black54, ), const SizedBox(width: 10), Text( _CustomServiceLocation(service.location), style: const TextStyle( fontSize: 16, color: Colors.black54), ), ], ), ), if (service.description.isNotEmpty) ...[ const SizedBox(height: 12.0), Text( '"${service.description.trim()}"', style: const TextStyle(color: Colors.grey), textAlign: TextAlign.center, ), ], const SizedBox(height: 20.0), customActionButtons(service, user), const SizedBox(height: 40.0), customMessageStatus(service, user), const SizedBox(height: 20.0), customButton( service, context, user, servicesProvider), ], ), ), ), ], ), ), ), ), ], ); }); } void navigateTo(String routeName) { NavigationService.replaceTo(routeName); SideMenuProvider.closeMenu(); } Widget customActionButtons(Service service, Usuario user) { DateTime serviceDate = DateTime.parse(service.day); DateTime now = DateTime.now(); DateTime serviceDateTime = DateTime( serviceDate.year, serviceDate.month, serviceDate.day, service.range1Hour2.hour, service.range1Hour2.minute, ); if (service.status == ServiceStatus.acepted || service.status == ServiceStatus.active) { if (now.isAfter(serviceDateTime)) { return const SizedBox(); } else { return Wrap( alignment: WrapAlignment.center, spacing: 15, children: [ Visibility( visible: user.phone == null || user.phone == '' ? false : true, child: ElevatedButton( onPressed: () => launch("tel:${user.phone}"), style: ElevatedButton.styleFrom( foregroundColor: const Color(0xFF2BA4EC), backgroundColor: Colors.white, shape: const CircleBorder( side: BorderSide( color: Color(0xFF2BA4EC), width: 2, ), ), ), child: const Padding( padding: EdgeInsets.symmetric(vertical: 20, horizontal: 0), child: Icon( Icons.phone_android, size: 30, color: Color(0xFF2BA4EC), ), ), ), ), ElevatedButton( onPressed: () { if (type == 'user') { NavigationService.navigateTo( '/dashboard/user/service/${service.id}/chat/${user.id}'); } if (type == 'professional') { NavigationService.navigateTo( '/dashboard/professional/service/${service.id}/chat/${user.id}'); } }, style: ElevatedButton.styleFrom( foregroundColor: const Color(0xFF2BA4EC), backgroundColor: Colors.white, shape: const CircleBorder( side: BorderSide( color: Color(0xFF2BA4EC), width: 2, ), ), ), child: const Padding( padding: EdgeInsets.symmetric(vertical: 20, horizontal: 0), child: Icon( Icons.message, size: 30, color: Color(0xFF2BA4EC), ), ), ), ], ); } } return const SizedBox(); } Widget customMessageStatus(Service service, Usuario user) { DateTime serviceDate = DateTime.parse(service.day); DateTime now = DateTime.now(); DateTime serviceDateTime = DateTime( serviceDate.year, serviceDate.month, serviceDate.day, service.range1Hour2.hour, service.range1Hour2.minute, ); if (type == 'user') { if (service.status == ServiceStatus.completed && service.professionalScored == false) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.green.shade50, child: Padding( padding: const EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( children: [ const Text( 'Completado', style: TextStyle(fontSize: 32, color: Colors.green), ), const Text( 'Califica el servicio', style: TextStyle(fontSize: 20, color: Colors.green), ), const SizedBox(height: 15), FilledButton( onPressed: () { NavigationService.navigateTo( '/dashboard/user/service/${service.id}/rating/${user.id}'); }, style: FilledButton.styleFrom( backgroundColor: Colors.green, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Container( alignment: Alignment.center, child: const Text( 'Calificar', style: TextStyle( color: Colors.white, fontSize: 18, ), ), ), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.green.shade50, width: 4), shape: BoxShape.circle, ), child: const Icon( Icons.star, color: Colors.green, size: 48, ), ), ) ], ); } if (service.status == ServiceStatus.completed && service.professionalScored == true) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.green.shade50, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( children: [ Text( 'Completado', style: TextStyle(fontSize: 32, color: Colors.green), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.green.shade50, width: 4), shape: BoxShape.circle, ), child: const Icon( Icons.star, color: Colors.green, size: 48, ), ), ) ], ); } if (service.status == ServiceStatus.cancelled) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Text( 'Cancelado', style: TextStyle(fontSize: 32, color: Colors.red), ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } if (service.status == ServiceStatus.denied) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Text( 'Rechazado', style: TextStyle(fontSize: 32, color: Colors.red), ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } if (now.isAfter(serviceDateTime)) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Caducado', style: TextStyle(fontSize: 32, color: Colors.red), ), Text( 'Tu servicio ha excedido \n el tiempo de espera', textAlign: TextAlign.center, style: TextStyle(fontSize: 18, color: Colors.red), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } } if (type == 'professional') { if (service.status == ServiceStatus.completed && service.userScored == false) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.green.shade50, child: Padding( padding: const EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( children: [ const Text( 'Completado', style: TextStyle(fontSize: 32, color: Colors.green), ), const Text( 'Califica el servicio', style: TextStyle(fontSize: 20, color: Colors.green), ), const SizedBox(height: 15), FilledButton( onPressed: () { NavigationService.navigateTo( '/dashboard/professional/service/${service.id}/rating/${user.id}'); }, style: FilledButton.styleFrom( backgroundColor: Colors.green, padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Container( alignment: Alignment.center, child: const Text( 'Calificar', style: TextStyle( color: Colors.white, fontSize: 18, ), ), ), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.green.shade50, width: 4), shape: BoxShape.circle, ), child: const Icon( Icons.star, color: Colors.green, size: 48, ), ), ) ], ); } if (service.status == ServiceStatus.completed && service.userScored == true) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.green.shade50, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( children: [ Text( 'Completado', style: TextStyle(fontSize: 32, color: Colors.green), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.green.shade50, width: 4), shape: BoxShape.circle, ), child: const Icon( Icons.star, color: Colors.green, size: 48, ), ), ) ], ); } if (service.status == ServiceStatus.cancelled) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Text( 'Cancelado', style: TextStyle(fontSize: 32, color: Colors.red), ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } if (service.status == ServiceStatus.denied) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Text( 'Rechazado', style: TextStyle(fontSize: 32, color: Colors.red), ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } if (now.isAfter(serviceDateTime)) { return Stack( alignment: AlignmentDirectional.topCenter, clipBehavior: Clip.none, children: [ Card( color: Colors.red.shade100, child: const Padding( padding: EdgeInsets.fromLTRB(32, 56, 32, 32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Caducado', style: TextStyle(fontSize: 32, color: Colors.red), ), Text( 'Tu servicio ha excedido \n el tiempo de espera', textAlign: TextAlign.center, style: TextStyle(fontSize: 18, color: Colors.red), ), ], ), ), ), Positioned( top: -40, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.red.shade100, width: 4), shape: BoxShape.circle, ), child: const Icon(Icons.close_rounded, color: Colors.red, size: 48), ), ) ], ); } } return const SizedBox(); } Widget customButton(Service service, BuildContext context, Usuario userInfo, ServicesProvider servicesProvider) { DateTime serviceDate = DateTime.parse(service.day); DateTime now = DateTime.now(); DateTime serviceDateTime = DateTime( serviceDate.year, serviceDate.month, serviceDate.day, service.range1Hour2.hour, service.range1Hour2.minute, ); if (now.isAfter(serviceDateTime)) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () { navigateTo(Flurorouter.dashboardRoute); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Volver', style: TextStyle(color: Colors.white)), ), ); } else { if (type == 'professional') { if (service.status == ServiceStatus.pending) { return Column( children: [ ConstrainedBox( constraints: const BoxConstraints(maxWidth: 160), child: ElevatedButton( onPressed: () async { await servicesProvider.changeServiceStatus( service.id!, ServiceStatus.denied); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.red.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Rechazar servicio', style: TextStyle(color: Colors.white)), ), ), const SizedBox(height: 8), ConstrainedBox( constraints: const BoxConstraints(maxWidth: 160), child: ElevatedButton( onPressed: () { servicesProvider.changeServiceStatus( service.id!, ServiceStatus.acepted); navigateTo(Flurorouter.dashboardRoute); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Aceptar servicio', style: TextStyle(color: Colors.white)), ), ), ], ); } if (service.status == ServiceStatus.acepted) { if (serviceDateTime.difference(now).inDays > 1) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () { servicesProvider.changeServiceStatus( service.id!, ServiceStatus.denied); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.red.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Cancelar servicio', style: TextStyle(color: Colors.white)), ), ); } else { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 160), child: ElevatedButton( onPressed: () { servicesProvider.changeServiceStatus( service.id!, ServiceStatus.active); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Iniciar servicio', style: TextStyle(color: Colors.white)), ), ); } } if (service.status == ServiceStatus.active) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 160), child: ElevatedButton( onPressed: () { servicesProvider.changeServiceStatus( service.id!, ServiceStatus.completed); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Terminar servicio', style: TextStyle(color: Colors.white)), ), ); } } if (type == 'user') { if (service.status == ServiceStatus.pending) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.red.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Cancelar servicio', style: TextStyle(color: Colors.white)), ), ); } if (service.status == ServiceStatus.acepted) { if (serviceDateTime.difference(now).inDays > 1) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.red.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Cancelar servicio', style: TextStyle(color: Colors.white)), ), ); } } if (service.status == ServiceStatus.active) { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Terminar servicio', style: TextStyle(color: Colors.white)), ), ); // GeneralSecondaryButton( // label: 'Terminar servicio', // onPressed: () { // // final currentState = context.read().state; // // if (currentState is ServiceLoaded) { // // context.read().add(UpdateServiceStatus( // // widget.serviceId, ServiceStatus.completed)); // // } // }); } } } return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 130), child: ElevatedButton( onPressed: () { if (type == 'professional') { navigateTo(Flurorouter.professionalServicesRequestsRoute); } if (type == 'user') { navigateTo(Flurorouter.dashboardRoute); } }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( Colors.blue.shade400, ), shape: WidgetStateProperty.all(const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(5)), )), shadowColor: WidgetStateProperty.all(Colors.transparent), ), child: const Text('Volver', style: TextStyle(color: Colors.white)), ), ); } String _CustomServiceLocation(ServiceLocationPreferences location) { if (type == 'user') { if (location == ServiceLocationPreferences.office) { return 'Servicio en sitio / consultorio'; } } if (type == 'professional') { if (location == ServiceLocationPreferences.office) { return 'Servicio en tu consultorio'; } } if (location == ServiceLocationPreferences.delivery) { return 'Servicio a domicilio'; } return 'Error al cargar el servicio.'; } }