diff --git a/lib/blocs/service_bloc/service_bloc.dart b/lib/blocs/service_bloc/service_bloc.dart index 3ba91e0..e909860 100644 --- a/lib/blocs/service_bloc/service_bloc.dart +++ b/lib/blocs/service_bloc/service_bloc.dart @@ -37,6 +37,8 @@ class ServiceBloc extends Bloc { _onLoadPendingServicesForProfessional); on(_onUpdateProfessionalScored); on(_onUpdateUserScored); + on( + _onCountPendingServicesForProfessional); } void _onCreateService(CreateService event, Emitter emit) async { @@ -297,6 +299,22 @@ class ServiceBloc extends Bloc { emit(CreateServiceFailure()); } } + + void _onCountPendingServicesForProfessional( + CountPendingServicesForProfessional event, + Emitter emit) async { + try { + final count = await _serviceRepository + .countPendingServicesForProfessional(event.professionalId); + + + + emit(PendingServicesCountedLoaded(count)); + } catch (e) { + log(e.toString()); + emit(CreateServiceFailure()); + } + } } class ServiceInfoUI { diff --git a/lib/blocs/service_bloc/service_event.dart b/lib/blocs/service_bloc/service_event.dart index e992fee..b2de913 100644 --- a/lib/blocs/service_bloc/service_event.dart +++ b/lib/blocs/service_bloc/service_event.dart @@ -98,6 +98,15 @@ class UpdateUserScored extends ServiceEvent { List get props => [serviceId]; } +class CountPendingServicesForProfessional extends ServiceEvent { + final String professionalId; + + const CountPendingServicesForProfessional(this.professionalId); + + @override + List get props => [professionalId]; +} + class CreateService extends ServiceEvent { final String professionalId; final bool? professionalScored; diff --git a/lib/blocs/service_bloc/service_state.dart b/lib/blocs/service_bloc/service_state.dart index c4c3777..43bee3a 100644 --- a/lib/blocs/service_bloc/service_state.dart +++ b/lib/blocs/service_bloc/service_state.dart @@ -1,6 +1,6 @@ part of 'service_bloc.dart'; -abstract class ServiceState extends Equatable { +class ServiceState extends Equatable { const ServiceState(); @override @@ -49,4 +49,13 @@ class ServiceStatusUpdated extends ServiceState { List get props => [newStatus]; } +class PendingServicesCountedLoaded extends ServiceState { + final int count; + + const PendingServicesCountedLoaded(this.count); + + @override + List get props => [count]; +} + class ScoredUpdated extends ServiceState {} diff --git a/lib/components/general_drawer.dart b/lib/components/general_drawer.dart index 803a07f..1e7fc2d 100644 --- a/lib/components/general_drawer.dart +++ b/lib/components/general_drawer.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -10,6 +11,7 @@ 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/blocs/service_bloc/service_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'; @@ -31,6 +33,7 @@ import 'package:prosappco/screens/professional/professional_services_screen.dart import 'package:prosappco/screens/profile/profile_screen.dart'; import 'package:prosappco/screens/user/user_history_services_screen.dart'; import 'package:prosappco/screens/web/web_view_screen.dart'; +import 'package:service_repository/service_repository.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:user_repository/user_repository.dart'; @@ -200,15 +203,53 @@ class GeneralDrawer extends StatelessWidget { color: const Color(0xFF2BA4EC), child: ListTile( onTap: () { - shouldProModeActive( - context, professionalState) - ? Navigator.pop(context) - : Navigator.pop(context); + Navigator.pop(context); }, - trailing: const Icon( - Icons.keyboard_arrow_right, - color: Colors.white, - ), + trailing: shouldProModeActive( + context, professionalState) + ? FutureBuilder( + builder: (context, + AsyncSnapshot snapshot) { + if (!snapshot.hasData || + snapshot.data! < 1) { + return const SizedBox(); + } + final int notificationCount = + snapshot.data!; + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: + BorderRadius.circular(12), + ), + child: Text( + notificationCount > 9 + ? '+9' + : notificationCount + .toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ); + }, + future: Injector.appInstance + .get() + .countPendingServicesForProfessional( + FirebaseAuth + .instance.currentUser!.uid), + ) + : const Icon( + Icons.keyboard_arrow_right, + color: Colors.white, + size: 25, + ), title: Text( shouldProModeActive( context, professionalState) @@ -257,8 +298,7 @@ class GeneralDrawer extends StatelessWidget { title: Row( children: [ RatingBar.builder( - // initialRating: calculoRating(average), - initialRating: 3, + initialRating: calculoRating(average), minRating: 1, direction: Axis.horizontal, allowHalfRating: true, @@ -340,81 +380,131 @@ class GeneralDrawer extends StatelessWidget { } buttonOfState(BuildContext context, ProfessionalState state) { - return ElevatedButton( - onPressed: () { - final myUserState = context.read().state; - if (myUserState.status == MyUserStatus.success) { - final user = myUserState.user!; + return Stack( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + child: ElevatedButton( + onPressed: () { + final myUserState = context.read().state; + if (myUserState.status == MyUserStatus.success) { + final user = myUserState.user!; - if (user.name != null && - user.email != null && - user.city != null && - user.phone != null) { - switch (user.proState) { - case ProState.active: - Navigator.pop(context); + if (user.name != null && + user.email != null && + user.city != null && + user.phone != null) { + switch (user.proState) { + case ProState.active: + Navigator.pop(context); - context - .read() - .add(const SwitchProModeEvent()); + context + .read() + .add(const SwitchProModeEvent()); - break; - case ProState.inactive: - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const ProfessionalFormScreen(), - ), - ); - break; - case ProState.pending: - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const ProfessionalPendingScreen(), - ), - ); - break; - case ProState.denied: - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const ProfessionalDeniedScreen(), - ), - ); - break; - } - } else { - ScaffoldMessenger.of(context).clearSnackBars(); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('Por favor, completa tu perfil'), - )); + break; + case ProState.inactive: + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const ProfessionalFormScreen(), + ), + ); + break; + case ProState.pending: + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + const ProfessionalPendingScreen(), + ), + ); + break; + case ProState.denied: + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + const ProfessionalDeniedScreen(), + ), + ); + break; + } + } else { + ScaffoldMessenger.of(context).clearSnackBars(); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('Por favor, completa tu perfil'), + )); - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const ProfileScreen(), + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const ProfileScreen(), + ), + ); + } + } else {} + }, + style: FilledButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primary, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), ), - ); - } - } else {} - }, - style: FilledButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.primary, - padding: const EdgeInsets.symmetric(vertical: 15), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - child: (state is LoadedModeProState) - ? Text( - state.isProModeActive ? 'Modo cliente' : 'Modo profesional', - style: const TextStyle(color: Colors.white, fontSize: 18), - ) - : const Text( - 'Modo profesional', - style: TextStyle(color: Colors.white, fontSize: 18), ), + child: (state is LoadedModeProState) + ? Text( + state.isProModeActive ? 'Modo cliente' : 'Modo profesional', + style: const TextStyle(color: Colors.white, fontSize: 18), + ) + : const Text( + 'Modo profesional', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + ), + (state is LoadedModeProState) + ? Visibility( + visible: !state.isProModeActive, + child: Positioned( + top: 0, + right: 0, + child: FutureBuilder( + builder: (context, AsyncSnapshot snapshot) { + if (!snapshot.hasData || snapshot.data! < 1) { + return const SizedBox(); + } + final int notificationCount = snapshot.data!; + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + notificationCount > 9 + ? '+9' + : notificationCount.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ); + }, + future: Injector.appInstance + .get() + .countPendingServicesForProfessional( + FirebaseAuth.instance.currentUser!.uid), + ), + ), + ) + : const SizedBox(), + ], ); } 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 80f9a40..d0a5cf9 100644 --- a/packages/service_repository/lib/src/repositories/firebase_service_repository.dart +++ b/packages/service_repository/lib/src/repositories/firebase_service_repository.dart @@ -91,8 +91,16 @@ class FirebaseServiceRepository { .toList()); } - // actualizar professionalScored a true + Future countPendingServicesForProfessional(String professionalId) async { + QuerySnapshot> query = await serviceCollection + .where('professional_id', isEqualTo: professionalId) + .where('status', isEqualTo: 0) + .get(); + return query.size; + } + + // actualizar professionalScored a true Future setProfessionalScored(String serviceId) { return serviceCollection .doc(serviceId)