diff --git a/lib/components/general_secondary_button.dart b/lib/components/general_secondary_button.dart new file mode 100644 index 0000000..c781c51 --- /dev/null +++ b/lib/components/general_secondary_button.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +class GeneralSecondaryButton extends StatelessWidget { + final String label; + final VoidCallback onPressed; + final Color? color; + + const GeneralSecondaryButton({ + super.key, + required this.label, + required this.onPressed, + this.color, + }); + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: onPressed, + style: FilledButton.styleFrom( + backgroundColor: color ?? Theme.of(context).colorScheme.primary, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Container( + alignment: Alignment.center, + child: Text( + label, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), + ), + ), + ); + } +} diff --git a/lib/screens/lists/professional_service_history_list_screen.dart b/lib/screens/lists/professional_service_history_list_screen.dart index 014b656..c1264c8 100644 --- a/lib/screens/lists/professional_service_history_list_screen.dart +++ b/lib/screens/lists/professional_service_history_list_screen.dart @@ -6,6 +6,7 @@ import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; +import 'package:prosappco/screens/service/professional_service_screen.dart'; import 'package:prosappco/screens/service/service_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:shimmer/shimmer.dart'; @@ -52,7 +53,6 @@ class _ProfessionalServiceHistoryListScreenState itemBuilder: (_, index) { final serviceInfo = serviceState.services[index]; final user = serviceInfo.user; - final professional = serviceInfo.professional; final service = serviceInfo.service; return Container( @@ -68,7 +68,9 @@ class _ProfessionalServiceHistoryListScreenState context, CupertinoPageRoute( builder: (context) => - const ServiceScreen(), + ProfessionalServiceScreen( + serviceId: service.id!, + ), ), ); }, @@ -178,8 +180,8 @@ class _ProfessionalServiceHistoryListScreenState if (service.status == ServiceStatus.completed) { return itemStatus(Colors.blueAccent, 'Completado'); } - if (service.status == ServiceStatus.cancelled) { - return itemStatus(Colors.red, 'Cancelado'); + if (service.status == ServiceStatus.denied) { + return itemStatus(Colors.red, 'Rechazado'); } return itemStatus(Colors.red, 'Cancelado'); @@ -205,9 +207,3 @@ class _ProfessionalServiceHistoryListScreenState ); } } - -// pending - 0 -// acepted - 1 -// active - 2 -// cancelled - 3 -// completed - 4 \ No newline at end of file diff --git a/lib/screens/lists/professional_service_list_screen.dart b/lib/screens/lists/professional_service_list_screen.dart index eb2eef5..64f9784 100644 --- a/lib/screens/lists/professional_service_list_screen.dart +++ b/lib/screens/lists/professional_service_list_screen.dart @@ -6,6 +6,7 @@ import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; +import 'package:prosappco/screens/service/professional_service_screen.dart'; import 'package:prosappco/screens/service/service_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:shimmer/shimmer.dart'; @@ -38,7 +39,7 @@ class _ProfessionalServiceListScreenState create: (context) => serviceBloc, child: Scaffold( appBar: AppBar( - title: const Text('Mis Servicios'), + title: const Text('Mis servicios'), ), body: BlocBuilder( builder: (context, serviceState) { @@ -66,7 +67,10 @@ class _ProfessionalServiceListScreenState Navigator.push( context, CupertinoPageRoute( - builder: (context) => const ServiceScreen(), + builder: (context) => + ProfessionalServiceScreen( + serviceId: service.id!, + ), ), ); }, @@ -127,10 +131,12 @@ class _ProfessionalServiceListScreenState customStatus(service), ], ), - Text( - '"${service.description.trim()}"', - overflow: TextOverflow.ellipsis, - ), + service.description.isEmpty + ? Container() + : Text( + '"${service.description.trim()}"', + overflow: TextOverflow.ellipsis, + ), ], ), ), diff --git a/lib/screens/lists/user_service_history_list_screen.dart b/lib/screens/lists/user_service_history_list_screen.dart index a92e3ae..451bef2 100644 --- a/lib/screens/lists/user_service_history_list_screen.dart +++ b/lib/screens/lists/user_service_history_list_screen.dart @@ -7,6 +7,7 @@ import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; import 'package:prosappco/screens/service/service_screen.dart'; +import 'package:prosappco/screens/service/user_service_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:shimmer/shimmer.dart'; @@ -67,7 +68,9 @@ class _UserServiceHistoryListScreenState Navigator.push( context, CupertinoPageRoute( - builder: (context) => const ServiceScreen(), + builder: (context) => UserServiceScreen( + serviceId: service.id!, + ), ), ); }, diff --git a/lib/screens/lists/user_service_list_screen.dart b/lib/screens/lists/user_service_list_screen.dart index 4c8ca6c..0956aab 100644 --- a/lib/screens/lists/user_service_list_screen.dart +++ b/lib/screens/lists/user_service_list_screen.dart @@ -7,6 +7,7 @@ import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; import 'package:prosappco/screens/service/service_screen.dart'; +import 'package:prosappco/screens/service/user_service_screen.dart'; import 'package:service_repository/service_repository.dart'; import 'package:shimmer/shimmer.dart'; @@ -65,7 +66,9 @@ class _UserServiceListScreenState extends State { Navigator.push( context, CupertinoPageRoute( - builder: (context) => const ServiceScreen(), + builder: (context) => UserServiceScreen( + serviceId: service.id!, + ), ), ); }, diff --git a/lib/screens/service/professional_service_screen.dart b/lib/screens/service/professional_service_screen.dart new file mode 100644 index 0000000..ad08b3a --- /dev/null +++ b/lib/screens/service/professional_service_screen.dart @@ -0,0 +1,495 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:injector/injector.dart'; +import 'package:intl/intl.dart'; +import 'package:professional_repository/professional_repository.dart'; +import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; +import 'package:prosappco/components/general_secondary_button.dart'; +import 'package:service_repository/service_repository.dart'; +import 'package:setting_repository/setting_repository.dart'; +import 'package:user_repository/user_repository.dart'; + +class ProfessionalServiceScreen extends StatefulWidget { + final String serviceId; + const ProfessionalServiceScreen({super.key, required this.serviceId}); + + @override + State createState() => + _ProfessionalServiceScreenState(); +} + +class _ProfessionalServiceScreenState extends State { + final settingRepository = Injector.appInstance.get(); + SettingEntity? settings; + + @override + void initState() { + super.initState(); + + _loadSettings(); + } + + void _loadSettings() { + settingRepository.getSettings().then( + (value) => setState(() { + settings = value; + }), + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => Injector.appInstance.get(), + child: Scaffold( + appBar: AppBar( + title: const Text('Servicio'), + ), + body: BlocBuilder( + builder: (context, state) { + if (state is ServiceLoaded) { + final service = state.service; + return FutureBuilder( + future: _getUserAndProfessionalInfo(service), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else { + if (snapshot.hasError) { + return Center( + child: Text('Error inesperado: ${snapshot.error}'), + ); + } else { + final userInfo = snapshot.data![0] as MyUser; + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + ListTile( + leading: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey.shade300, + shape: BoxShape.circle, + image: userInfo.picture == null + ? null + : DecorationImage( + image: NetworkImage( + userInfo.picture!, + ), + fit: BoxFit.contain, + ), + ), + child: userInfo.picture == null + ? Icon( + CupertinoIcons.person, + color: Colors.grey.shade400, + size: 40, + ) + : null, + ), + title: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${userInfo.name}', + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + const SizedBox(width: 5), + Text( + '${DateFormat('dd MMMM', 'es').format(DateTime.parse(service.day))} - ${ScheduleEntity.getFormatTime(service.range1Hour1)}', + style: TextStyle( + color: Colors.grey[600], + ), + ), + ], + ), + subtitle: const Text('Rating: 5.0'), + ), + Container( + margin: const EdgeInsets.only( + left: 40, + right: 40, + top: 20, + bottom: 20, + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 15, + ), + 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( + children: [ + const Icon( + Icons.error_outline, + size: 27, + color: Colors.black54, + ), + const SizedBox(width: 15), + service.location == + ServiceLocationPreferences + .delivery + ? const Text( + 'Servicio a domicilio.', + style: TextStyle( + color: Colors.black, + fontSize: 14, + ), + ) + : const Text( + 'Servicio en tu consultorio', + style: TextStyle( + color: Colors.black, + fontSize: 14, + ), + ), + ], + ), + ), + ListTile( + leading: const Icon(Icons.near_me), + title: Text( + service.address, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600], + ), + ), + subtitle: service.aditionalAddress.isEmpty + ? null + : Text( + service.aditionalAddress, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600], + ), + ), + ), + service.description.isEmpty + ? const SizedBox() + : Container( + alignment: Alignment.center, + width: MediaQuery.of(context) + .size + .width * + 0.8, + child: Text( + '"${service.description.trim()}"', + style: TextStyle( + color: Colors.grey[600], + fontStyle: FontStyle.italic, + ), + ), + ), + const SizedBox(height: 65), + customMessageStatus(service), + const SizedBox(height: 20), + ], + ), + ), + ), + const Divider( + height: 1, + thickness: 0.5, + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + child: customButton(service, context), + ), + ], + ); + } + } + }, + ); + } else { + BlocProvider.of(context) + .add(LoadService(widget.serviceId)); + return const Center(child: CircularProgressIndicator()); + } + }, + ), + ), + ); + } + + Widget customMessageStatus(ServiceEntity service) { + if (service.status == ServiceStatus.acepted) { + 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: Text( + 'Aceptado', + 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.check, 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 (service.status == ServiceStatus.active) { + 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: Text( + 'En proceso...', + 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.access_time_rounded, + color: Colors.green, + size: 48, + ), + ), + ) + ], + ); + } + if (service.status == ServiceStatus.completed) { + 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: 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, + ), + ), + ) + ], + ); + } + + return const SizedBox(); + } + + Widget customButton(ServiceEntity service, BuildContext context) { + if (service.status == ServiceStatus.pending) { + return Column( + children: [ + GeneralSecondaryButton( + label: 'Rechazar servicio', + color: Theme.of(context).colorScheme.error, + onPressed: () { + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add(UpdateServiceStatus( + widget.serviceId, ServiceStatus.denied)); + } + }, + ), + const SizedBox(height: 10), + GeneralSecondaryButton( + label: 'Aceptar servicio', + onPressed: () { + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add(UpdateServiceStatus( + widget.serviceId, ServiceStatus.acepted)); + } + }, + ), + ], + ); + } + if (service.status == ServiceStatus.acepted) { + return GeneralSecondaryButton( + label: 'Iniciar servicio', + onPressed: () { + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add( + UpdateServiceStatus(widget.serviceId, ServiceStatus.active)); + } + }, + ); + // customStatusButton( + // label: 'Iniciar servicio', + // onPressed: () { + // final currentState = context.read().state; + // if (currentState is ServiceLoaded) { + // context.read().add( + // UpdateServiceStatus(widget.serviceId, ServiceStatus.active)); + // } + // }, + // ); + } + + if (service.status == ServiceStatus.active) { + return GeneralSecondaryButton( + label: 'Terminar servicio', + onPressed: () { + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add(UpdateServiceStatus( + widget.serviceId, ServiceStatus.completed)); + } + }); + } + + return GeneralSecondaryButton( + label: 'Volver', + onPressed: () { + Navigator.pop(context); + }); + // customStatusButton( + // label: 'Volver', + // onPressed: () { + // Navigator.pop(context); + // }, + // ); + } + + String formatCurrency(int number) { + final formatter = + NumberFormat.currency(locale: 'es_CO', decimalDigits: 0, symbol: ''); + return '\$${formatter.format(number)}'; + } + + Future> _getUserAndProfessionalInfo( + ServiceEntity service) async { + final userRepo = FirebaseUserRepository(FirebaseAuth.instance); + final userInfo = await userRepo.getMyUser(service.userId); + + return [userInfo]; + } +} diff --git a/lib/screens/service/service_screen.dart b/lib/screens/service/service_screen.dart index cd74766..11c62e3 100644 --- a/lib/screens/service/service_screen.dart +++ b/lib/screens/service/service_screen.dart @@ -6,17 +6,13 @@ import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:professional_repository/professional_repository.dart'; import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; -import 'package:prosappco/components/general_primary_button.dart'; import 'package:service_repository/service_repository.dart'; import 'package:setting_repository/setting_repository.dart'; import 'package:user_repository/user_repository.dart'; class ServiceScreen extends StatefulWidget { - // final String serviceId; - const ServiceScreen({ - super.key, - // required this.serviceId - }); + final String serviceId; + const ServiceScreen({Key? key, required this.serviceId}) : super(key: key); @override State createState() => _ServiceScreenState(); @@ -71,182 +67,217 @@ class _ServiceScreenState extends State { return Column( children: [ - ListTile( - leading: Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey.shade300, - shape: BoxShape.circle, - image: userInfo.picture == null - ? null - : DecorationImage( - image: NetworkImage(userInfo.picture!), - fit: BoxFit.contain, + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + ListTile( + leading: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey.shade300, + shape: BoxShape.circle, + image: userInfo.picture == null + ? null + : DecorationImage( + image: NetworkImage( + userInfo.picture!), + fit: BoxFit.contain, + ), ), - ), - child: userInfo.picture == null - ? Icon( - CupertinoIcons.person, - color: Colors.grey.shade400, - size: 40, - ) - : null, - ), - title: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${userInfo.name}', - style: const TextStyle( - fontWeight: FontWeight.bold), - ), - const SizedBox(width: 5), - Text( - '${DateFormat('dd MMMM', 'es').format(DateTime.parse(service.day))} - ${ScheduleEntity.getFormatTime(service.range1Hour1)}', - style: TextStyle( - color: Colors.grey[600], - ), - ), - ], - ), - subtitle: const Text('Rating: 5.0'), - ), - Container( - margin: const EdgeInsets.only( - left: 40, right: 40, top: 20, bottom: 20), - padding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 15), - 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( - children: [ - const Icon( - Icons.error_outline, - size: 27, - color: Colors.black54, - ), - const SizedBox(width: 15), - service.location == - ServiceLocationPreferences.delivery - ? const Text( - 'Servicio a su domicilio.', - style: TextStyle( - color: Colors.black, fontSize: 14), - ) - : const Text( - 'Servicio en sitio / consultorio', - style: TextStyle( - color: Colors.black, fontSize: 14), - ), - ], - ), - ), - Visibility( - visible: settings?.tarifas ?? false, - child: Column( - children: [ - Text( - formatCurrency( - int.tryParse(service.rate) ?? 0), - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 25), - ), - const Text('Tarifa de consulta'), - const SizedBox(height: 15), - const Text( - 'Metodos de pago', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - professionalInfo.paymentMethods.datafono || - professionalInfo.paymentMethods.nequi || - professionalInfo - .paymentMethods.transferencia - ? Wrap( - spacing: 8, - runSpacing: 8, - alignment: WrapAlignment.center, - children: [ - Visibility( - visible: professionalInfo - .paymentMethods.datafono, - child: const Chip( - label: Text('Datafono')), - ), - Visibility( - visible: professionalInfo - .paymentMethods.nequi, - child: const Chip( - label: Text('Nequi')), - ), - Visibility( - visible: professionalInfo - .paymentMethods.transferencia, - child: const Chip( - label: Text( - 'Transferencia Bancaria')), - ), - ], - ) - : const Text( - 'No hay metodos de pago registrados', - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 15, - color: Colors.black45, + child: userInfo.picture == null + ? Icon( + CupertinoIcons.person, + color: Colors.grey.shade400, + size: 40, + ) + : null, + ), + title: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${userInfo.name}', + style: const TextStyle( + fontWeight: FontWeight.bold), ), - ), - ], - ), - ), - ListTile( - leading: const Icon(Icons.near_me), - title: Text( - service.address, - style: TextStyle( - fontSize: 15, color: Colors.grey[600]), - ), - subtitle: service.aditionalAddress.isEmpty - ? null - : Text( - service.aditionalAddress, - style: TextStyle( - fontSize: 15, color: Colors.grey[600]), + const SizedBox(width: 5), + Text( + '${DateFormat('dd MMMM', 'es').format(DateTime.parse(service.day))} - ${ScheduleEntity.getFormatTime(service.range1Hour1)}', + style: TextStyle( + color: Colors.grey[600], + ), + ), + ], + ), + subtitle: const Text('Rating: 5.0'), ), - ), - service.description.isEmpty - ? const SizedBox() - : Container( - alignment: Alignment.center, - width: - MediaQuery.of(context).size.width * 0.8, - child: Text( - '"${service.description.trim()}"', - style: TextStyle( - color: Colors.grey[600], - fontStyle: FontStyle.italic, + Container( + margin: const EdgeInsets.only( + left: 40, + right: 40, + top: 20, + bottom: 20), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 15), + 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( + children: [ + const Icon( + Icons.error_outline, + size: 27, + color: Colors.black54, + ), + const SizedBox(width: 15), + service.location == + ServiceLocationPreferences + .delivery + ? const Text( + 'Servicio a s domicilio.', + style: TextStyle( + color: Colors.black, + fontSize: 14), + ) + : const Text( + 'Servicio en sitio / consultorio', + style: TextStyle( + color: Colors.black, + fontSize: 14), + ), + ], ), ), - ), - Expanded( - child: customMessageStatus(service), + Visibility( + visible: settings?.tarifas ?? false, + child: Column( + children: [ + Text( + formatCurrency( + int.tryParse(service.rate) ?? 0), + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 25), + ), + const Text('Tarifa de consulta'), + const SizedBox(height: 15), + const Text( + 'Metodos de pago', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + professionalInfo + .paymentMethods.datafono || + professionalInfo + .paymentMethods.nequi || + professionalInfo.paymentMethods + .transferencia + ? Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + Visibility( + visible: professionalInfo + .paymentMethods + .datafono, + child: const Chip( + label: + Text('Datafono')), + ), + Visibility( + visible: professionalInfo + .paymentMethods.nequi, + child: const Chip( + label: Text('Nequi')), + ), + Visibility( + visible: professionalInfo + .paymentMethods + .transferencia, + child: const Chip( + label: Text( + 'Transferencia Bancaria')), + ), + ], + ) + : const Text( + 'No hay metodos de pago registrados', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 15, + color: Colors.black45, + ), + ), + ], + ), + ), + ListTile( + leading: const Icon(Icons.near_me), + title: Text( + service.address, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600]), + ), + subtitle: service.aditionalAddress.isEmpty + ? null + : Text( + service.aditionalAddress, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600]), + ), + ), + service.description.isEmpty + ? const SizedBox() + : Container( + alignment: Alignment.center, + width: MediaQuery.of(context) + .size + .width * + 0.8, + child: Text( + '"${service.description.trim()}"', + style: TextStyle( + color: Colors.grey[600], + fontStyle: FontStyle.italic, + ), + ), + ), + customMessageStatus(service), + + // customButton(service, context), + const SizedBox(height: 20), + ], + ), + ), + ), + const Divider( + height: 1, + thickness: 0.5, + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + child: customButton(service, context), ), - customButton(service, context), - const SizedBox(height: 20), ], ); } @@ -254,8 +285,8 @@ class _ServiceScreenState extends State { }, ); } else { - // BlocProvider.of(context) - // .add(LoadService(widget.serviceId)); + BlocProvider.of(context) + .add(LoadService(widget.serviceId)); return const Center( child: CircularProgressIndicator(), ); @@ -341,31 +372,69 @@ class _ServiceScreenState extends State { ); } - GeneralPrimaryButton customButton( - ServiceEntity service, BuildContext context) { + ElevatedButton customButton(ServiceEntity service, BuildContext context) { if (service.status == ServiceStatus.pending) { - return GeneralPrimaryButton( + return ElevatedButton( onPressed: () { final currentState = context.read().state; if (currentState is ServiceLoaded) { - // context.read().add( - // UpdateServiceStatus( - // widget.serviceId, - // ServiceStatus.cancelled, - // ), - // ); + context.read().add( + UpdateServiceStatus( + widget.serviceId, + ServiceStatus.cancelled, + ), + ); } }, - color: Colors.red, - label: 'Cancelar Servicio', + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.error, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Container( + alignment: Alignment.center, + child: const Text( + 'Cancelar servicio', + style: TextStyle( + color: Colors.white, + fontSize: 18, + ), + ), + ), ); } - return GeneralPrimaryButton( + return ElevatedButton( onPressed: () { - Navigator.pop(context); + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add( + UpdateServiceStatus( + widget.serviceId, + ServiceStatus.cancelled, + ), + ); + } }, - label: 'Volver', + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primary, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Container( + alignment: Alignment.center, + child: const Text( + 'Volver', + style: TextStyle( + color: Colors.white, + fontSize: 18, + ), + ), + ), ); } @@ -378,12 +447,21 @@ class _ServiceScreenState extends State { Future> _getUserAndProfessionalInfo( ServiceEntity service) async { final userRepo = FirebaseUserRepository(FirebaseAuth.instance); - final userInfo = await userRepo.getMyUser(service.professionalId); - final professionalRepo = FirebaseProfessionalRepository(); - final professionalInfo = - await professionalRepo.getProInfo(service.professionalId); + if (FirebaseAuth.instance.currentUser!.uid == service.professionalId) { + final userInfo = await userRepo.getMyUser(service.userId); + final professionalInfo = + await professionalRepo.getProInfo(service.professionalId); - return [userInfo, professionalInfo]; + return [userInfo, professionalInfo]; + } else { + final userRepo = FirebaseUserRepository(FirebaseAuth.instance); + final userInfo = await userRepo.getMyUser(service.professionalId); + + final professionalInfo = + await professionalRepo.getProInfo(service.professionalId); + + return [userInfo, professionalInfo]; + } } } diff --git a/lib/screens/service/user_service_screen.dart b/lib/screens/service/user_service_screen.dart new file mode 100644 index 0000000..18dd0e5 --- /dev/null +++ b/lib/screens/service/user_service_screen.dart @@ -0,0 +1,566 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:injector/injector.dart'; +import 'package:intl/intl.dart'; +import 'package:professional_repository/professional_repository.dart'; +import 'package:prosappco/blocs/service_bloc/service_bloc.dart'; +import 'package:prosappco/components/general_secondary_button.dart'; +import 'package:service_repository/service_repository.dart'; +import 'package:setting_repository/setting_repository.dart'; +import 'package:user_repository/user_repository.dart'; + +class UserServiceScreen extends StatefulWidget { + final String serviceId; + const UserServiceScreen({super.key, required this.serviceId}); + + @override + State createState() => _UserServiceScreenState(); +} + +class _UserServiceScreenState extends State { + final settingRepository = Injector.appInstance.get(); + SettingEntity? settings; + + @override + void initState() { + super.initState(); + + _loadSettings(); + } + + void _loadSettings() { + settingRepository.getSettings().then( + (value) => setState(() { + settings = value; + }), + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => Injector.appInstance.get(), + child: Scaffold( + appBar: AppBar( + title: const Text('Servicio'), + ), + body: BlocBuilder( + builder: (context, state) { + if (state is ServiceLoaded) { + final service = state.service; + return FutureBuilder( + future: _getUserAndProfessionalInfo(service), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else { + if (snapshot.hasError) { + return Center( + child: Text('Error inesperado: ${snapshot.error}'), + ); + } else { + final userInfo = snapshot.data![0] as MyUser; + final professionalInfo = + snapshot.data![1] as ProfessionalEntity; + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + ListTile( + leading: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey.shade300, + shape: BoxShape.circle, + image: userInfo.picture == null + ? null + : DecorationImage( + image: NetworkImage( + userInfo.picture!, + ), + fit: BoxFit.contain, + ), + ), + child: userInfo.picture == null + ? Icon( + CupertinoIcons.person, + color: Colors.grey.shade400, + size: 40, + ) + : null, + ), + title: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${userInfo.name}', + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + const SizedBox(width: 5), + Text( + '${DateFormat('dd MMMM', 'es').format(DateTime.parse(service.day))} - ${ScheduleEntity.getFormatTime(service.range1Hour1)}', + style: TextStyle( + color: Colors.grey[600], + ), + ), + ], + ), + subtitle: const Text('Rating: 5.0'), + ), + Container( + margin: const EdgeInsets.only( + left: 40, + right: 40, + top: 20, + bottom: 20, + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 15, + ), + 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( + children: [ + const Icon( + Icons.error_outline, + size: 27, + color: Colors.black54, + ), + const SizedBox(width: 15), + service.location == + ServiceLocationPreferences + .delivery + ? const Text( + 'Servicio a tu domicilio.', + style: TextStyle( + color: Colors.black, + fontSize: 14, + ), + ) + : const Text( + 'Servicio en sitio / consultorio', + style: TextStyle( + color: Colors.black, + fontSize: 14, + ), + ), + ], + ), + ), + Visibility( + visible: settings?.tarifas ?? false, + child: Column( + children: [ + Text( + formatCurrency( + int.tryParse(service.rate) ?? 0), + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 25), + ), + const Text('Tarifa de consulta'), + const SizedBox(height: 15), + const Text( + 'Metodos de pago', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + professionalInfo + .paymentMethods.datafono || + professionalInfo + .paymentMethods.nequi || + professionalInfo.paymentMethods + .transferencia + ? Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: [ + Visibility( + visible: professionalInfo + .paymentMethods + .datafono, + child: const Chip( + label: + Text('Datafono')), + ), + Visibility( + visible: professionalInfo + .paymentMethods.nequi, + child: const Chip( + label: Text('Nequi')), + ), + Visibility( + visible: professionalInfo + .paymentMethods + .transferencia, + child: const Chip( + label: Text( + 'Transferencia Bancaria')), + ), + ], + ) + : const Text( + 'No hay metodos de pago registrados', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 15, + color: Colors.black45, + ), + ), + ], + ), + ), + ListTile( + leading: const Icon(Icons.near_me), + title: Text( + service.address, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600], + ), + ), + subtitle: service.aditionalAddress.isEmpty + ? null + : Text( + service.aditionalAddress, + style: TextStyle( + fontSize: 15, + color: Colors.grey[600], + ), + ), + ), + service.description.isEmpty + ? const SizedBox() + : Container( + alignment: Alignment.center, + width: MediaQuery.of(context) + .size + .width * + 0.8, + child: Text( + '"${service.description.trim()}"', + style: TextStyle( + color: Colors.grey[600], + fontStyle: FontStyle.italic, + ), + ), + ), + const SizedBox(height: 55), + customMessageStatus(service), + const SizedBox(height: 20), + ], + ), + ), + ), + const Divider( + height: 1, + thickness: 0.5, + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + child: customButton(service, context), + ), + ], + ); + } + } + }, + ); + } else { + BlocProvider.of(context) + .add(LoadService(widget.serviceId)); + return const Center(child: CircularProgressIndicator()); + } + }, + ), + ), + ); + } + + Widget customMessageStatus(ServiceEntity service) { + if (service.status == ServiceStatus.pending) { + 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: Text( + 'Servicio enviado', + 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.mark_email_read_rounded, + color: Colors.green, size: 48), + ), + ) + ], + ); + } + if (service.status == ServiceStatus.acepted) { + 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: Text( + 'Aceptado', + 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.check, 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 (service.status == ServiceStatus.active) { + 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: Text( + 'En proceso...', + 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.access_time_rounded, + color: Colors.green, + size: 48, + ), + ), + ) + ], + ); + } + if (service.status == ServiceStatus.completed) { + 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: 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, + ), + ), + ) + ], + ); + } + + return const SizedBox(); + } + + Widget customButton(ServiceEntity service, BuildContext context) { + if (service.status == ServiceStatus.pending) { + return GeneralSecondaryButton( + label: 'Cancelar servicio', + color: Theme.of(context).colorScheme.error, + onPressed: () { + final currentState = context.read().state; + if (currentState is ServiceLoaded) { + context.read().add( + UpdateServiceStatus(widget.serviceId, ServiceStatus.cancelled)); + } + }, + ); + } + // if (service.status == ServiceStatus.acepted) { + // return GeneralSecondaryButton( + // label: 'Iniciar servicio', + // onPressed: () { + // final currentState = context.read().state; + // if (currentState is ServiceLoaded) { + // context.read().add( + // UpdateServiceStatus(widget.serviceId, ServiceStatus.active)); + // } + // }, + // ); + // } + + // if (service.status == ServiceStatus.active) { + // return GeneralSecondaryButton( + // label: 'Terminar servicio', + // onPressed: () { + // final currentState = context.read().state; + // if (currentState is ServiceLoaded) { + // context.read().add(UpdateServiceStatus( + // widget.serviceId, ServiceStatus.completed)); + // } + // }); + // } + + return GeneralSecondaryButton( + label: 'Volver', + onPressed: () { + Navigator.pop(context); + }); + } + + String formatCurrency(int number) { + final formatter = + NumberFormat.currency(locale: 'es_CO', decimalDigits: 0, symbol: ''); + return '\$${formatter.format(number)}'; + } + + Future> _getUserAndProfessionalInfo( + ServiceEntity service) async { + final userRepo = FirebaseUserRepository(FirebaseAuth.instance); + final professionalRepo = FirebaseProfessionalRepository(); + + final userInfo = await userRepo.getMyUser(service.professionalId); + final professionalInfo = + await professionalRepo.getProInfo(service.professionalId); + + return [userInfo, professionalInfo]; + } +} diff --git a/lib/screens/user/user_service_screen.dart b/lib/screens/user/user_service_screen.dart index a2f216c..3a9df46 100644 --- a/lib/screens/user/user_service_screen.dart +++ b/lib/screens/user/user_service_screen.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -53,7 +55,8 @@ class _UserServiceScreenState extends State { final service = state.service; return FutureBuilder( future: _getUserAndProfessionalInfo(service), - builder: (BuildContext context, AsyncSnapshot> snapshot) { + builder: (BuildContext context, + AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else { @@ -372,12 +375,14 @@ class _UserServiceScreenState extends State { return '\$${formatter.format(number)}'; } - Future> _getUserAndProfessionalInfo(ServiceEntity service) async { + Future> _getUserAndProfessionalInfo( + ServiceEntity service) async { final userRepo = FirebaseUserRepository(FirebaseAuth.instance); final userInfo = await userRepo.getMyUser(service.professionalId); final professionalRepo = FirebaseProfessionalRepository(); - final professionalInfo = await professionalRepo.getProInfo(service.professionalId); + final professionalInfo = + await professionalRepo.getProInfo(service.professionalId); return [userInfo, professionalInfo]; } diff --git a/packages/service_repository/lib/src/entities/service_entity.dart b/packages/service_repository/lib/src/entities/service_entity.dart index 60dcc5a..3ef3d9b 100644 --- a/packages/service_repository/lib/src/entities/service_entity.dart +++ b/packages/service_repository/lib/src/entities/service_entity.dart @@ -4,6 +4,7 @@ import 'package:service_repository/service_repository.dart'; import 'package:flutter/material.dart'; class ServiceEntity extends Equatable { + final String? id; final String professionalId; final bool professionalScored; final String userId; @@ -22,6 +23,7 @@ class ServiceEntity extends Equatable { final ServiceLocationPreferences location; const ServiceEntity({ + this.id, required this.professionalId, required this.professionalScored, required this.userId, @@ -40,8 +42,9 @@ class ServiceEntity extends Equatable { required this.location, }); - static ServiceEntity fromDocument(Map doc) { + static ServiceEntity fromDocument(Map doc, String id) { return ServiceEntity( + id: id, professionalId: doc['professional_id'] as String, professionalScored: doc['professional_scored'] as bool, userId: doc['user_id'] as String, @@ -68,6 +71,7 @@ class ServiceEntity extends Equatable { Map toDocument() { return { + 'id': id, 'professional_id': professionalId, 'professional_scored': professionalScored, 'user_id': userId, @@ -95,7 +99,8 @@ class ServiceEntity extends Equatable { } @override - List get props => [ + List get props => [ + id, professionalId, professionalScored, userId, diff --git a/packages/service_repository/lib/src/models/service_status.dart b/packages/service_repository/lib/src/models/service_status.dart index db939a1..d022e3d 100644 --- a/packages/service_repository/lib/src/models/service_status.dart +++ b/packages/service_repository/lib/src/models/service_status.dart @@ -1,6 +1,13 @@ export 'service_status.dart'; -enum ServiceStatus { pending, acepted, active, cancelled, completed } +enum ServiceStatus { + pending, // 0 + acepted, // 1 + denied, // 2 + active, // 3 + cancelled, // 4 + completed, // 5 +} int enumToIntService(ServiceStatus state) { return state.index; diff --git a/packages/service_repository/lib/src/repositories/firebase_service_repository.dart b/packages/service_repository/lib/src/repositories/firebase_service_repository.dart index f330f98..feee3ac 100644 --- a/packages/service_repository/lib/src/repositories/firebase_service_repository.dart +++ b/packages/service_repository/lib/src/repositories/firebase_service_repository.dart @@ -21,7 +21,7 @@ class FirebaseServiceRepository { Stream getService(String serviceId) { return serviceCollection.doc(serviceId).snapshots().map((snapshot) { if (snapshot.exists) { - return ServiceEntity.fromDocument(snapshot.data()!); + return ServiceEntity.fromDocument(snapshot.data()!, snapshot.id); } else { throw Exception('El servicio con ID $serviceId no existe'); } @@ -31,10 +31,10 @@ class FirebaseServiceRepository { Stream> getServicesForUser(String userId) { return serviceCollection .where('user_id', isEqualTo: userId) - .where('status', whereIn: [0, 1, 2]) + .where('status', whereIn: [0, 1, 2, 3]) .snapshots() .map((querySnapshot) => querySnapshot.docs - .map((doc) => ServiceEntity.fromDocument(doc.data())) + .map((doc) => ServiceEntity.fromDocument(doc.data(), doc.id)) .toList()); } @@ -42,20 +42,20 @@ class FirebaseServiceRepository { String professionalId) { return serviceCollection .where('professional_id', isEqualTo: professionalId) - .where('status', whereIn: [0, 1, 2]) + .where('status', whereIn: [0, 1, 2, 3]) .snapshots() .map((querySnapshot) => querySnapshot.docs - .map((doc) => ServiceEntity.fromDocument(doc.data())) + .map((doc) => ServiceEntity.fromDocument(doc.data(), doc.id)) .toList()); } Stream> getServicesHistoryForUser(String userId) { return serviceCollection .where('user_id', isEqualTo: userId) - .where('status', whereIn: [3, 4]) + .where('status', whereIn: [4, 5]) .snapshots() .map((querySnapshot) => querySnapshot.docs - .map((doc) => ServiceEntity.fromDocument(doc.data())) + .map((doc) => ServiceEntity.fromDocument(doc.data(), doc.id)) .toList()); } @@ -63,10 +63,18 @@ class FirebaseServiceRepository { String professionalId) { return serviceCollection .where('professional_id', isEqualTo: professionalId) - .where('status', whereIn: [3, 4]) + .where('status', whereIn: [4, 5]) .snapshots() .map((querySnapshot) => querySnapshot.docs - .map((doc) => ServiceEntity.fromDocument(doc.data())) + .map((doc) => ServiceEntity.fromDocument(doc.data(), doc.id)) .toList()); } } + + + // 0 - pending + // 1 - acepted + // 2 - denied + // 3 - active + // 4 - cancelled + // 5 - completed \ No newline at end of file