fix
This commit is contained in:
@@ -6,8 +6,11 @@ import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||
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/configuracion.dart';
|
||||
import 'package:prosappco/src/screens/messages_user.dart';
|
||||
import 'package:prosappco/src/screens/profile.dart';
|
||||
import 'package:prosappco/src/screens/reputation.dart';
|
||||
import 'package:prosappco/src/screens/support.dart';
|
||||
|
||||
class DrawerMenu extends StatefulWidget {
|
||||
@override
|
||||
@@ -144,7 +147,16 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const ConfiguracionScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.construction_outlined,
|
||||
color: Colors.black,
|
||||
@@ -155,7 +167,16 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const SupportScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.question_mark_rounded,
|
||||
color: Colors.black,
|
||||
@@ -227,7 +248,16 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
color: const Color(0xFFD6F4FF),
|
||||
child: ListTile(
|
||||
tileColor: const Color(0xFFD6F4FF),
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const ReputationScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
trailing: const Icon(Icons.keyboard_arrow_right,
|
||||
color: Colors.black),
|
||||
title: const Text(
|
||||
@@ -255,7 +285,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toString()}'),
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -14,6 +14,8 @@ import 'package:prosappco/src/screens/profile_pro.dart';
|
||||
import 'package:prosappco/src/screens/reputation.dart';
|
||||
|
||||
import '../models/scores_model.dart';
|
||||
import '../screens/configuracion.dart';
|
||||
import '../screens/support.dart';
|
||||
|
||||
class DrawerProfessional extends StatefulWidget {
|
||||
@override
|
||||
@@ -153,7 +155,16 @@ class _DrawerProfessionalState extends State<DrawerProfessional> {
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const ConfiguracionScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.construction_outlined,
|
||||
color: Colors.black,
|
||||
@@ -164,7 +175,16 @@ class _DrawerProfessionalState extends State<DrawerProfessional> {
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const SupportScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: const Icon(
|
||||
Icons.question_mark_rounded,
|
||||
color: Colors.black,
|
||||
@@ -296,7 +316,7 @@ class _DrawerProfessionalState extends State<DrawerProfessional> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toString()}'),
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -17,6 +17,7 @@ class EventoService {
|
||||
double latitude,
|
||||
double longitude,
|
||||
String status,
|
||||
int? tarifa,
|
||||
) async {
|
||||
try {
|
||||
DateTime ahora = DateTime.now();
|
||||
@@ -35,7 +36,8 @@ class EventoService {
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
'status': status,
|
||||
'Timestamp': ahora
|
||||
'Timestamp': ahora,
|
||||
'tarifa': tarifa ?? 0,
|
||||
}).then((value) {
|
||||
FirebaseFirestore.instance.collection('users').doc(uid).update({
|
||||
'services': FieldValue.arrayUnion([value.id])
|
||||
@@ -135,6 +137,7 @@ class Event {
|
||||
double? latitud;
|
||||
String status;
|
||||
ScoresModel? scoresModel;
|
||||
int? tarifa;
|
||||
|
||||
Event({
|
||||
this.id,
|
||||
@@ -150,6 +153,7 @@ class Event {
|
||||
this.longitud,
|
||||
this.latitud,
|
||||
this.status = 'pendiente',
|
||||
this.tarifa,
|
||||
});
|
||||
|
||||
factory Event.fromJson(Map<String, dynamic> json) {
|
||||
@@ -167,6 +171,7 @@ class Event {
|
||||
longitud: json['longitude'] ?? 0,
|
||||
latitud: json['latitude'] ?? 0,
|
||||
status: json['status'],
|
||||
tarifa: json['tarifa'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ScoresModel {
|
||||
String userReceived, bool isFromClient, bool userInfo) async {
|
||||
final receivedScoresQuery = FirebaseFirestore.instance
|
||||
.collection('scores')
|
||||
.where('is_from_client', isEqualTo: isFromClient)
|
||||
.where('is_from_professional', isEqualTo: isFromClient)
|
||||
.where('to_user', isEqualTo: userReceived);
|
||||
|
||||
final receivedScoresSnapshot = await receivedScoresQuery.get();
|
||||
@@ -48,7 +48,7 @@ class ScoresModel {
|
||||
String userGiven, bool isFromClient, bool userInfo) async {
|
||||
final givenScoresQuery = FirebaseFirestore.instance
|
||||
.collection('scores')
|
||||
.where('is_from_client', isEqualTo: isFromClient)
|
||||
.where('is_from_professional', isEqualTo: isFromClient)
|
||||
.where('from_user', isEqualTo: userGiven);
|
||||
|
||||
final givenScoresSnapshot = await givenScoresQuery.get();
|
||||
@@ -101,7 +101,7 @@ class ScoreDetailModel {
|
||||
fromUser: data['from_user'],
|
||||
toUser: data['to_user'],
|
||||
comment: data['comment'],
|
||||
isFromClient: data['is_from_client'],
|
||||
isFromClient: data['is_from_professional'],
|
||||
name: user?.name ?? "...",
|
||||
avatar: user?.photo);
|
||||
} catch (e) {
|
||||
|
||||
@@ -3,17 +3,51 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
class SettingModel {
|
||||
final bool domicilios;
|
||||
final bool tarifas;
|
||||
final String titulo;
|
||||
final String parrafo;
|
||||
final String numero;
|
||||
final String email;
|
||||
final String dias;
|
||||
final String horas;
|
||||
final String version;
|
||||
final String proliticasPrivacidad;
|
||||
final String terminosCondiciones;
|
||||
|
||||
SettingModel(this.domicilios, this.tarifas);
|
||||
SettingModel(
|
||||
this.domicilios,
|
||||
this.tarifas,
|
||||
this.titulo,
|
||||
this.parrafo,
|
||||
this.numero,
|
||||
this.email,
|
||||
this.dias,
|
||||
this.horas,
|
||||
this.version,
|
||||
this.proliticasPrivacidad,
|
||||
this.terminosCondiciones,
|
||||
);
|
||||
|
||||
static Future<SettingModel> fromJson(Map<String, dynamic> json) async {
|
||||
try {
|
||||
if (json == null) return SettingModel(false, false);
|
||||
if (json == null)
|
||||
return SettingModel(false, false, '', '', '', '', '', '', '', '', '');
|
||||
|
||||
return SettingModel(json['domicilio'], json['tarifa']);
|
||||
return SettingModel(
|
||||
json['domicilio'],
|
||||
json['tarifa'],
|
||||
json['titulo_soporte'],
|
||||
json['parrafo_soporte'],
|
||||
json['numero_soporte'],
|
||||
json['email_soporte'],
|
||||
json['dias_soporte'],
|
||||
json['horas_soporte'],
|
||||
json['version'],
|
||||
json['politicas_privacidad'],
|
||||
json['terminos_condiciones'],
|
||||
);
|
||||
} catch (e) {
|
||||
print('Error settings: $e');
|
||||
return SettingModel(false, false);
|
||||
return SettingModel(false, false, '', '', '', '', '', '', '', '', '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +58,14 @@ class SettingModel {
|
||||
.collection('settings')
|
||||
.doc('global')
|
||||
.get();
|
||||
|
||||
final Map<String, dynamic>? data = snapshot.data();
|
||||
|
||||
print('data $data');
|
||||
return fromJson(data!);
|
||||
} catch (e) {
|
||||
print('Error getting settings: $e');
|
||||
return SettingModel(false, false);
|
||||
return SettingModel(false, false, '', '', '', '', '', '', '', '', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,25 +8,27 @@ class UserModel {
|
||||
final String? profession;
|
||||
final String? state;
|
||||
final Reference? photo;
|
||||
final int? tarifa;
|
||||
|
||||
UserModel(this.name, this.city, this.profession, this.state, this.photo);
|
||||
UserModel(this.name, this.city, this.profession, this.state, this.photo,
|
||||
this.tarifa);
|
||||
|
||||
static Future<UserModel> fromJson(
|
||||
Map<String, dynamic>? json, String uid) async {
|
||||
try {
|
||||
if (json == null) return UserModel('', '', '', null, null);
|
||||
if (json == null) return UserModel('', '', '', null, null, 0);
|
||||
|
||||
String? avatar = json['photo'];
|
||||
return UserModel(
|
||||
json['name'],
|
||||
json['city'],
|
||||
json['profesion'],
|
||||
json['estado'],
|
||||
avatar != null ? storage.ref().child(avatar) : null,
|
||||
);
|
||||
json['name'],
|
||||
json['city'],
|
||||
json['profesion'],
|
||||
json['estado'],
|
||||
avatar != null ? storage.ref().child(avatar) : null,
|
||||
json['tarifa'] ?? 0);
|
||||
} catch (e) {
|
||||
print('XD user $e');
|
||||
return UserModel('', '', '', null, null);
|
||||
return UserModel('', '', '', null, null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ class UserModel {
|
||||
return fromJson(data, uid);
|
||||
} catch (e) {
|
||||
print('Error getting user: $e');
|
||||
return UserModel('', '', '', null, null);
|
||||
return UserModel('', '', '', null, null, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/models/setting_model.dart';
|
||||
import 'package:prosappco/src/screens/web_view.dart';
|
||||
|
||||
class AboutScreen extends StatefulWidget {
|
||||
const AboutScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AboutScreen> createState() => _AboutScreenState();
|
||||
}
|
||||
|
||||
class _AboutScreenState extends State<AboutScreen> {
|
||||
SettingModel? settings;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (settings == null) {
|
||||
SettingModel.getSettings().then(
|
||||
(SettingModel value) => setState(() {
|
||||
settings = value;
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'Acerca de la aplicación'),
|
||||
body: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return WebViewScreen(
|
||||
label: 'Políticas de privacidad',
|
||||
link: settings?.proliticasPrivacidad ?? '',
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
title: const Text('Políticas de privacidad'),
|
||||
trailing:
|
||||
const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return WebViewScreen(
|
||||
label: 'Términos y condiciones',
|
||||
link: settings?.terminosCondiciones ?? '',
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
title: const Text('Términos y condiciones'),
|
||||
trailing:
|
||||
const Icon(Icons.keyboard_arrow_right, color: Colors.black),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Versión de la aplicación'),
|
||||
subtitle: Text(settings?.version ?? ''),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/components/primary_btn.dart';
|
||||
import 'package:prosappco/src/models/event_model.dart';
|
||||
import 'package:prosappco/src/models/scores_model.dart';
|
||||
import 'package:prosappco/src/screens/cita.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -26,7 +25,10 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
|
||||
EventoService eventoService = EventoService();
|
||||
CalendarFormat _calendarFormat = CalendarFormat.month;
|
||||
|
||||
DateTime today = DateTime.now();
|
||||
DateTime now = DateTime.now();
|
||||
|
||||
TimeOfDay? _selectedTime1;
|
||||
TimeOfDay? _selectedTime2;
|
||||
|
||||
@@ -283,19 +285,36 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
),
|
||||
PrimaryButtom(
|
||||
onPressed: () async {
|
||||
final DateTime combinedDate1 = DateTime(
|
||||
today.year,
|
||||
today.month,
|
||||
today.day,
|
||||
_selectedTime1!.hour,
|
||||
_selectedTime1!.minute,
|
||||
);
|
||||
final DateTime combinedDate2 = DateTime(
|
||||
today.year,
|
||||
today.month,
|
||||
today.day,
|
||||
_selectedTime2!.hour,
|
||||
_selectedTime2!.minute,
|
||||
);
|
||||
|
||||
await eventoService
|
||||
.createEvent(
|
||||
_titleController.text,
|
||||
_descriptionController.text,
|
||||
today.toString(),
|
||||
_selectedTime1!.format(context).toString(),
|
||||
_selectedTime2!.format(context).toString(),
|
||||
uid.toString(),
|
||||
'',
|
||||
'',
|
||||
0,
|
||||
0,
|
||||
'aprobado')
|
||||
_titleController.text,
|
||||
_descriptionController.text,
|
||||
DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(today),
|
||||
'$combinedDate1',
|
||||
'$combinedDate2',
|
||||
uid.toString(),
|
||||
'',
|
||||
'',
|
||||
0,
|
||||
0,
|
||||
'aprobado',
|
||||
0,
|
||||
)
|
||||
.then((value) {
|
||||
Navigator.pop(context);
|
||||
_titleController.text = '';
|
||||
@@ -323,8 +342,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
|
||||
Widget _eventList() {
|
||||
return FutureBuilder(
|
||||
future:
|
||||
getByProId('${DateFormat("yyyy-MM-dd 00:00:00.000").format(today)}Z'),
|
||||
future: getByProId(DateFormat("yyyy-MM-dd 00:00:00.000").format(today)),
|
||||
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Text('No tiene citas');
|
||||
@@ -355,7 +373,9 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: Text(e.range1Hour1),
|
||||
leading: Text(
|
||||
TimeOfDay.fromDateTime(DateTime.parse(e.range1Hour1))
|
||||
.format(context)),
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
@@ -402,7 +422,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${e.scoresModel?.total.toString()}) ${e.scoresModel?.average.toString()}'),
|
||||
'(${e.scoresModel?.total.toString()}) ${e.scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -37,12 +37,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if (scoresModel == null) {
|
||||
// ScoresModel.scoreTo(uid.toString(), false, false).then(
|
||||
// (ScoresModel s) => setState(() => scoresModel = s),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -62,7 +56,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(0, 2), // changes position of shadow
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
+151
-6
@@ -3,6 +3,7 @@ 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:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:prosappco/src/authentication/authentication_repository.dart';
|
||||
import 'package:prosappco/src/components/photo_view.dart';
|
||||
@@ -11,6 +12,7 @@ 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:prosappco/src/screens/score.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:community_material_icon/community_material_icon.dart';
|
||||
|
||||
@@ -25,13 +27,20 @@ class CitaScreen extends StatefulWidget {
|
||||
class _CitaScreenState extends State<CitaScreen> {
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
UserModel? user;
|
||||
@override
|
||||
DateTime today = DateTime.now();
|
||||
String nombre = '';
|
||||
int tarifa = 0;
|
||||
Reference? ref_photo;
|
||||
ScoresModel? scoresModel;
|
||||
|
||||
final phoneNumber = '+573022548060';
|
||||
|
||||
String formatCurrency(int number) {
|
||||
final formatter =
|
||||
NumberFormat.currency(locale: 'es_CO', decimalDigits: 0, symbol: '');
|
||||
return '\$${formatter.format(number)}';
|
||||
}
|
||||
|
||||
Future<void> _openMap(double lat, double lng) async {
|
||||
final Uri _url =
|
||||
Uri.parse('https://www.google.com/maps/search/?api=1&query=$lat,$lng');
|
||||
@@ -73,17 +82,25 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
today.difference(DateTime.parse(widget.evento.range1Hour1));
|
||||
// DateTime todays = DateFormat('hh:mm a').parse(today.timeZoneName);
|
||||
final eventDate = DateFormat('yyyy-MM-dd').parse(widget.evento.day);
|
||||
|
||||
if (nombre == '') {
|
||||
if (uid != widget.evento.userId) {
|
||||
UserModel.getUser(widget.evento.userId).then((value) {
|
||||
setState(() {
|
||||
nombre = value.name;
|
||||
ref_photo = value.photo;
|
||||
UserModel.getUser(uid.toString()).then((me) {
|
||||
setState(() {
|
||||
tarifa = me.tarifa ?? 0;
|
||||
nombre = value.name;
|
||||
ref_photo = value.photo;
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
UserModel.getUser(widget.evento.professionalId).then((value) {
|
||||
setState(() {
|
||||
tarifa = value.tarifa ?? 0;
|
||||
nombre = value.name;
|
||||
ref_photo = value.photo;
|
||||
});
|
||||
@@ -122,7 +139,7 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(widget.evento.day))} ${widget.evento.range1Hour1}',
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(widget.evento.day))} ${TimeOfDay.fromDateTime(DateTime.parse(widget.evento.range1Hour1)).format(context)}',
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 16,
|
||||
@@ -151,7 +168,7 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toString()}'),
|
||||
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -194,6 +211,18 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
formatCurrency(tarifa),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 25),
|
||||
),
|
||||
Text('Tarifa consulta ${widget.evento.tarifa}',
|
||||
style: const TextStyle(fontSize: 15)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
textAlign: TextAlign.center,
|
||||
'" ${widget.evento.description} "',
|
||||
@@ -367,6 +396,80 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
widget.evento.status == 'aprobado'
|
||||
? eventDate.year == today.year &&
|
||||
eventDate.month == today.month &&
|
||||
eventDate.day == today.day
|
||||
? (DateTime.now()
|
||||
.difference(
|
||||
DateTime.parse(widget.evento.range1Hour1))
|
||||
.abs() <=
|
||||
const Duration(minutes: 30))
|
||||
? 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": "iniciado"});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Iniciar servicio',
|
||||
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()
|
||||
: const SizedBox()
|
||||
: const SizedBox(),
|
||||
widget.evento.status == 'pendiente'
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
@@ -433,6 +536,48 @@ class _CitaScreenState extends State<CitaScreen> {
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
widget.evento.status == 'iniciado'
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: Column(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
FirebaseFirestore.instance
|
||||
.collection("services")
|
||||
.doc('${widget.evento.id}')
|
||||
.update({"status": "terminado"}).then((value) {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return ScoreScreen(evento: widget.evento);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Terminar servicio',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/screens/about.dart';
|
||||
|
||||
class ConfiguracionScreen extends StatelessWidget {
|
||||
const ConfiguracionScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'Configuración'),
|
||||
body: ListTile(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const AboutScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
title: const Text('Acerca de la aplicación'),
|
||||
trailing: const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.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';
|
||||
import 'package:prosappco/src/authentication/authentication_repository.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/models/scores_model.dart';
|
||||
import 'package:prosappco/src/screens/cita.dart';
|
||||
|
||||
class MyServicesScreen extends StatefulWidget {
|
||||
@@ -16,6 +19,7 @@ class MyServicesScreen extends StatefulWidget {
|
||||
|
||||
class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
DateTime today = DateTime.now();
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -44,10 +48,32 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
}
|
||||
|
||||
Widget _eventList() {
|
||||
return FutureBuilder(
|
||||
future: getByUserIdAll('aprobado', 'denegado'),
|
||||
return StreamBuilder<List<Event>>(
|
||||
stream: FirebaseFirestore.instance
|
||||
.collection('services')
|
||||
.where('user_id', isEqualTo: uid)
|
||||
.where('status',
|
||||
whereIn: ['aprobado', 'denegado', 'iniciado', 'terminado'])
|
||||
.snapshots()
|
||||
.asyncMap((snapshot) async {
|
||||
try {
|
||||
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');
|
||||
return eventos;
|
||||
} catch (e) {
|
||||
print('Error getByProId $e');
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
@@ -67,13 +93,14 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
child: Center(child: Text('No tienes citas')),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
...eventos.map(
|
||||
(event) => ListTile(
|
||||
tileColor: event.status == 'aprobado'
|
||||
? Colors.blue[100]
|
||||
: Colors.red[100],
|
||||
tileColor: event.status == 'denegado'
|
||||
? Colors.red[100]
|
||||
: Colors.blue[100],
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
@@ -90,11 +117,23 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
: event.status == 'iniciado'
|
||||
? const Icon(
|
||||
Icons.access_time,
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: event.status == 'terminado'
|
||||
? const Icon(
|
||||
Icons.rocket_launch,
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
@@ -108,7 +147,7 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${event.range1Hour1}',
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
fontSize: 16,
|
||||
@@ -141,7 +180,7 @@ class _MyServicesScreenState extends State<MyServicesScreen> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'),
|
||||
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.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';
|
||||
import 'package:prosappco/src/authentication/authentication_repository.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/models/scores_model.dart';
|
||||
import 'package:prosappco/src/screens/cita.dart';
|
||||
|
||||
class MyServicesProScreen extends StatefulWidget {
|
||||
MyServicesProScreen({super.key});
|
||||
const MyServicesProScreen({super.key});
|
||||
|
||||
@override
|
||||
State<MyServicesProScreen> createState() => _MyServicesProScreenState();
|
||||
@@ -15,6 +19,7 @@ class MyServicesProScreen extends StatefulWidget {
|
||||
|
||||
class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
DateTime today = DateTime.now();
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -43,10 +48,32 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
}
|
||||
|
||||
Widget _eventList() {
|
||||
return FutureBuilder(
|
||||
future: getByProIdAll('aprobado', 'denegado'),
|
||||
return StreamBuilder<List<Event>>(
|
||||
stream: FirebaseFirestore.instance
|
||||
.collection('services')
|
||||
.where('professional_id', isEqualTo: uid)
|
||||
.where('status',
|
||||
whereIn: ['aprobado', 'denegado', 'iniciado', 'terminado'])
|
||||
.snapshots()
|
||||
.asyncMap((snapshot) async {
|
||||
try {
|
||||
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');
|
||||
return eventos;
|
||||
} catch (e) {
|
||||
print('Error getByProId $e');
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
@@ -66,24 +93,23 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
child: Center(child: Text('No tienes citas')),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
...eventos.map(
|
||||
(event) => ListTile(
|
||||
tileColor: event.status == 'aprobado'
|
||||
? Colors.blue[100]
|
||||
: Colors.red[100],
|
||||
tileColor: event.status == 'denegado'
|
||||
? Colors.red[100]
|
||||
: Colors.blue[100],
|
||||
onTap: () {
|
||||
print(event.id);
|
||||
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// CupertinoPageRoute(
|
||||
// builder: (BuildContext context) {
|
||||
// return CitaScreen(evento: event);
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return CitaScreen(evento: event);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: event.status == 'aprobado'
|
||||
? const Icon(
|
||||
@@ -91,11 +117,17 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
: event.status == 'iniciado'
|
||||
? const Icon(
|
||||
Icons.access_time,
|
||||
color: Colors.blue,
|
||||
size: 40,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
@@ -109,7 +141,7 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${event.range1Hour1}',
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(event.day))} - ${TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1)).format(context)}',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[600],
|
||||
fontSize: 16,
|
||||
@@ -142,7 +174,7 @@ class _MyServicesProScreenState extends State<MyServicesProScreen> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toString()}'),
|
||||
'(${event.scoresModel?.total.toString()}) ${event.scoresModel?.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -36,6 +36,7 @@ class Professional {
|
||||
final double longitude;
|
||||
final List<String> professionalEspecializado;
|
||||
final ScoresModel scores;
|
||||
final int? tarifa;
|
||||
|
||||
Professional({
|
||||
required this.id,
|
||||
@@ -49,6 +50,7 @@ class Professional {
|
||||
required this.realAddress,
|
||||
required this.latitude,
|
||||
required this.longitude,
|
||||
this.tarifa,
|
||||
});
|
||||
|
||||
String getEspecializaciones() {
|
||||
@@ -90,18 +92,18 @@ class Professional {
|
||||
.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),
|
||||
);
|
||||
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['tarifa'] ?? 0);
|
||||
return professional;
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -170,7 +170,7 @@ class _ProfessionalInfoScreenState extends State<ProfessionalInfoScreen> {
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'(${widget.professional.scores.total.toString()}) ${widget.professional.scores.average.toString()}'),
|
||||
'(${widget.professional.scores.total.toString()}) ${widget.professional.scores.average.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.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/scores_model.dart';
|
||||
|
||||
class ReputationProScreen extends StatefulWidget {
|
||||
const ReputationProScreen({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ReputationProScreen> createState() => _ReputationProScreenState();
|
||||
}
|
||||
|
||||
class _ReputationProScreenState extends State<ReputationProScreen> {
|
||||
ScoresModel? scoresModel;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
|
||||
if (scoresModel == null) {
|
||||
ScoresModel.scoreFrom(uid.toString(), false, true).then(
|
||||
(ScoresModel s) => setState(() => scoresModel = s),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'Reputación'),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
..._scoresList(scoresModel?.details ?? []),
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _scoresList(List<ScoreDetailModel> list) {
|
||||
return list.map((e) => _scoreItem(e)).toList();
|
||||
}
|
||||
|
||||
Widget _scoreItem(ScoreDetailModel scoreDetails) {
|
||||
return ListTile(
|
||||
onTap: () {},
|
||||
leading: ReferencePhoto(
|
||||
ref: scoreDetails.avatar,
|
||||
size: 50,
|
||||
sizeCircle: 50,
|
||||
sizeIcon: 35,
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
RatingBar.builder(
|
||||
initialRating: scoreDetails.score,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 22,
|
||||
maxRating: 5,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 0),
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
),
|
||||
onRatingUpdate: (rating) {},
|
||||
ignoreGestures: true,
|
||||
),
|
||||
Text(
|
||||
' (${scoreDetails.score})',
|
||||
style: const TextStyle(color: Colors.black54, fontSize: 13),
|
||||
)
|
||||
],
|
||||
),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${scoreDetails.name}, ',
|
||||
style: const TextStyle(fontSize: 15, color: Colors.black),
|
||||
),
|
||||
TextSpan(
|
||||
text: '"${scoreDetails.comment}"',
|
||||
style: const TextStyle(fontSize: 15, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ 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/scores_model.dart';
|
||||
import 'package:prosappco/src/models/user_model.dart';
|
||||
|
||||
class ReputationScreen extends StatefulWidget {
|
||||
ReputationScreen({
|
||||
const ReputationScreen({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -24,7 +23,7 @@ class _ReputationScreenState extends State<ReputationScreen> {
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
|
||||
if (scoresModel == null) {
|
||||
ScoresModel.scoreTo(uid.toString(), true, true).then(
|
||||
ScoresModel.scoreTo(uid.toString(), false, true).then(
|
||||
(ScoresModel s) => setState(() => scoresModel = s),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_storage/firebase_storage.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/photo_view.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/models/event_model.dart';
|
||||
import 'package:prosappco/src/models/user_model.dart';
|
||||
|
||||
class ScoreScreen extends StatefulWidget {
|
||||
final Event evento;
|
||||
|
||||
const ScoreScreen({super.key, required this.evento});
|
||||
|
||||
@override
|
||||
State<ScoreScreen> createState() => ScoreScreenState();
|
||||
}
|
||||
|
||||
class ScoreScreenState extends State<ScoreScreen> {
|
||||
TextEditingController commentController = TextEditingController();
|
||||
Reference? ref_photo;
|
||||
String nombre = '';
|
||||
double _rating = 1.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (nombre == '') {
|
||||
if (uid != widget.evento.userId) {
|
||||
UserModel.getUser(widget.evento.userId).then((value) {
|
||||
UserModel.getUser(uid.toString()).then((me) {
|
||||
setState(() {
|
||||
nombre = value.name;
|
||||
ref_photo = value.photo;
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
UserModel.getUser(widget.evento.professionalId).then((value) {
|
||||
setState(() {
|
||||
nombre = value.name;
|
||||
ref_photo = value.photo;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(onPressed: () {}, label: 'Puntuación'),
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: ListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
child: ReferencePhoto(
|
||||
ref: ref_photo,
|
||||
size: 50,
|
||||
sizeCircle: 50,
|
||||
sizeIcon: 35,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
nombre,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16),
|
||||
),
|
||||
subtitle: Text(
|
||||
'${DateFormat('dd MMM', 'es').format(DateTime.parse(widget.evento.day))} ${TimeOfDay.fromDateTime(DateTime.parse(widget.evento.range1Hour1)).format(context)}'),
|
||||
),
|
||||
),
|
||||
RatingBar.builder(
|
||||
initialRating: _rating,
|
||||
minRating: 1,
|
||||
direction: Axis.horizontal,
|
||||
allowHalfRating: true,
|
||||
itemCount: 5,
|
||||
itemSize: 40,
|
||||
glow: false,
|
||||
maxRating: 5,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
itemBuilder: (context, _) => const Icon(
|
||||
Icons.star,
|
||||
color: Color(0xFF2BA4EC),
|
||||
),
|
||||
onRatingUpdate: (rating) {
|
||||
setState(() {
|
||||
_rating = rating;
|
||||
});
|
||||
},
|
||||
ignoreGestures: false,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 40),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Comentario',
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
TextFormField(
|
||||
maxLines: null,
|
||||
keyboardType: TextInputType
|
||||
.multiline, // establece el tipo de teclado como "multilinea"
|
||||
controller: commentController,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: Column(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (widget.evento.professionalId == uid) {
|
||||
FirebaseFirestore.instance.collection("scores").add({
|
||||
"comment": commentController.text,
|
||||
"from_user": uid,
|
||||
"is_from_professional": false,
|
||||
"score": _rating,
|
||||
"to_user": widget.evento.userId,
|
||||
}).then((value) {
|
||||
// Navigator.pushReplacementNamed(context, '/score');
|
||||
});
|
||||
} else {
|
||||
FirebaseFirestore.instance.collection("scores").add({
|
||||
"comment": commentController.text,
|
||||
"from_user": uid,
|
||||
"is_from_professional": true,
|
||||
"score": _rating,
|
||||
"to_user": widget.evento.professionalId,
|
||||
}).then((value) {
|
||||
// Navigator.pushReplacementNamed(context, '/score');
|
||||
});
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
elevation: 0,
|
||||
minimumSize: const Size(230, 60),
|
||||
),
|
||||
child: const Text(
|
||||
'Enviar',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:community_material_icon/community_material_icon.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -35,6 +35,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
||||
final _serviceTypeController = TextEditingController();
|
||||
final _observacionController = TextEditingController();
|
||||
String professionalId = '';
|
||||
int professionalTarifa = 0;
|
||||
String professionalAddress = '';
|
||||
String professionalUbicacion = '';
|
||||
double? professionalLatitude;
|
||||
@@ -130,6 +131,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
||||
|
||||
final FirebaseStorage storage = FirebaseStorage.instance;
|
||||
final uid = AuthenticationRepository.instance.getCurrentUserUid();
|
||||
final fcmToken = FirebaseMessaging.instance.getToken();
|
||||
|
||||
BitmapDescriptor? _markerIcon;
|
||||
|
||||
@@ -411,6 +413,9 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
||||
|
||||
professionalId = profesional.id;
|
||||
|
||||
professionalTarifa =
|
||||
profesional.tarifa ?? 0;
|
||||
|
||||
professionalUbicacion =
|
||||
profesional.ubicacion;
|
||||
|
||||
@@ -549,35 +554,36 @@ class _ServiceScreenState extends State<ServiceScreen> {
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
int tiempo2 = ((_selectedTime!.hour * 3600 +
|
||||
_selectedTime!.minute * 60) +
|
||||
7200) %
|
||||
86400;
|
||||
final DateTime combinedDate = DateTime(
|
||||
_selectedDate!.year,
|
||||
_selectedDate!.month,
|
||||
_selectedDate!.day,
|
||||
_selectedTime!.hour,
|
||||
_selectedTime!.minute);
|
||||
|
||||
int hora2 = tiempo2 ~/ 3600;
|
||||
int minutos2 = (tiempo2 % 3600) ~/ 60;
|
||||
|
||||
TimeOfDay time2 =
|
||||
TimeOfDay(hour: hora2, minute: minutos2);
|
||||
DateTime time2 =
|
||||
combinedDate.add(const Duration(hours: 2));
|
||||
|
||||
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,
|
||||
'pendiente')
|
||||
value.name,
|
||||
_observacionController.text,
|
||||
'$_selectedDate',
|
||||
'$combinedDate',
|
||||
'$time2',
|
||||
professionalId,
|
||||
ubicacion,
|
||||
_locationController.text,
|
||||
ubicacion != 'sitio'
|
||||
? coordinates.latitude
|
||||
: professionalLatitude,
|
||||
ubicacion != 'sitio'
|
||||
? coordinates.longitude
|
||||
: professionalLongitude,
|
||||
'pendiente',
|
||||
professionalTarifa,
|
||||
)
|
||||
.then((value) {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.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';
|
||||
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 {
|
||||
@@ -50,8 +52,29 @@ class _SolicitudScreenState extends State<SolicitudScreen> {
|
||||
}
|
||||
|
||||
Widget _eventList() {
|
||||
return FutureBuilder(
|
||||
future: getByProIdAll('pendiente', ''),
|
||||
return StreamBuilder<List<Event>>(
|
||||
stream: FirebaseFirestore.instance
|
||||
.collection('services')
|
||||
.where('professional_id', isEqualTo: uid)
|
||||
.where('status', whereIn: ['pendiente', ''])
|
||||
.snapshots()
|
||||
.asyncMap((snapshot) async {
|
||||
try {
|
||||
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');
|
||||
return eventos;
|
||||
} catch (e) {
|
||||
print('Error getByProId $e');
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
@@ -87,7 +110,10 @@ class _SolicitudScreenState extends State<SolicitudScreen> {
|
||||
),
|
||||
);
|
||||
},
|
||||
leading: Text(event.range1Hour1),
|
||||
leading: Text(
|
||||
TimeOfDay.fromDateTime(DateTime.parse(event.range1Hour1))
|
||||
.format(context),
|
||||
),
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
@@ -134,7 +160,7 @@ 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.toStringAsFixed(1)}'),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import 'package:community_material_icon/community_material_icon.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:prosappco/src/models/setting_model.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SupportScreen extends StatefulWidget {
|
||||
const SupportScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SupportScreen> createState() => SsupportStateScreen();
|
||||
}
|
||||
|
||||
class SsupportStateScreen extends State<SupportScreen> {
|
||||
SettingModel? settings;
|
||||
|
||||
Future<void> _sendWhatsapp(String? number) async {
|
||||
final _whatsappUrl =
|
||||
'https://wa.me/$number?text=${Uri.parse('Hola! soy usuario de Prosapp y quisiera conocer mas sobre esta app')}';
|
||||
|
||||
if (!await launch(_whatsappUrl)) {
|
||||
throw Exception('Could not launch $_whatsappUrl');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _sendEmail(String recipients) async {
|
||||
final Email email = Email(
|
||||
body: '',
|
||||
subject: 'Soporte Prosapp',
|
||||
recipients: [recipients],
|
||||
isHTML: false,
|
||||
);
|
||||
|
||||
await FlutterEmailSender.send(email);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (settings == null) {
|
||||
SettingModel.getSettings().then(
|
||||
(SettingModel value) => setState(() {
|
||||
settings = value;
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: 'Soporte'),
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 30, left: 35, right: 35),
|
||||
child: Text(
|
||||
'${settings?.titulo}',
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 35),
|
||||
child: Text('${settings?.parrafo}'),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Expanded(child: SizedBox()),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_sendWhatsapp(settings?.numero);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
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(
|
||||
CommunityMaterialIcons.whatsapp,
|
||||
size: 30,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_sendEmail(settings?.email ?? '');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: const Color(0xFF2BA4EC),
|
||||
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.email_outlined,
|
||||
size: 30,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Expanded(child: SizedBox()),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 50),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Horario de atención:',
|
||||
style: TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text('${settings?.dias}'),
|
||||
const SizedBox(height: 5),
|
||||
Text('${settings?.horas}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:prosappco/src/components/pop_appbar.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WebViewScreen extends StatefulWidget {
|
||||
String label;
|
||||
String link;
|
||||
WebViewScreen({super.key, required this.label, required this.link});
|
||||
|
||||
@override
|
||||
State<WebViewScreen> createState() => _WebViewScreenState();
|
||||
}
|
||||
|
||||
class _WebViewScreenState extends State<WebViewScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setBackgroundColor(const Color(0x00000000))
|
||||
..setNavigationDelegate(
|
||||
NavigationDelegate(
|
||||
onProgress: (int progress) {
|
||||
// Update loading bar.
|
||||
},
|
||||
onPageStarted: (String url) {},
|
||||
onPageFinished: (String url) {},
|
||||
onWebResourceError: (WebResourceError error) {},
|
||||
onNavigationRequest: (NavigationRequest request) {
|
||||
if (request.url.startsWith('https://www.youtube.com/')) {
|
||||
return NavigationDecision.prevent;
|
||||
}
|
||||
return NavigationDecision.navigate;
|
||||
},
|
||||
),
|
||||
)
|
||||
..loadRequest(Uri.parse('${widget.link}'));
|
||||
return Scaffold(
|
||||
appBar: PopAppbar(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
label: widget.label,
|
||||
),
|
||||
body: WebViewWidget(controller: controller),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user