From 278fdfd9e1dad66fc32d5f06c9de16d7a1992190 Mon Sep 17 00:00:00 2001 From: Felipe Date: Fri, 5 Jan 2024 15:57:46 -0500 Subject: [PATCH] update --- lib/src/components/drawer_professional.dart | 5 +- lib/src/components/schedule_picker.dart | 14 +- lib/src/models/professional_model.dart | 99 +++++++ .../presentation/screens/calendar_pro.dart | 264 ++++++++++++++++++ lib/src/presentation/screens/chat.dart | 2 +- lib/src/presentation/screens/horario.dart | 123 ++++++-- lib/src/presentation/screens/map/service.dart | 139 +++++---- .../presentation/screens/professional.dart | 109 +------- .../screens/professional_info.dart | 2 +- .../screens/profile/profile_pro.dart | 36 +-- .../screens/profile/profile_pro_web.dart | 34 +-- lib/src/presentation/screens/service_web.dart | 1 + lib/src/presentation/screens/web_view.dart | 2 +- lib/src/utils/time_of_day_extension.dart | 19 ++ lib/src/utils/time_of_day_utils.dart | 15 + pubspec.lock | 34 +-- 16 files changed, 647 insertions(+), 251 deletions(-) create mode 100644 lib/src/models/professional_model.dart create mode 100644 lib/src/presentation/screens/calendar_pro.dart create mode 100644 lib/src/utils/time_of_day_extension.dart create mode 100644 lib/src/utils/time_of_day_utils.dart diff --git a/lib/src/components/drawer_professional.dart b/lib/src/components/drawer_professional.dart index 4f8b5ad..b24940d 100644 --- a/lib/src/components/drawer_professional.dart +++ b/lib/src/components/drawer_professional.dart @@ -7,9 +7,7 @@ import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/presentation/screens/calendar.dart'; -import 'package:prosappco/src/presentation/screens/messages.dart'; import 'package:prosappco/src/presentation/screens/my_services_pro.dart'; -import 'package:prosappco/src/presentation/screens/professional.dart'; import 'package:prosappco/src/presentation/screens/profile/profile.dart'; import 'package:prosappco/src/presentation/screens/profile/profile_pro.dart'; import 'package:prosappco/src/presentation/screens/profile/profile_pro_web.dart'; @@ -31,8 +29,7 @@ class _DrawerProfessionalState extends State { ScoresModel? scoresModel; Future _irSugerencias() async { - const url = - 'https://admin.prosapp.co/sugerencias '; // Aquí debes poner la URL a la que quieres dirigirte + const url = 'https://admin.prosapp.co/sugerencias'; if (await canLaunch(url)) { await launch(url); } else { diff --git a/lib/src/components/schedule_picker.dart b/lib/src/components/schedule_picker.dart index ba32513..fb2cec8 100644 --- a/lib/src/components/schedule_picker.dart +++ b/lib/src/components/schedule_picker.dart @@ -199,13 +199,13 @@ class Schedule { } catch (e) { print('Error getting user: $e'); return { - "Lunes": Schedule(false, false, null, null, null, null), - "Martes": Schedule(false, false, null, null, null, null), - "Miercoles": Schedule(false, false, null, null, null, null), - "Jueves": Schedule(false, false, null, null, null, null), - "Viernes": Schedule(false, false, null, null, null, null), - "Sabado": Schedule(false, false, null, null, null, null), - "Domingo": Schedule(false, false, null, null, null, null), + "1": Schedule(false, false, null, null, null, null), + "2": Schedule(false, false, null, null, null, null), + "3": Schedule(false, false, null, null, null, null), + "4": Schedule(false, false, null, null, null, null), + "5": Schedule(false, false, null, null, null, null), + "6": Schedule(false, false, null, null, null, null), + "7": Schedule(false, false, null, null, null, null), }; } } diff --git a/lib/src/models/professional_model.dart b/lib/src/models/professional_model.dart new file mode 100644 index 0000000..2360791 --- /dev/null +++ b/lib/src/models/professional_model.dart @@ -0,0 +1,99 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_storage/firebase_storage.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/models/scores_model.dart'; + +class Professional { + final String id; + final Reference professionalRef; + final String name; + final String professionName; + final String cityName; + final String ubicacion; + final String realAddress; + final double latitude; + final double longitude; + final List professionalEspecializado; + final ScoresModel scores; + final int? tarifa; + final String? token; + + Professional({ + required this.id, + required this.professionalRef, + required this.name, + required this.professionName, + required this.cityName, + required this.ubicacion, + required this.professionalEspecializado, + required this.scores, + required this.realAddress, + required this.latitude, + required this.longitude, + this.tarifa, + this.token, + }); + + String getEspecializaciones() { + return professionalEspecializado.join(',\n'); + } + + @override + String toString() { + return 'Professional {\n' + ' professionalRef: $professionalRef,\n' + ' name: $name,\n' + ' professionName: $professionName,\n' + ' cityName: $cityName,\n' + ' ubicacion: $ubicacion,\n' + ' realAddress: $realAddress,\n' + ' latitude: $latitude,\n' + ' longitude: $longitude,\n' + ' professionalEspecializado: ${getEspecializaciones()}\n' + ' tarifa: $tarifa,\n' + ' token: $token,\n' + '}'; + } + + static Future getProfessional(String uid) async { + var photo = '...'; + final FirebaseStorage storage = FirebaseStorage.instance; + + try { + DocumentSnapshot user = + await FirebaseFirestore.instance.collection('users').doc(uid).get(); + + Map data = user.data() as Map; + + photo = await AuthenticationRepository.instance.getPhoto(user.id); + + if (data['estado'] == 'activo') { + List especializaciones; + + especializaciones = (data['especializaciones'] as List) + .map((e) => e.toString()) + .toList(); + + Professional professional = Professional( + id: user.id, + name: data['name'], + professionName: data['profesion'], + cityName: data['city'], + professionalRef: storage.ref().child(photo), + professionalEspecializado: especializaciones, + ubicacion: data['ubicacion'] ?? '', + realAddress: data['address'] ?? '', + latitude: data['latitude'] ?? 0, + longitude: data['longitude'] ?? 0, + scores: await ScoresModel.scoreFrom(uid, true, true), + tarifa: data['tarifas'] ?? 0, + token: data['token'] ?? '', + ); + return professional; + } + } catch (e) { + print('Error al obtener profesionales: $e'); + } + return null; + } +} diff --git a/lib/src/presentation/screens/calendar_pro.dart b/lib/src/presentation/screens/calendar_pro.dart new file mode 100644 index 0000000..41f5baa --- /dev/null +++ b/lib/src/presentation/screens/calendar_pro.dart @@ -0,0 +1,264 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/components/schedule_picker.dart'; +import 'package:prosappco/src/models/event_model.dart'; +import 'package:prosappco/src/models/professional_model.dart'; +import 'package:prosappco/src/presentation/screens/map/service.dart'; +import 'package:prosappco/src/utils/time_of_day_utils.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:intl/intl.dart'; + +class CalendarProScreen extends StatefulWidget { + final Professional professional; + + const CalendarProScreen({super.key, required this.professional}); + + @override + State createState() => _CalendarProScreenState(); +} + +class _CalendarProScreenState extends State { + final uid = AuthenticationRepository.instance.getCurrentUserUid(); + List? _events; + + EventoService eventoService = EventoService(); + CalendarFormat _calendarFormat = CalendarFormat.month; + + DateTime today = DateTime.now(); + DateTime now = DateTime.now(); + late int numDay; + + Map? _horarios; + + @override + void initState() { + super.initState(); + + if (_horarios == null) { + Schedule.getHorarios(widget.professional.id.toString()).then( + (Map data) { + setState(() { + _horarios = data; + }); + }, + ); + } + + today = DateTime.utc(today.year, today.month, today.day); + numDay = today.weekday; + + if (_events == null) { + Event.getEventsAllByIdStatus(uid ?? "", 'aprobado') + .then((value) => setState(() { + _events = value; + })); + } + } + + void _onDaySelected(DateTime day, DateTime focusedDay) { + setState(() { + today = day; + numDay = today.weekday; + }); + } + + void _onFormatChange(CalendarFormat format) { + setState(() { + _calendarFormat = format; + }); + } + + @override + Widget build(BuildContext context) { + if (_events == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + var events = _events!; + + DateTime lastDay = today.add(const Duration(days: 365)); + + return Scaffold( + floatingActionButtonLocation: kIsWeb + ? FloatingActionButtonLocation.startFloat + : FloatingActionButtonLocation.endFloat, + resizeToAvoidBottomInset: false, + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: 'Calendario', + ), + body: Column( + children: [ + Container( + color: const Color.fromARGB(255, 224, 247, 255), + child: TableCalendar( + locale: 'es_MX', + firstDay: DateTime.utc(2010, 10, 16), + lastDay: lastDay, + focusedDay: today, + availableGestures: AvailableGestures.all, + onDaySelected: _onDaySelected, + selectedDayPredicate: (day) => isSameDay(day, today), + calendarFormat: _calendarFormat, + onFormatChanged: _onFormatChange, + // eventLoader: (date) { + // return events + // .where((element) { + // DateTime day = DateTime.parse(element.day); + // return (date.year == day.year && + // date.month == day.month && + // date.day == day.day); + // }) + // .map((e) => e.description) + // .toList(); + // }, + availableCalendarFormats: const { + CalendarFormat.month: 'Mes', + CalendarFormat.week: 'Semana', + CalendarFormat.twoWeeks: '2 Semanas', + }, + ), + ), + SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), + child: Text(DateFormat('dd MMMM yyyy', 'es').format(today), + style: const TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w600, + )), + ), + ), + const Divider( + height: 0, + ), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 15), + child: Column( + children: [...rangesItems(_horarios?[numDay.toString()])], + ), + )) + ], + ), + ); + } + + List rangesItems(Schedule? schedule) { + if (schedule == null) { + return const [ + Padding( + padding: EdgeInsets.only(top: 20, left: 30, right: 30), + child: Text( + 'El profesional no acepta turnos este día', + style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500), + textAlign: TextAlign.center, + ), + ), + ]; + } + if (!schedule.habilitado) { + return const [ + Padding( + padding: EdgeInsets.only(top: 20, left: 30, right: 30), + child: Text( + 'El profesional no acepta turnos este día', + style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500), + textAlign: TextAlign.center, + ), + ) + ]; + } + if (schedule.jornadaContinua) { + List ranges = TimeOfDayUtils.genRanges( + schedule.range1Hour1!, + schedule.range2Hour2!, + ); + + return rangesItemsa(ranges); + } else { + List ranges1 = TimeOfDayUtils.genRanges( + schedule.range1Hour1!, + schedule.range1Hour2!, + ); + List ranges2 = TimeOfDayUtils.genRanges( + schedule.range2Hour1!, + schedule.range2Hour2!, + ); + + return [ + ...rangesItemsa(ranges1), + ...rangesItemsa(ranges2), + ]; + } + } + + List rangesItemsa(List ranges) { + return ranges + .map((time) => Card( + elevation: 4, + margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: ListTile( + onTap: () { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => ServiceScreen( + fechaSeleccionada: today, horaSeleccionada: time), + ), + (route) => false, // Elimina todas las rutas en la pila + ); + }, + contentPadding: const EdgeInsets.all(16), + leading: Container( + width: 40, + height: 40, + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Colors.blue, Colors.green], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + shape: BoxShape.circle, + ), + child: const Center( + child: Icon( + Icons.access_time, + color: Colors.white, + ), + ), + ), + title: Text( + time.format(context), + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.bold), + ), + subtitle: const Text( + 'Disponible', + style: TextStyle( + color: Colors.green, + fontSize: 13, + fontWeight: FontWeight.bold), + ), + trailing: const Icon( + Icons.arrow_forward_ios, + color: Colors.grey, + ), + ), + )) + .toList(); + } +} diff --git a/lib/src/presentation/screens/chat.dart b/lib/src/presentation/screens/chat.dart index 90c8520..8acd705 100644 --- a/lib/src/presentation/screens/chat.dart +++ b/lib/src/presentation/screens/chat.dart @@ -9,8 +9,8 @@ import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/models/chat_model.dart'; import 'package:prosappco/src/models/event_model.dart'; +import 'package:prosappco/src/models/professional_model.dart'; import 'package:prosappco/src/models/user_model.dart'; -import 'package:prosappco/src/presentation/screens/professional.dart'; import 'package:prosappco/src/presentation/screens/professional_info.dart'; import 'package:http/http.dart' as http; diff --git a/lib/src/presentation/screens/horario.dart b/lib/src/presentation/screens/horario.dart index 91e2d59..177ddb2 100644 --- a/lib/src/presentation/screens/horario.dart +++ b/lib/src/presentation/screens/horario.dart @@ -1,5 +1,6 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/components/primary_btn.dart'; @@ -22,22 +23,32 @@ class HorarioScreen extends StatelessWidget { Future updateHorario(BuildContext context) async { try { Map horariosMap = {}; + horarios.forEach((key, value) { + if (value.habilitado && !value.jornadaContinua) { + if (value.range1Hour1 == null || + value.range1Hour2 == null || + value.range2Hour1 == null || + value.range2Hour2 == null) { + value.habilitado = false; + value.jornadaContinua = false; + } + } + + if (value.habilitado && value.jornadaContinua) { + if (value.range1Hour1 == null || value.range2Hour2 == null) { + value.habilitado = false; + value.jornadaContinua = false; + } + } + horariosMap[key] = { 'habilitado': value.habilitado, 'jornadaContinua': value.jornadaContinua, - 'range1Hour1': value.range1Hour1 != null - ? value.range1Hour1!.format(context).toString() - : null, - 'range1Hour2': value.range1Hour2 != null - ? value.range1Hour2!.format(context).toString() - : null, - 'range2Hour1': value.range2Hour1 != null - ? value.range2Hour1!.format(context).toString() - : null, - 'range2Hour2': value.range2Hour2 != null - ? value.range2Hour2!.format(context).toString() - : null, + 'range1Hour1': formatTimeOfDay(value.range1Hour1), + 'range1Hour2': formatTimeOfDay(value.range1Hour2), + 'range2Hour1': formatTimeOfDay(value.range2Hour1), + 'range2Hour2': formatTimeOfDay(value.range2Hour2), }; }); @@ -49,27 +60,99 @@ class HorarioScreen extends StatelessWidget { } } + // Future updateHorario(BuildContext context) async { + // try { + // Map horariosMap = {}; + // horarios.forEach((key, value) { + // if (value.habilitado && !value.jornadaContinua) { + // if (value.range1Hour1 == null || + // value.range1Hour2 == null || + // value.range2Hour1 == null || + // value.range2Hour2 == null) { + // value.habilitado = false; + // value.jornadaContinua = false; + // return; + // } + // } + + // if (value.habilitado && value.jornadaContinua) { + // if (value.range1Hour1 == null || value.range2Hour2 == null) { + // value.habilitado = false; + // value.jornadaContinua = false; + // } + // } + + // horariosMap[key] = { + // 'habilitado': value.habilitado, + // 'jornadaContinua': value.jornadaContinua, + // 'range1Hour1': formatTimeOfDay(value.range1Hour1), + // 'range1Hour2': formatTimeOfDay(value.range1Hour2), + // 'range2Hour1': formatTimeOfDay(value.range2Hour1), + // 'range2Hour2': formatTimeOfDay(value.range2Hour2), + // }; + // }); + + // await FirebaseFirestore.instance.collection('users').doc(uid).update({ + // 'horario': horariosMap, + // }); + // } catch (e) { + // print('Error al actualizar el horario: $e'); + // } + // } + + String? formatTimeOfDay(TimeOfDay? time) { + if (time != null) { + final now = DateTime.now(); + final dateTime = + DateTime(now.year, now.month, now.day, time.hour, time.minute); + final format = DateFormat.jm(); + return format.format(dateTime); + } + return null; + } + int _dayOfWeekToInt(String dayOfWeek) { switch (dayOfWeek) { - case 'Lunes': + case '1': return 1; - case 'Martes': + case '2': return 2; - case 'Miercoles': + case '3': return 3; - case 'Jueves': + case '4': return 4; - case 'Viernes': + case '5': return 5; - case 'Sabado': + case '6': return 6; - case 'Domingo': + case '7': return 7; default: throw ArgumentError('Invalid day of week: $dayOfWeek'); } } + String _stringToDayOfWeek(String dayOfWeek) { + switch (dayOfWeek) { + case '1': + return 'Lunes'; + case '2': + return 'Martes'; + case '3': + return 'Miércoles'; + case '4': + return 'Jueves'; + case '5': + return 'Viernes'; + case '6': + return 'Sábado'; + case '7': + return 'Domingo'; + default: + throw ArgumentError('Invalid day of week: $dayOfWeek'); + } + } + @override Widget build(BuildContext context) { final sortedHorarios = Map.fromEntries( @@ -94,7 +177,7 @@ class HorarioScreen extends StatelessWidget { children: sortedHorarios.entries.map( (entry) { return SchedulePicker( - name: entry.key, + name: _stringToDayOfWeek(entry.key), schedule: entry.value, ); }, diff --git a/lib/src/presentation/screens/map/service.dart b/lib/src/presentation/screens/map/service.dart index d1ac8c1..b62d294 100644 --- a/lib/src/presentation/screens/map/service.dart +++ b/lib/src/presentation/screens/map/service.dart @@ -18,6 +18,7 @@ import 'package:prosappco/constansts.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/network_utility.dart'; import 'package:prosappco/src/models/event_model.dart'; +import 'package:prosappco/src/models/professional_model.dart'; import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/presentation/screens/professional.dart'; @@ -32,7 +33,11 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; class ServiceScreen extends StatefulWidget { - const ServiceScreen({super.key}); + final DateTime? fechaSeleccionada; + final TimeOfDay? horaSeleccionada; + + const ServiceScreen( + {super.key, this.fechaSeleccionada, this.horaSeleccionada}); @override State createState() => _ServiceScreenState(); @@ -100,6 +105,9 @@ class _ServiceScreenState extends State { _auth = FirebaseAuth.instance; + print('jurgo 1 ${widget.fechaSeleccionada}'); + print('jurgo 2 ${widget.horaSeleccionada}'); + final currentUser = _auth.currentUser; if (currentUser != null && currentUser.displayName != null) { @@ -611,64 +619,79 @@ class _ServiceScreenState extends State { }, ), ), - const SizedBox(height: 15), - Row( - children: [ - Expanded( - child: TextFormField( - readOnly: true, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.calendar_month), - suffixIcon: _selectedDate == null - ? const Icon(Icons.arrow_drop_down) - : null, - hintText: 'Fecha', - ), - controller: TextEditingController( - text: _selectedDate == null - ? '' - : formatter.format(_selectedDate!), - ), - onTap: () { - if (_profesionalController.text.isNotEmpty) { - _selectDateAndTime(context); - } else { - WarningSnackbar.show( - title: 'Selecciona un profesional', - message: - 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', - backgroundColor: Colors.orange, - ); - } - }, + widget.fechaSeleccionada == null && + widget.horaSeleccionada == null + ? const SizedBox() + : const SizedBox(height: 15), + widget.fechaSeleccionada == null && + widget.horaSeleccionada == null + ? const SizedBox() + : Row( + children: [ + Expanded( + child: TextFormField( + readOnly: true, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.calendar_month), + hintText: 'Fecha', + ), + // controller: TextEditingController( + // text: _selectedDate == null + // ? '' + // : formatter.format(_selectedDate!), + // ), + controller: TextEditingController( + text: widget.fechaSeleccionada == null + ? '' + : formatter + .format(widget.fechaSeleccionada!), + ), + // onTap: () { + // if (_profesionalController + // .text.isNotEmpty) { + // _selectDateAndTime(context); + // } else { + // WarningSnackbar.show( + // title: 'Selecciona un profesional', + // message: + // 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', + // backgroundColor: Colors.orange, + // ); + // } + // }, + ), + ), + Expanded( + child: TextFormField( + // onTap: () { + // if (_profesionalController.text.isNotEmpty) { + // _selectDateAndTime(context); + // } else { + // WarningSnackbar.show( + // title: 'Selecciona un profesional', + // message: + // 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', + // backgroundColor: Colors.orange); + // } + // }, + readOnly: true, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.watch_later_outlined), + hintText: 'Hora', + ), + // controller: TextEditingController( + // text: _selectedTime == null + // ? '' + // : ' ${_selectedTime!.format(context)}', + // ), + controller: TextEditingController( + text: widget.horaSeleccionada == null + ? '' + : ' ${widget.horaSeleccionada!.format(context)}', + ), + )) + ], ), - ), - Expanded( - child: TextFormField( - onTap: () { - if (_profesionalController.text.isNotEmpty) { - _selectDateAndTime(context); - } else { - WarningSnackbar.show( - title: 'Selecciona un profesional', - message: - 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', - backgroundColor: Colors.orange); - } - }, - readOnly: true, - decoration: const InputDecoration( - suffixIcon: Icon(Icons.arrow_drop_down), - hintText: 'Hora', - ), - controller: TextEditingController( - text: _selectedTime == null - ? '' - : ' ${_selectedTime!.format(context)}', - ), - )) - ], - ), const SizedBox(height: 15), TextFormField( controller: _observacionController, diff --git a/lib/src/presentation/screens/professional.dart b/lib/src/presentation/screens/professional.dart index 3fa9745..5387768 100644 --- a/lib/src/presentation/screens/professional.dart +++ b/lib/src/presentation/screens/professional.dart @@ -7,8 +7,10 @@ import 'package:intl/intl.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/models/professional_model.dart'; import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/models/user_model.dart'; +import 'package:prosappco/src/presentation/screens/calendar_pro.dart'; import 'package:prosappco/src/presentation/screens/professional_info.dart'; import 'package:prosappco/src/presentation/widgets/shared/loading_item_list.dart'; import '../../models/scores_model.dart'; @@ -27,101 +29,6 @@ final CollectionReference usersCollection = FirebaseFirestore.instance.collection('users'); var _photo = '...'; -class Professional { - final String id; - final Reference professionalRef; - final String name; - final String professionName; - final String cityName; - final String ubicacion; - final String realAddress; - final double latitude; - final double longitude; - final List professionalEspecializado; - final ScoresModel scores; - final int? tarifa; - final String? token; - - Professional({ - required this.id, - required this.professionalRef, - required this.name, - required this.professionName, - required this.cityName, - required this.ubicacion, - required this.professionalEspecializado, - required this.scores, - required this.realAddress, - required this.latitude, - required this.longitude, - this.tarifa, - this.token, - }); - - String getEspecializaciones() { - return professionalEspecializado.join(',\n'); - } - - @override - String toString() { - return 'Professional {\n' - ' professionalRef: $professionalRef,\n' - ' name: $name,\n' - ' professionName: $professionName,\n' - ' cityName: $cityName,\n' - ' ubicacion: $ubicacion,\n' - ' realAddress: $realAddress,\n' - ' latitude: $latitude,\n' - ' longitude: $longitude,\n' - ' professionalEspecializado: ${getEspecializaciones()}\n' - ' tarifa: $tarifa,\n' - ' token: $token,\n' - '}'; - } - - static Future getProfessional(String uid) async { - var photo = '...'; - final FirebaseStorage storage = FirebaseStorage.instance; - - try { - DocumentSnapshot user = - await FirebaseFirestore.instance.collection('users').doc(uid).get(); - - Map data = user.data() as Map; - - photo = await AuthenticationRepository.instance.getPhoto(user.id); - - if (data['estado'] == 'activo') { - List especializaciones; - - especializaciones = (data['especializaciones'] as List) - .map((e) => e.toString()) - .toList(); - - Professional professional = Professional( - id: user.id, - name: data['name'], - professionName: data['profesion'], - cityName: data['city'], - professionalRef: storage.ref().child(photo), - professionalEspecializado: especializaciones, - ubicacion: data['ubicacion'] ?? '', - realAddress: data['address'] ?? '', - latitude: data['latitude'] ?? 0, - longitude: data['longitude'] ?? 0, - scores: await ScoresModel.scoreFrom(uid, true, true), - tarifa: data['tarifas'] ?? 0, - token: data['token'] ?? '', - ); - return professional; - } - } catch (e) { - print('Error al obtener profesionales: $e'); - } - return null; - } -} - class _ProfessionalScreenState extends State { UserModel? userme; SettingModel? settings; @@ -480,8 +387,16 @@ class _ProfessionalScreenState extends State { }); } else if (professionals[index].ubicacion == 'sitio') { - Navigator.pop( - context, [professionals[index], 'sitio']); + // Navigator.pop(context, [professionals[index], 'sitio']); + + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return CalendarProScreen( + professional: professionals[index]); + }, + ), + ); } else { Navigator.pop( context, [professionals[index], 'domicilio']); diff --git a/lib/src/presentation/screens/professional_info.dart b/lib/src/presentation/screens/professional_info.dart index 46b2972..d33f87f 100644 --- a/lib/src/presentation/screens/professional_info.dart +++ b/lib/src/presentation/screens/professional_info.dart @@ -5,8 +5,8 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:intl/intl.dart'; import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/models/professional_model.dart'; import 'package:prosappco/src/models/setting_model.dart'; -import 'package:prosappco/src/presentation/screens/professional.dart'; import 'package:prosappco/src/presentation/screens/reputation.dart'; import '../../models/scores_model.dart'; diff --git a/lib/src/presentation/screens/profile/profile_pro.dart b/lib/src/presentation/screens/profile/profile_pro.dart index 0d137fd..dde8e6b 100644 --- a/lib/src/presentation/screens/profile/profile_pro.dart +++ b/lib/src/presentation/screens/profile/profile_pro.dart @@ -65,7 +65,7 @@ class _ProfileProScreenState extends State { super.initState(); if (settings == null) { SettingModel.getSettings().then((SettingModel value) => setState( - () => {print('Settings: $value'), settings = value}, + () => settings = value, )); } @@ -149,7 +149,7 @@ class _ProfileProScreenState extends State { void createSchedules() async { if (_horarios == null || _horarios!.isEmpty) { final defaultSchedule = { - 'Lunes': { + '1': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -157,7 +157,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Martes': { + '2': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -165,7 +165,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Miercoles': { + '3': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -173,7 +173,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Jueves': { + '4': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -181,7 +181,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Viernes': { + '5': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -189,7 +189,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Sabado': { + '6': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -197,7 +197,7 @@ class _ProfileProScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Domingo': { + '7': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -642,7 +642,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: Text(timeList(_horarios?['Lunes'], context)), + child: Text(timeList(_horarios?['1'], context)), ), ), ], @@ -658,8 +658,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Martes'], context)), + child: Text(timeList(_horarios?['2'], context)), ), ), ], @@ -675,8 +674,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: Text( - timeList(_horarios?['Miercoles'], context)), + child: Text(timeList(_horarios?['3'], context)), ), ), ], @@ -692,8 +690,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Jueves'], context)), + child: Text(timeList(_horarios?['4'], context)), ), ), ], @@ -709,8 +706,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Viernes'], context)), + child: Text(timeList(_horarios?['5'], context)), ), ), ], @@ -726,8 +722,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Sabado'], context)), + child: Text(timeList(_horarios?['6'], context)), ), ), ], @@ -743,8 +738,7 @@ class _ProfileProScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Domingo'], context)), + child: Text(timeList(_horarios?['7'], context)), ), ), ], diff --git a/lib/src/presentation/screens/profile/profile_pro_web.dart b/lib/src/presentation/screens/profile/profile_pro_web.dart index f890a43..f1ce504 100644 --- a/lib/src/presentation/screens/profile/profile_pro_web.dart +++ b/lib/src/presentation/screens/profile/profile_pro_web.dart @@ -251,7 +251,7 @@ class _ProfileProWebScreenState extends State { void createSchedules() async { if (_horarios == null || _horarios!.isEmpty) { final defaultSchedule = { - 'Lunes': { + '1': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -259,7 +259,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Martes': { + '2': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -267,7 +267,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Miercoles': { + '3': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -275,7 +275,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Jueves': { + '4': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -283,7 +283,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Viernes': { + '5': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -291,7 +291,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Sabado': { + '6': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -299,7 +299,7 @@ class _ProfileProWebScreenState extends State { 'range2Hour1': null, 'range2Hour2': null }, - 'Domingo': { + '7': { 'habilitado': false, 'jornadaContinua': false, 'range1Hour1': null, @@ -513,7 +513,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: Text(timeList(_horarios?['Lunes'], context)), + child: Text(timeList(_horarios?['1'], context)), ), ), ], @@ -529,8 +529,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Martes'], context)), + child: Text(timeList(_horarios?['2'], context)), ), ), ], @@ -546,8 +545,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: Text( - timeList(_horarios?['Miercoles'], context)), + child: Text(timeList(_horarios?['3'], context)), ), ), ], @@ -563,8 +561,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Jueves'], context)), + child: Text(timeList(_horarios?['4'], context)), ), ), ], @@ -580,8 +577,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Viernes'], context)), + child: Text(timeList(_horarios?['5'], context)), ), ), ], @@ -597,8 +593,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Sabado'], context)), + child: Text(timeList(_horarios?['6'], context)), ), ), ], @@ -614,8 +609,7 @@ class _ProfileProWebScreenState extends State { TableCell( child: Container( padding: const EdgeInsets.all(8.0), - child: - Text(timeList(_horarios?['Domingo'], context)), + child: Text(timeList(_horarios?['7'], context)), ), ), ], diff --git a/lib/src/presentation/screens/service_web.dart b/lib/src/presentation/screens/service_web.dart index a8ed3ea..12fd9f5 100644 --- a/lib/src/presentation/screens/service_web.dart +++ b/lib/src/presentation/screens/service_web.dart @@ -8,6 +8,7 @@ import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/models/professional_model.dart'; import 'package:prosappco/src/presentation/screens/profile/profile.dart'; import 'package:prosappco/src/presentation/widgets/shared/drawer_menu.dart'; import 'package:prosappco/src/models/event_model.dart'; diff --git a/lib/src/presentation/screens/web_view.dart b/lib/src/presentation/screens/web_view.dart index dabae38..d0cd6de 100644 --- a/lib/src/presentation/screens/web_view.dart +++ b/lib/src/presentation/screens/web_view.dart @@ -38,7 +38,7 @@ class _WebViewScreenState extends State { }, onWebResourceError: (WebResourceError error) {}, onNavigationRequest: (NavigationRequest request) { - if (request.url.startsWith('https://www.youtube.com/')) { + if (request.url.startsWith('https://www.google.com/')) { return NavigationDecision.prevent; } return NavigationDecision.navigate; diff --git a/lib/src/utils/time_of_day_extension.dart b/lib/src/utils/time_of_day_extension.dart new file mode 100644 index 0000000..a631b51 --- /dev/null +++ b/lib/src/utils/time_of_day_extension.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +extension TimeOfDayExtension on TimeOfDay { + TimeOfDay add({int hour = 0, int minute = 0}) { + return replacing(hour: this.hour + hour, minute: this.minute + minute); + } + + int compareTo(TimeOfDay other) { + if (hour < other.hour) return -1; + if (hour > other.hour) return 1; + if (minute < other.minute) return -1; + if (minute > other.minute) return 1; + return 0; + } + + bool isBefore(TimeOfDay other) { + return compareTo(other) == -1; + } +} diff --git a/lib/src/utils/time_of_day_utils.dart b/lib/src/utils/time_of_day_utils.dart new file mode 100644 index 0000000..d4ce6e9 --- /dev/null +++ b/lib/src/utils/time_of_day_utils.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:prosappco/src/utils/time_of_day_extension.dart'; + +class TimeOfDayUtils { + static List genRanges(TimeOfDay timeStart, TimeOfDay timeEnd) { + List ranges = []; + TimeOfDay current = timeStart; + while (current.isBefore(timeEnd)) { + ranges.add(current); + // Sumar 2 horas al objeto DateTime + current = current.add(hour: 2); + } + return ranges; + } +} diff --git a/pubspec.lock b/pubspec.lock index 841391a..f1f7255 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.17.1" community_material_icon: dependency: "direct main" description: @@ -745,10 +745,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.18.0" intl_phone_field: dependency: "direct main" description: @@ -809,18 +809,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.2.0" meta: dependency: transitive description: @@ -1062,10 +1062,10 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" stack_trace: dependency: transitive description: @@ -1118,10 +1118,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.5.1" timezone: dependency: transitive description: @@ -1242,14 +1242,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" webview_flutter: dependency: "direct main" description: @@ -1315,5 +1307,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.0.0 <4.0.0" flutter: ">=3.10.0"