chat primera face
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
+4
-1
@@ -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}');
|
||||
|
||||
@@ -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<DrawerMenu> {
|
||||
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,
|
||||
|
||||
@@ -112,7 +112,14 @@ class _DrawerProfessionalState extends State<DrawerProfessional> {
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
class ChatModel {
|
||||
List<MessageModel> messages;
|
||||
|
||||
ChatModel({required this.messages});
|
||||
|
||||
static ChatModel fromDocumentSnapshot(
|
||||
DocumentSnapshot<Map<String, dynamic>> snapshot) {
|
||||
try {
|
||||
List<MessageModel> messages = [];
|
||||
List<dynamic> 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});
|
||||
}
|
||||
@@ -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<List<Event>> getByProId(String day) async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Event>> getByProIdAll() async {
|
||||
Future<List<Event>> 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<Event> 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<List<Event>> 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<String, dynamic> 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<List<Event>> 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<Event> 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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
class SettingModel {
|
||||
final bool domicilios;
|
||||
|
||||
SettingModel(this.domicilios);
|
||||
|
||||
static Future<SettingModel> fromJson(Map<String, dynamic> json) async {
|
||||
try {
|
||||
if (json == null) return SettingModel(false);
|
||||
|
||||
return SettingModel(json['habilitado']);
|
||||
} catch (e) {
|
||||
print('Error settings: $e');
|
||||
return SettingModel(false);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<SettingModel> getDomiciliosSettings() async {
|
||||
try {
|
||||
final DocumentSnapshot<Map<String, dynamic>> snapshot =
|
||||
await FirebaseFirestore.instance
|
||||
.collection('settings')
|
||||
.doc('domicilios')
|
||||
.get();
|
||||
final Map<String, dynamic>? data = snapshot.data();
|
||||
return fromJson(data!);
|
||||
} catch (e) {
|
||||
print('Error getting settings: $e');
|
||||
return SettingModel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,9 +61,10 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
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<CalendarScreen> {
|
||||
'',
|
||||
'',
|
||||
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;
|
||||
}),
|
||||
|
||||
@@ -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<ChatScreen> createState() => _ChatScreenState();
|
||||
}
|
||||
|
||||
class _ChatScreenState extends State<ChatScreen> {
|
||||
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))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+108
-23
@@ -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<CitaScreen> {
|
||||
),
|
||||
),
|
||||
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<CitaScreen> {
|
||||
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(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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<MyServicesScreen> createState() => _MyServicesScreenState();
|
||||
}
|
||||
|
||||
class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
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<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
List<Event> 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<MyServicesProScreen> createState() => _MyServicesProScreenState();
|
||||
}
|
||||
|
||||
class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
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<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
List<Event> 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<ProfessionalScreen> {
|
||||
_photo = await AuthenticationRepository.instance.getPhoto(user.id);
|
||||
|
||||
if (data['estado'] == 'activo') {
|
||||
List<String> especializaciones;
|
||||
if (user.id != uid) {
|
||||
List<String> especializaciones;
|
||||
|
||||
especializaciones = (data['especializaciones'] as List<dynamic>)
|
||||
.map((e) => e.toString())
|
||||
.toList();
|
||||
especializaciones = (data['especializaciones'] as List<dynamic>)
|
||||
.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<ProfessionalScreen> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ProfilePro> {
|
||||
var _direccion = '...';
|
||||
var _ubicacion = '...';
|
||||
var _opcionalAddress = '...';
|
||||
SettingModel? setting_domicilio;
|
||||
|
||||
Map<String, Schedule>? _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<ProfilePro> {
|
||||
),
|
||||
),
|
||||
),
|
||||
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',
|
||||
|
||||
@@ -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<ServiceScreen> {
|
||||
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<ServiceScreen> {
|
||||
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<ServiceScreen> {
|
||||
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<ServiceScreen> {
|
||||
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<ServiceScreen> {
|
||||
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<ServiceScreen> {
|
||||
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,
|
||||
|
||||
@@ -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<SolicitudScreen> {
|
||||
|
||||
Widget _eventList() {
|
||||
return FutureBuilder(
|
||||
future: getByProIdAll(),
|
||||
future: getByProIdAll('pendiente', ''),
|
||||
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
@@ -135,11 +134,11 @@ class _SolicitudScreenState extends State<SolicitudScreen> {
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user