diff --git a/images/pro_marke.png b/images/pro_marke.png new file mode 100644 index 0000000..5d65a9b Binary files /dev/null and b/images/pro_marke.png differ diff --git a/lib/main.dart b/lib/main.dart index 68f07f3..0db13c9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,10 +8,11 @@ import 'package:prosappco/src/screens/city.dart'; import 'package:prosappco/src/screens/login.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:prosappco/src/screens/login_email.dart'; +import 'package:prosappco/src/screens/my_services.dart'; +import 'package:prosappco/src/screens/my_services_pro.dart'; import 'package:prosappco/src/screens/new_number.dart'; import 'package:prosappco/src/screens/new_password.dart'; import 'package:prosappco/src/screens/profession.dart'; -import 'package:prosappco/src/screens/professional.dart'; import 'package:prosappco/src/screens/professional_profile.dart'; import 'package:prosappco/src/screens/professional_revision.dart'; import 'package:prosappco/src/screens/profile.dart'; @@ -63,6 +64,8 @@ class MyApp extends StatelessWidget { '/profilePro': (context) => const ProfilePro(), '/calendar': (context) => const CalendarScreen(), '/solicitud': (context) => SolicitudScreen(), + '/misserviciospro': (context) => MyServicesProScreen(), + '/misservicios': (context) => MyServicesScreen(), }, onGenerateRoute: (settings) { throw Exception('Ruta desconocida: ${settings.name}'); diff --git a/lib/src/components/drawer_menu.dart b/lib/src/components/drawer_menu.dart index 1a5353e..c7ebd4f 100644 --- a/lib/src/components/drawer_menu.dart +++ b/lib/src/components/drawer_menu.dart @@ -7,7 +7,6 @@ import 'package:prosappco/src/components/photo_view.dart'; import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/screens/profile.dart'; -import 'package:prosappco/src/screens/solicitudes.dart'; class DrawerMenu extends StatefulWidget { @override @@ -106,7 +105,14 @@ class _DrawerMenuState extends State { child: Column( children: [ ListTile( - onTap: () {}, + onTap: () { + if (ModalRoute.of(context)?.settings.name != + '/misservicios') { + Navigator.pushNamed(context, '/misservicios'); + } else { + Scaffold.of(context).openEndDrawer(); + } + }, leading: const Icon( Icons.history, color: Colors.black, diff --git a/lib/src/components/drawer_professional.dart b/lib/src/components/drawer_professional.dart index af4d0c2..e8288f9 100644 --- a/lib/src/components/drawer_professional.dart +++ b/lib/src/components/drawer_professional.dart @@ -112,7 +112,14 @@ class _DrawerProfessionalState extends State { child: Column( children: [ ListTile( - onTap: () {}, + onTap: () { + if (ModalRoute.of(context)?.settings.name != + '/misserviciospro') { + Navigator.pushNamed(context, '/misserviciospro'); + } else { + Scaffold.of(context).openEndDrawer(); + } + }, leading: const Icon( Icons.history, color: Colors.black, diff --git a/lib/src/models/chat_model.dart b/lib/src/models/chat_model.dart new file mode 100644 index 0000000..751d512 --- /dev/null +++ b/lib/src/models/chat_model.dart @@ -0,0 +1,37 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +class ChatModel { + List messages; + + ChatModel({required this.messages}); + + static ChatModel fromDocumentSnapshot( + DocumentSnapshot> snapshot) { + try { + List messages = []; + List messagesData = snapshot.get('message') ?? []; + + for (var data in messagesData) { + messages.add(MessageModel( + user: data['user'] ?? '', + content: data['content'] ?? '', + timestamp: (data['timestamp'] as Timestamp).toDate(), + )); + } + + return ChatModel(messages: messages); + } catch (e) { + print('error $e'); + return ChatModel(messages: []); + } + } +} + +class MessageModel { + String user; + String content; + DateTime timestamp; + + MessageModel( + {required this.user, required this.content, required this.timestamp}); +} diff --git a/lib/src/models/event_model.dart b/lib/src/models/event_model.dart index c2ced35..4df3ee5 100644 --- a/lib/src/models/event_model.dart +++ b/lib/src/models/event_model.dart @@ -16,6 +16,7 @@ class EventoService { String address, double latitude, double longitude, + String status, ) async { try { DateTime ahora = DateTime.now(); @@ -33,6 +34,7 @@ class EventoService { 'address': address, 'latitude': latitude, 'longitude': longitude, + 'status': status, 'Timestamp': ahora }).then((value) { FirebaseFirestore.instance.collection('users').doc(uid).update({ @@ -72,17 +74,18 @@ Future> getByProId(String day) async { } } -Future> getByProIdAll() async { +Future> getByProIdAll(String state1, String state2) async { try { var snapshot = await FirebaseFirestore.instance .collection('services') .where('professional_id', isEqualTo: uid) - .get(); + .where('status', whereIn: [state1, state2]).get(); List eventos = []; for (var element in snapshot.docs) { final event = Event.fromJson(element.data()); event.scoresModel = await ScoresModel.scoreTo(event.userId, false, false); + event.id = element.id; eventos.add(event); } print('eventos $eventos'); @@ -94,6 +97,7 @@ Future> getByProIdAll() async { } class Event { + String? id; String title; String? description; String day; @@ -105,9 +109,11 @@ class Event { String? address; double? longitud; double? latitud; + String status; ScoresModel? scoresModel; Event({ + this.id, required this.title, this.description, required this.day, @@ -119,10 +125,12 @@ class Event { this.address, this.longitud, this.latitud, + this.status = 'pendiente', }); factory Event.fromJson(Map json) { return Event( + id: json['id'] ?? '', title: json['title'], description: json['description'], day: json['day'], @@ -134,6 +142,7 @@ class Event { address: json['address'] ?? '', longitud: json['longitude'] ?? 0, latitud: json['latitude'] ?? 0, + status: json['status'], ); } @@ -170,4 +179,25 @@ class Event { return []; } } + + static Future> getEventsAllByIdStatus( + String uid, String state) async { + try { + var snapshot = await FirebaseFirestore.instance + .collection('services') + .where('professional_id', isEqualTo: uid) + .where('status', isEqualTo: state) + .get(); + + List eventos = []; + for (var element in snapshot.docs) { + eventos.add(Event.fromJson(element.data())); + } + print('eventos $eventos'); + return eventos; + } catch (e) { + print('Error getByProId $e'); + return []; + } + } } diff --git a/lib/src/models/setting_model.dart b/lib/src/models/setting_model.dart new file mode 100644 index 0000000..f4699cf --- /dev/null +++ b/lib/src/models/setting_model.dart @@ -0,0 +1,33 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; + +class SettingModel { + final bool domicilios; + + SettingModel(this.domicilios); + + static Future fromJson(Map json) async { + try { + if (json == null) return SettingModel(false); + + return SettingModel(json['habilitado']); + } catch (e) { + print('Error settings: $e'); + return SettingModel(false); + } + } + + static Future getDomiciliosSettings() async { + try { + final DocumentSnapshot> snapshot = + await FirebaseFirestore.instance + .collection('settings') + .doc('domicilios') + .get(); + final Map? data = snapshot.data(); + return fromJson(data!); + } catch (e) { + print('Error getting settings: $e'); + return SettingModel(false); + } + } +} diff --git a/lib/src/screens/calendar.dart b/lib/src/screens/calendar.dart index 093b450..38b480e 100644 --- a/lib/src/screens/calendar.dart +++ b/lib/src/screens/calendar.dart @@ -61,9 +61,10 @@ class _CalendarScreenState extends State { super.initState(); if (_events == null) { - Event.getEventsAllById(uid ?? "").then((value) => setState(() { - _events = value; - })); + Event.getEventsAllByIdStatus(uid ?? "", 'aprobado') + .then((value) => setState(() { + _events = value; + })); } } @@ -293,14 +294,16 @@ class _CalendarScreenState extends State { '', '', 0, - 0) + 0, + 'aprobado') .then((value) { Navigator.pop(context); _titleController.text = ''; _descriptionController.text = ''; }); - Event.getEventsAllById(uid ?? "").then( + Event.getEventsAllByIdStatus(uid ?? "", 'aprobado') + .then( (value) => setState(() { _events = value; }), diff --git a/lib/src/screens/chat.dart b/lib/src/screens/chat.dart new file mode 100644 index 0000000..c470469 --- /dev/null +++ b/lib/src/screens/chat.dart @@ -0,0 +1,109 @@ +import 'package:cloud_firestore/cloud_firestore.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/models/chat_model.dart'; + +class ChatScreen extends StatefulWidget { + final String eventoId; + const ChatScreen({super.key, required this.eventoId}); + + @override + State createState() => _ChatScreenState(); +} + +class _ChatScreenState extends State { + final _textController = TextEditingController(); + final uid = AuthenticationRepository.instance.getCurrentUserUid(); + + @override + Widget build(BuildContext context) { + String textoIngresado = _textController.text; + return Scaffold( + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: 'Mensajes'), + body: Column( + children: [ + StreamBuilder( + stream: FirebaseFirestore.instance + .collection('chats') + .doc(widget.eventoId) + .snapshots(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const Center(child: CircularProgressIndicator()); + } + + final data = snapshot.data!; + final chat = ChatModel.fromDocumentSnapshot(data); + + print('messages ${chat.messages}'); + + return Column(children: [ + ...chat.messages.map( + (e) => ListTile( + title: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${e.content}, ', + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + // TextSpan( + // text: DateFormat('dd MMM', 'es') + // .format(DateTime.parse(e.day)), + // style: const TextStyle( + // color: Colors.grey, + // fontSize: 16, + // ), + // ), + ], + ), + ), + ), + ) + ]); + + // ListTile( + // title: Text('${}'), + // ); + }, + ), + TextFormField( + controller: _textController, + ), + IconButton( + onPressed: () async { + final nuevoMensaje = MessageModel( + user: uid!, + content: _textController.text, + timestamp: DateTime.now()); + + final nuevoMensajeMap = { + 'user': nuevoMensaje.user, + 'content': nuevoMensaje.content, + 'timestamp': nuevoMensaje.timestamp, + }; + + FirebaseFirestore.instance + .collection('chats') + .doc(widget.eventoId) + .update({ + 'message': FieldValue.arrayUnion([nuevoMensajeMap]) + }); + + _textController.clear(); + }, + icon: const Icon(Icons.send)) + ], + ), + ); + } +} diff --git a/lib/src/screens/cita.dart b/lib/src/screens/cita.dart index 2ebb463..a00968d 100644 --- a/lib/src/screens/cita.dart +++ b/lib/src/screens/cita.dart @@ -1,5 +1,7 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:intl/intl.dart'; @@ -8,6 +10,7 @@ import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/models/event_model.dart'; import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/user_model.dart'; +import 'package:prosappco/src/screens/chat.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:community_material_icon/community_material_icon.dart'; @@ -213,6 +216,44 @@ class _CitaScreenState extends State { ), ), const SizedBox(width: 20), + ElevatedButton( + onPressed: () async { + await FirebaseFirestore.instance + .collection('chats') + .doc(widget.evento.id) + .set({}); + + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return ChatScreen(eventoId: widget.evento.id!); + }, + ), + ); + }, + style: ElevatedButton.styleFrom( + foregroundColor: const Color(0xFF2BA4EC), + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + side: const BorderSide( + color: Color(0xFF2BA4EC), + width: 2, + ), + ), + ), + child: const Padding( + padding: + EdgeInsets.symmetric(vertical: 18, horizontal: 0), + child: Icon( + Icons.message, + size: 30, + color: Color(0xFF2BA4EC), + ), + ), + ), + const SizedBox(width: 20), ElevatedButton( onPressed: () { _sendWhatsapp(); @@ -280,32 +321,76 @@ class _CitaScreenState extends State { child: Text('${widget.evento.address}')) ], ), - ) + ), ], ), ), - Padding( - padding: const EdgeInsets.only(bottom: 30), - child: ElevatedButton( - onPressed: () {}, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFEC2B2B), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - elevation: 0, - minimumSize: const Size(230, 60), - ), - child: const Text( - 'Cancelar servicio', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ), - ), + widget.evento.status == 'pendiendo' + ? Padding( + padding: const EdgeInsets.only(bottom: 30), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 20), + child: ElevatedButton( + onPressed: () { + FirebaseFirestore.instance + .collection("services") + .doc('${widget.evento.id}') + .update({"status": "aprobado"}).then((value) { + Navigator.pushReplacementNamed( + context, '/solicitud'); + }); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF2BA4EC), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + elevation: 0, + minimumSize: const Size(230, 60), + ), + child: const Text( + 'Aceptar', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + ), + ElevatedButton( + onPressed: () { + FirebaseFirestore.instance + .collection("services") + .doc('${widget.evento.id}') + .update({"status": "denegado"}).then((value) { + Navigator.pushReplacementNamed( + context, '/solicitud'); + }); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFEC2B2B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + elevation: 0, + minimumSize: const Size(230, 60), + ), + child: const Text( + 'Cancelar servicio', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + ], + ), + ) + : const SizedBox(), ], ), ); diff --git a/lib/src/screens/my_services.dart b/lib/src/screens/my_services.dart new file mode 100644 index 0000000..3b94771 --- /dev/null +++ b/lib/src/screens/my_services.dart @@ -0,0 +1,151 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:intl/intl.dart'; +import 'package:prosappco/src/components/drawer_professional.dart'; +import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/models/event_model.dart'; +import 'package:prosappco/src/screens/cita.dart'; + +class MyServicesScreen extends StatefulWidget { + MyServicesScreen({super.key}); + + @override + State createState() => _MyServicesScreenState(); +} + +class _MyServicesScreenState extends State { + DateTime today = DateTime.now(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: 'Mis servicios'), + drawer: DrawerProfessional(), + body: SingleChildScrollView( + child: Column( + children: [ + _eventList(), + ], + ), + ), + ), + ); + } + + Widget _eventList() { + return FutureBuilder( + future: getByProIdAll('aprobado', 'denegado'), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator(), + ); + } + + List eventos = []; + + try { + eventos.addAll(snapshot.data!); + } catch (e) { + print("Error" + e.toString()); + } + + if (eventos.isEmpty) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 50), + child: Center(child: Text('No tienes citas')), + ); + } + return Column( + children: [ + ...eventos.map( + (event) => ListTile( + tileColor: event.status == 'aprobado' + ? Colors.green[100] + : Colors.red[100], + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return CitaScreen(evento: event); + }, + ), + ); + }, + leading: Text(event.range1Hour1), + title: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${event.title}, ', + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + TextSpan( + text: DateFormat('dd MMM', 'es') + .format(DateTime.parse(event.day)), + style: const TextStyle( + color: Colors.grey, + fontSize: 16, + ), + ), + ], + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + RatingBar.builder( + initialRating: event.scoresModel?.average ?? 0, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: true, + itemCount: 5, + itemSize: 25, + maxRating: 5, + itemPadding: + const EdgeInsets.symmetric(horizontal: 0), + itemBuilder: (context, _) => const Icon( + Icons.star, + color: Color(0xFF2BA4EC), + ), + onRatingUpdate: (rating) {}, + ignoreGestures: true, + ), + const SizedBox(width: 5), + Text( + '(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'), + ], + ), + Text( + '" ${event.description}"', + style: const TextStyle(fontStyle: FontStyle.italic), + ), + ], + ), + trailing: const Icon(Icons.keyboard_arrow_right), + ), + ), + ], + ); + }, + ); + } +} diff --git a/lib/src/screens/my_services_pro.dart b/lib/src/screens/my_services_pro.dart new file mode 100644 index 0000000..392af9d --- /dev/null +++ b/lib/src/screens/my_services_pro.dart @@ -0,0 +1,161 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:intl/intl.dart'; +import 'package:prosappco/src/components/drawer_professional.dart'; +import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/src/models/event_model.dart'; +import 'package:prosappco/src/screens/cita.dart'; + +class MyServicesProScreen extends StatefulWidget { + MyServicesProScreen({super.key}); + + @override + State createState() => _MyServicesProScreenState(); +} + +class _MyServicesProScreenState extends State { + DateTime today = DateTime.now(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + appBar: PopAppbar( + onPressed: () { + Navigator.pop(context); + }, + label: 'Mis servicios'), + drawer: DrawerProfessional(), + body: SingleChildScrollView( + child: Column( + children: [ + _eventList(), + ], + ), + ), + ), + ); + } + + Widget _eventList() { + return FutureBuilder( + future: getByProIdAll('aprobado', 'denegado'), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator(), + ); + } + + List eventos = []; + + try { + eventos.addAll(snapshot.data!); + } catch (e) { + print("Error" + e.toString()); + } + + if (eventos.isEmpty) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 50), + child: Center(child: Text('No tienes citas')), + ); + } + return Column( + children: [ + ...eventos.map( + (event) => ListTile( + tileColor: event.status == 'aprobado' + ? Colors.blue[100] + : Colors.red[100], + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return CitaScreen(evento: event); + }, + ), + ); + }, + leading: event.status == 'aprobado' + ? const Icon( + Icons.check, + color: Colors.blue, + size: 40, + ) + : const Icon( + Icons.close, + color: Colors.red, + size: 40, + ), + title: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${event.title}, ', + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + TextSpan( + text: + '${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${event.range1Hour1}', + style: const TextStyle( + color: Colors.grey, + fontSize: 16, + ), + ), + ], + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + RatingBar.builder( + initialRating: event.scoresModel?.average ?? 0, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: true, + itemCount: 5, + itemSize: 25, + maxRating: 5, + itemPadding: + const EdgeInsets.symmetric(horizontal: 0), + itemBuilder: (context, _) => const Icon( + Icons.star, + color: Color(0xFF2BA4EC), + ), + onRatingUpdate: (rating) {}, + ignoreGestures: true, + ), + const SizedBox(width: 5), + Text( + '(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'), + ], + ), + Text( + '" ${event.description}"', + style: const TextStyle(fontStyle: FontStyle.italic), + ), + ], + ), + trailing: const Icon(Icons.keyboard_arrow_right), + ), + ), + ], + ); + }, + ); + } +} diff --git a/lib/src/screens/professional.dart b/lib/src/screens/professional.dart index d93f25c..cff9935 100644 --- a/lib/src/screens/professional.dart +++ b/lib/src/screens/professional.dart @@ -3,7 +3,6 @@ import 'package:diacritic/diacritic.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.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'; @@ -171,28 +170,30 @@ class _ProfessionalScreenState extends State { _photo = await AuthenticationRepository.instance.getPhoto(user.id); if (data['estado'] == 'activo') { - List especializaciones; + if (user.id != uid) { + List especializaciones; - especializaciones = (data['especializaciones'] as List) - .map((e) => e.toString()) - .toList(); + especializaciones = (data['especializaciones'] as List) + .map((e) => e.toString()) + .toList(); - if (widget.profession == data['profesion'] || - widget.profession == '') { - 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.scoreTo(user.id, true, true), - ); - professionals.add(professional); + if (widget.profession == data['profesion'] || + widget.profession == '') { + 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.scoreTo(user.id, true, true), + ); + professionals.add(professional); + } } } } @@ -211,13 +212,16 @@ class _ProfessionalScreenState extends State { setState(() { if (_professionals != null) { if (searchController.text.isEmpty) { - filteredProfessionals = _professionals!; + filteredProfessionals = _professionals! + .where((professional) => professional.id != uid) + .toList(); } else { filteredProfessionals = _professionals! - .where((professional) => removeDiacritics(professional.name) - .toLowerCase() - .contains( - removeDiacritics(searchController.text.toLowerCase()))) + .where((professional) => + removeDiacritics(professional.name).toLowerCase().contains( + removeDiacritics( + searchController.text.toLowerCase())) && + professional.id != uid) .toList(); } } diff --git a/lib/src/screens/profile_pro.dart b/lib/src/screens/profile_pro.dart index f215cc4..df141a0 100644 --- a/lib/src/screens/profile_pro.dart +++ b/lib/src/screens/profile_pro.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -9,10 +8,10 @@ import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/components/banner_photo.dart'; -import 'package:prosappco/src/components/drawer_professional.dart'; import 'package:prosappco/src/components/pop_appbar.dart'; import 'package:prosappco/src/components/primary_btn.dart'; import 'package:prosappco/src/components/schedule_picker.dart'; +import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/screens/horario.dart'; import 'package:prosappco/src/screens/professional.dart'; import 'package:prosappco/src/screens/professional_direccion.dart'; @@ -41,12 +40,18 @@ class _ProfileProState extends State { var _direccion = '...'; var _ubicacion = '...'; var _opcionalAddress = '...'; + SettingModel? setting_domicilio; Map? _horarios; @override void initState() { super.initState(); + if (setting_domicilio == null) { + SettingModel.getDomiciliosSettings().then( + (SettingModel value) => setState(() => setting_domicilio = value), + ); + } final uid = AuthenticationRepository.instance.getCurrentUserUid(); @@ -283,17 +288,19 @@ class _ProfileProState extends State { ), ), ), - const Divider( - color: Colors.white, - height: 12, - ), - customSwitch( - 'Servicio a domicilio', - domicilioValue, - (value) { - domicilioValue = value; - }, - ), + if (setting_domicilio?.domicilios == true) + const Divider( + color: Colors.white, + height: 12, + ), + if (setting_domicilio?.domicilios == true) + customSwitch( + 'Servicio a domicilio', + domicilioValue, + (value) { + domicilioValue = value; + }, + ), const Divider(), customSwitch( 'Servicio en sitio', diff --git a/lib/src/screens/service.dart b/lib/src/screens/service.dart index 969095f..92a2bef 100644 --- a/lib/src/screens/service.dart +++ b/lib/src/screens/service.dart @@ -1,4 +1,5 @@ import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:community_material_icon/community_material_icon.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -88,7 +89,7 @@ class _ServiceScreenState extends State { final DateTime? picked = await showDatePicker( context: context, initialDate: now, - firstDate: DateTime(now.year), + firstDate: now, lastDate: DateTime(now.year + 1), // builder: (context, child) { // return Theme(data: ThemeData.dark(), child: child!); @@ -130,10 +131,19 @@ class _ServiceScreenState extends State { final FirebaseStorage storage = FirebaseStorage.instance; final uid = AuthenticationRepository.instance.getCurrentUserUid(); + BitmapDescriptor? _markerIcon; + @override void initState() { super.initState(); + BitmapDescriptor.fromAssetImage( + ImageConfiguration(size: Size(48, 48)), 'images/pro_marke.png') + .then((icon) { + setState(() { + _markerIcon = icon; + }); + }); try { getUsersWithActiveStatus().then((value) { for (var doc in value) { @@ -142,6 +152,7 @@ class _ServiceScreenState extends State { if (element['latitude'] != null && element['longitude'] != null) { markers.add( Marker( + icon: _markerIcon!, markerId: MarkerId(doc.id), position: LatLng( element['latitude'], @@ -448,7 +459,29 @@ class _ServiceScreenState extends State { width: 180, child: TextFormField( onTap: () { - _selectDate(context); + if (_profesionalController + .text.isNotEmpty) { + _selectDate(context); + } else { + final snackBar = SnackBar( + backgroundColor: Colors.blue, + content: const Text( + 'Selecciona un profesional', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + elevation: 8.0, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(10.0), + ), + ); + + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + } }, readOnly: true, decoration: InputDecoration( @@ -469,7 +502,29 @@ class _ServiceScreenState extends State { width: 140, child: TextFormField( onTap: () { - _selectTime(context); + if (_profesionalController + .text.isNotEmpty) { + _selectTime(context); + } else { + final snackBar = SnackBar( + backgroundColor: Colors.blue, + content: const Text( + 'Selecciona un profesional', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + elevation: 8.0, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(10.0), + ), + ); + + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + } }, readOnly: true, decoration: const InputDecoration( @@ -508,21 +563,21 @@ class _ServiceScreenState extends State { UserModel.getUser(uid.toString()).then((value) { eventoService .createEvent( - value.name, - _observacionController.text, - '${_selectedDate}Z', - _selectedTime!.format(context), - time2.format(context), - professionalId, - ubicacion, - _locationController.text, - ubicacion != 'sitio' - ? coordinates.latitude - : professionalLatitude, - ubicacion != 'sitio' - ? coordinates.longitude - : professionalLongitude, - ) + value.name, + _observacionController.text, + '${_selectedDate}Z', + _selectedTime!.format(context), + time2.format(context), + professionalId, + ubicacion, + _locationController.text, + ubicacion != 'sitio' + ? coordinates.latitude + : professionalLatitude, + ubicacion != 'sitio' + ? coordinates.longitude + : professionalLongitude, + 'pendiente') .then((value) { Navigator.push( context, diff --git a/lib/src/screens/solicitudes.dart b/lib/src/screens/solicitudes.dart index 909dddf..dc5fab4 100644 --- a/lib/src/screens/solicitudes.dart +++ b/lib/src/screens/solicitudes.dart @@ -4,7 +4,6 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:intl/intl.dart'; import 'package:prosappco/src/components/drawer_professional.dart'; import 'package:prosappco/src/models/event_model.dart'; -import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/screens/cita.dart'; class SolicitudScreen extends StatefulWidget { @@ -52,7 +51,7 @@ class _SolicitudScreenState extends State { Widget _eventList() { return FutureBuilder( - future: getByProIdAll(), + future: getByProIdAll('pendiente', ''), builder: (BuildContext context, AsyncSnapshot> snapshot) { if (!snapshot.hasData) { return const Center( @@ -135,11 +134,11 @@ class _SolicitudScreenState extends State { ), const SizedBox(width: 5), Text( - '(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'), + '(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'), ], ), Text( - '" ${event.description} "', + '" ${event.description}"', style: const TextStyle(fontStyle: FontStyle.italic), ), ],