servicios

This commit is contained in:
Juan Felipe Duarte
2023-04-27 15:56:20 -05:00
parent 69168917f2
commit b3d31d3a8d
8 changed files with 297 additions and 115 deletions
-2
View File
@@ -19,7 +19,6 @@ import 'package:prosappco/src/screens/profile_pro.dart';
import 'package:prosappco/src/screens/register.dart';
import 'package:prosappco/src/screens/request_sent.dart';
import 'package:prosappco/src/screens/service.dart';
import 'firebase_options.dart';
void main() async {
@@ -60,7 +59,6 @@ class MyApp extends StatelessWidget {
'/solicitudEnviada': (context) => const RequestSentScreen(),
'/nuevaPassword': (context) => NewPasswordScreen(),
'/servicio': (context) => const ServiceScreen(),
'/profesional': (context) => const ProfessionalScreen(),
'/profilePro': (context) => const ProfilePro(),
'/calendar': (context) => const CalendarScreen(),
},
+9 -10
View File
@@ -4,13 +4,8 @@ import 'package:prosappco/src/authentication/authentication_repository.dart';
final uid = AuthenticationRepository.instance.getCurrentUserUid();
class EventoService {
Future<void> createEvent(
String title,
String description,
String day,
String range1Hour1,
String range1Hour2,
) async {
Future<void> createEvent(String title, String description, String day,
String range1Hour1, String range1Hour2, String professionalId) async {
try {
await FirebaseFirestore.instance.collection('services').add({
'user_id': uid,
@@ -18,7 +13,8 @@ class EventoService {
'description': description,
'day': day,
'range1Hour1': range1Hour1,
'range1Hour2': range1Hour2
'range1Hour2': range1Hour2,
'professional_id': professionalId
}).then((value) {
FirebaseFirestore.instance.collection('users').doc(uid).update({
'services': FieldValue.arrayUnion([value.id])
@@ -34,7 +30,7 @@ Future<List<Event>> getByProId(String day) async {
try {
var snapshot = await FirebaseFirestore.instance
.collection('services')
.where('user_id', isEqualTo: uid)
.where('professional_id', isEqualTo: uid)
.where('day', isEqualTo: day.toString())
.get();
@@ -57,6 +53,7 @@ class Event {
String? range1Hour1;
String? range1Hour2;
String? userId;
String? professionalId;
Event({
this.title,
@@ -65,6 +62,7 @@ class Event {
this.range1Hour1,
this.range1Hour2,
this.userId,
this.professionalId,
});
factory Event.fromJson(Map<String, dynamic> json) {
@@ -75,6 +73,7 @@ class Event {
range1Hour1: json['range1Hour1'],
range1Hour2: json['range1Hour2'],
userId: json['user_id'],
professionalId: json['professional_id'],
);
}
@@ -82,7 +81,7 @@ class Event {
try {
var snapshot = await FirebaseFirestore.instance
.collection('services')
.where('user_id', isEqualTo: uid)
.where('professional_id', isEqualTo: uid)
.get();
List<Event> eventos = [];
+39 -2
View File
@@ -1,9 +1,11 @@
import 'package:flutter/cupertino.dart';
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/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';
@@ -22,6 +24,8 @@ class _CalendarScreenState extends State<CalendarScreen> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
ScoresModel? scoresModel;
EventoService eventoService = EventoService();
CalendarFormat _calendarFormat = CalendarFormat.month;
DateTime today = DateTime.now();
@@ -63,6 +67,12 @@ class _CalendarScreenState extends State<CalendarScreen> {
_events = value;
}));
}
if (scoresModel == null) {
ScoresModel.scoreFrom(uid.toString(), false).then(
(ScoresModel s) => setState(() => scoresModel = s),
);
}
}
void _onDaySelected(DateTime day, DateTime focusedDay) {
@@ -287,6 +297,7 @@ class _CalendarScreenState extends State<CalendarScreen> {
today.toString(),
_selectedTime1!.format(context).toString(),
_selectedTime2!.format(context).toString(),
uid.toString(),
)
.then((value) {
Navigator.pop(context);
@@ -380,8 +391,34 @@ class _CalendarScreenState extends State<CalendarScreen> {
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${e.description}'),
Text('${e.description}'),
Row(
children: [
RatingBar.builder(
initialRating: 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(
'(${scoresModel?.total.toString()}) ${scoresModel?.average.toString()}'),
],
),
Text(
'" ${e.description} "',
style: const TextStyle(fontStyle: FontStyle.italic),
),
],
),
trailing: const Icon(Icons.keyboard_arrow_right),
+3 -3
View File
@@ -74,7 +74,7 @@ class _CitaScreenState extends State<CitaScreen> {
text: TextSpan(
children: [
TextSpan(
text: '${nombre}, ',
text: '$nombre, ',
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
@@ -84,7 +84,7 @@ class _CitaScreenState extends State<CitaScreen> {
TextSpan(
text:
'${DateFormat('dd MMM', 'es').format(DateTime.parse(widget.evento.day!))} ${widget.evento.range1Hour1}',
style: TextStyle(
style: const TextStyle(
color: Colors.grey,
fontSize: 16,
),
@@ -119,7 +119,7 @@ class _CitaScreenState extends State<CitaScreen> {
Text(
textAlign: TextAlign.center,
'" ${widget.evento.description} "',
style: TextStyle(
style: const TextStyle(
color: Colors.grey, fontStyle: FontStyle.italic),
)
],
+9 -8
View File
@@ -120,14 +120,15 @@ class _HorarioScreenState extends State<HorarioScreen> {
Padding(
padding: const EdgeInsets.only(top: 30, bottom: 30),
child: PrimaryButtom(
onPressed: () async {
updateHorario().then((value) => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfilePro()),
));
},
label: 'Guardar'),
onPressed: () async {
updateHorario().then((value) => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfilePro()),
));
},
label: 'Guardar',
),
)
],
),
+49 -40
View File
@@ -11,7 +11,8 @@ import 'package:prosappco/src/screens/professional_info.dart';
import '../models/scores_model.dart';
class ProfessionalScreen extends StatefulWidget {
const ProfessionalScreen({super.key});
final String profession;
const ProfessionalScreen({super.key, required this.profession});
@override
State<ProfessionalScreen> createState() => _ProfessionalScreenState();
@@ -24,6 +25,7 @@ final CollectionReference usersCollection =
var _photo = '...';
class Professional {
final String id;
final Reference professionalRef;
final String name;
final String professionName;
@@ -33,6 +35,7 @@ class Professional {
final ScoresModel scores;
Professional({
required this.id,
required this.professionalRef,
required this.name,
required this.professionName,
@@ -78,6 +81,7 @@ class Professional {
.toList();
Professional professional = Professional(
id: user.id,
name: data['name'],
professionName: data['profesion'],
cityName: data['city'],
@@ -95,44 +99,6 @@ class Professional {
}
}
Future<List<Professional>> getProfessionals() async {
List<Professional> professionals = [];
try {
QuerySnapshot users = await usersCollection.get();
for (DocumentSnapshot user in users.docs) {
// Acceder a los datos de cada usuario
Map<String, dynamic> data = user.data() as Map<String, dynamic>;
// Crear un objeto Professional a partir de los datos del usuario
_photo = await AuthenticationRepository.instance.getPhoto(user.id);
if (data['estado'] == 'activo') {
List<String> especializaciones;
especializaciones = (data['especializaciones'] as List<dynamic>)
.map((e) => e.toString())
.toList();
Professional professional = Professional(
name: data['name'],
professionName: data['profesion'],
cityName: data['city'],
professionalRef: storage.ref().child(_photo),
professionalEspecializado: especializaciones,
ubicacion: data['ubicacion'] ?? '',
scores: await ScoresModel.scoreTo(user.id, true, true),
);
professionals.add(professional);
}
}
} catch (e) {
print('Error al obtener profesionales: $e');
}
return professionals;
}
class _ProfessionalScreenState extends State<ProfessionalScreen> {
List<Professional>? filteredProfessionals;
@@ -141,9 +107,52 @@ class _ProfessionalScreenState extends State<ProfessionalScreen> {
final uid = AuthenticationRepository.instance.getCurrentUserUid();
List<Professional>? _professionals;
Future<List<Professional>> getProfessionals() async {
List<Professional> professionals = [];
try {
QuerySnapshot users = await usersCollection.get();
for (DocumentSnapshot user in users.docs) {
// Acceder a los datos de cada usuario
Map<String, dynamic> data = user.data() as Map<String, dynamic>;
// Crear un objeto Professional a partir de los datos del usuario
_photo = await AuthenticationRepository.instance.getPhoto(user.id);
if (data['estado'] == 'activo') {
List<String> especializaciones;
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'] ?? '',
scores: await ScoresModel.scoreTo(user.id, true, true),
);
professionals.add(professional);
}
}
}
} catch (e) {
print('Error al obtener profesionales: $e');
}
return professionals;
}
@override
void initState() {
super.initState();
searchController.addListener(() {
setState(() {
if (_professionals != null) {
@@ -257,7 +266,7 @@ class _ProfessionalScreenState extends State<ProfessionalScreen> {
),
),
onTap: () {
// Navigator.pop(context, professionals[index]);
Navigator.pop(context, professionals[index]);
},
);
},
+87 -50
View File
@@ -1,4 +1,4 @@
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
@@ -10,8 +10,11 @@ import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:prosappco/src/authentication/authentication_repository.dart';
import 'package:prosappco/src/components/drawer_menu.dart';
import 'package:prosappco/src/models/event_model.dart';
import 'package:prosappco/src/models/user_model.dart';
import 'package:prosappco/src/screens/professional.dart';
import 'package:intl/intl.dart';
import 'package:prosappco/src/screens/service_type.dart';
class ServiceScreen extends StatefulWidget {
const ServiceScreen({super.key});
@@ -21,9 +24,16 @@ class ServiceScreen extends StatefulWidget {
}
class _ServiceScreenState extends State<ServiceScreen> {
EventoService eventoService = EventoService();
final TextEditingController _locationController = TextEditingController();
final String _locationPosition = '';
final _profesionalController = TextEditingController();
final _serviceTypeController = TextEditingController();
final _observacionController = TextEditingController();
var professionalId = '';
String _serviceType = 'Servicio';
String _professional = '';
final DateFormat formatter = DateFormat('dd/MM/yyyy');
final DateTime now = DateTime.now();
@@ -32,7 +42,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
late GoogleMapController googleMapController;
static const CameraPosition initialCameraPosition = CameraPosition(
static CameraPosition initialCameraPosition = const CameraPosition(
target: LatLng(7.8939100, -72.5078200),
zoom: 14.4746,
);
@@ -130,9 +140,6 @@ class _ServiceScreenState extends State<ServiceScreen> {
@override
Widget build(BuildContext context) {
List<String> opc = ["Servicio", "Opción 1", "Opción 2", "Opción 3"];
String defaultValue = opc[0];
return SafeArea(
child: Scaffold(
backgroundColor: const Color(0xFFD6F4FF),
@@ -218,7 +225,7 @@ class _ServiceScreenState extends State<ServiceScreen> {
// markers.clear();
// markers.add(Marker(
// markerId: const MarkerId('currentLocation'),
// markerId: MarkerId('currentLocation'),
// position:
// LatLng(position.latitude, position.longitude)));
},
@@ -254,54 +261,56 @@ class _ServiceScreenState extends State<ServiceScreen> {
),
Padding(
padding:
const EdgeInsets.only(top: 23, left: 100, right: 25),
const EdgeInsets.only(top: 22, left: 100, right: 25),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.4),
spreadRadius: 1,
blurRadius: 2,
offset: const Offset(
1, 2), // changes position of shadow
offset: const Offset(1, 2),
),
],
),
child: DropdownButtonFormField(
value: defaultValue,
elevation: 0,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: BorderSide.none,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
onTap: () async {
final String? serviceType = await Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ServiceTypeScreen();
},
),
) as String?;
if (serviceType != null) {
setState(() {
_serviceType = serviceType;
_serviceTypeController.text = _serviceType;
});
}
},
controller: _serviceTypeController,
style: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w600,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: BorderSide.none,
readOnly: true,
decoration: InputDecoration(
hintText:
_serviceType == '' ? 'Servicio' : _serviceType,
hintStyle: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.w600),
border: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
items: opc.map((e) {
return DropdownMenuItem(
value: e,
child: Text(
e,
style:
const TextStyle(fontWeight: FontWeight.bold),
),
);
}).toList(),
onChanged: (value) {
print(value);
},
),
),
),
@@ -319,29 +328,35 @@ class _ServiceScreenState extends State<ServiceScreen> {
child: Column(
children: [
TextFormField(
readOnly: true,
controller: _locationController,
decoration: const InputDecoration(
prefixIcon: Icon(Icons.near_me),
hintText: 'Dirección'),
prefixIcon: Icon(Icons.near_me),
hintText: 'Dirección',
),
),
const SizedBox(height: 15),
TextFormField(
// controller: _cedulaController,
controller: _profesionalController,
readOnly: true,
onTap: () async {
final String? profesional =
final Professional? profesional =
await Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext context) {
return const ProfessionalScreen();
return ProfessionalScreen(
profession: _serviceTypeController.text,
);
},
),
) as String?;
);
if (profesional != null) {
setState(() {
// _profession = profesional;
_profesionalController.text =
profesional.name.toString();
professionalId = profesional.id;
});
}
},
@@ -396,14 +411,36 @@ class _ServiceScreenState extends State<ServiceScreen> {
),
const SizedBox(height: 15),
TextFormField(
// controller: _cedulaController,
controller: _observacionController,
decoration: const InputDecoration(
prefixIcon: Icon(Icons.message_outlined),
hintText: 'Observaciones'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
onPressed: () {
int tiempo2 = ((_selectedTime!.hour * 3600 +
_selectedTime!.minute * 60) +
7200) %
86400;
int hora2 = tiempo2 ~/ 3600;
int minutos2 = (tiempo2 % 3600) ~/ 60;
TimeOfDay time2 =
TimeOfDay(hour: hora2, minute: minutos2);
UserModel.getUser(uid.toString()).then((value) {
eventoService.createEvent(
value.name,
_observacionController.text,
'${_selectedDate}Z',
_selectedTime!.format(context),
time2.format(context),
professionalId,
);
});
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2BA4EC),
shape: RoundedRectangleBorder(
+101
View File
@@ -0,0 +1,101 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:diacritic/diacritic.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:prosappco/src/components/pop_appbar.dart';
import 'package:prosappco/src/screens/profession.dart';
import 'package:prosappco/src/screens/service.dart';
class ServiceTypeScreen extends StatefulWidget {
const ServiceTypeScreen({super.key});
@override
State<ServiceTypeScreen> createState() => _ServiceTypeScreenState();
}
class _ServiceTypeScreenState extends State<ServiceTypeScreen> {
List<String>? filteredProfessions;
TextEditingController searchController = TextEditingController();
List<String>? _professions;
@override
void initState() {
super.initState();
searchController.addListener(() {
setState(() {
if (_professions != null) {
if (searchController.text.isEmpty) {
filteredProfessions = _professions!;
} else {
filteredProfessions = _professions!
.where((profession) => removeDiacritics(profession)
.toLowerCase()
.contains(
removeDiacritics(searchController.text.toLowerCase())))
.toList();
}
}
});
});
if (_professions == null) {
getProfessions().then((List<String> element) => setState(() {
_professions = element;
filteredProfessions = element;
}));
}
}
@override
Widget build(BuildContext context) {
if (filteredProfessions == null) {
return const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFF2BA4EC)),
),
);
}
var professions = filteredProfessions!;
return Scaffold(
appBar: PopAppbar(
onPressed: () {
Navigator.pop(context);
},
label: 'Tipo de servicio'),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: TextField(
controller: searchController,
decoration: const InputDecoration(
hintText: 'Escribe el tipo de servicio',
prefixIcon: Icon(Icons.assignment_ind_rounded),
),
),
),
Expanded(
child: ListView.builder(
itemCount: professions.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
professions[index],
style: const TextStyle(
fontSize: 18.0,
color: Colors.black,
),
),
onTap: () {
Navigator.pop(context, professions[index]);
},
);
},
),
),
],
),
);
}
}