diff --git a/lib/main.dart b/lib/main.dart index 72673ce..612a42d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/presentation/screens/service_web.dart'; import 'package:prosappco/src/providers/user_provider.dart'; import 'package:prosappco/src/presentation/screens/calendar.dart'; import 'package:prosappco/src/presentation/screens/city.dart'; @@ -117,6 +118,7 @@ class MyApp extends StatelessWidget { '/solicitudEnviada': (context) => const RequestSentScreen(), '/nuevaPassword': (context) => NewPasswordScreen(), '/servicio': (context) => const ServiceScreen(), + '/servicioWeb': (context) => const ServiceWebScreen(), '/profilePro': (context) => const ProfileProScreen(), '/calendar': (context) => const CalendarScreen(), '/solicitud': (context) => SolicitudScreen(), diff --git a/lib/src/authentication/authentication_repository.dart b/lib/src/authentication/authentication_repository.dart index 743da19..4344e1c 100644 --- a/lib/src/authentication/authentication_repository.dart +++ b/lib/src/authentication/authentication_repository.dart @@ -1,11 +1,13 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:prosappco/src/authentication/exceptions/register_failed.dart'; import 'package:prosappco/src/presentation/screens/login/login.dart'; // import 'package:prosappco/src/presentation/screens/service.dart'; import 'package:prosappco/src/presentation/screens/map/service.dart'; +import 'package:prosappco/src/presentation/screens/service_web.dart'; class AuthenticationRepository extends GetxController { static AuthenticationRepository get instance => Get.find(); @@ -29,7 +31,9 @@ class AuthenticationRepository extends GetxController { _setInitialScreen(User? user) { user == null ? Get.offAll(const LoginScreen()) - : Get.offAll(const ServiceScreen()); + : kIsWeb + ? Get.offAll(const ServiceWebScreen()) + : Get.offAll(const ServiceScreen()); } Future phoneAuthentication(String phoneNo) async { @@ -79,7 +83,9 @@ class AuthenticationRepository extends GetxController { email: email, password: password); firebaseUser.value != null - ? Get.offAll(const ServiceScreen()) + ? kIsWeb + ? Get.offAll(const ServiceWebScreen()) + : Get.to(const ServiceScreen()) : Get.to(const LoginScreen()); } on FirebaseAuthException catch (e) { final ex = SignUpWithEmailAndPasswordFailure.code(e.code); @@ -140,7 +146,9 @@ class AuthenticationRepository extends GetxController { // Continúa con el flujo de la aplicación después del inicio de sesión exitoso // Por ejemplo, redirecciona a la siguiente pantalla firebaseUser.value != null - ? Get.offAll(const ServiceScreen()) + ? kIsWeb + ? Get.offAll(const ServiceWebScreen()) + : Get.to(const ServiceScreen()) : Get.to(const LoginScreen()); } else { // El usuario canceló el inicio de sesión con Google @@ -208,8 +216,6 @@ class AuthenticationRepository extends GetxController { await FirebaseFirestore.instance.collection('users').doc(uid).get(); final Map? data = snapshot.data(); birthDate = data?['birth_date'] ?? ''; - - print('nada $birthDate'); } catch (e) { print('Error getting birthDate: $e'); } diff --git a/lib/src/controllers/otp_controller.dart b/lib/src/controllers/otp_controller.dart index 87883be..6819caa 100644 --- a/lib/src/controllers/otp_controller.dart +++ b/lib/src/controllers/otp_controller.dart @@ -1,13 +1,19 @@ +import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; // import 'package:prosappco/src/presentation/screens/service.dart'; import 'package:prosappco/src/presentation/screens/map/service.dart'; +import 'package:prosappco/src/presentation/screens/service_web.dart'; class OTPController extends GetxController { static OTPController get instance => Get.find(); Future verifyOTP(String otp) async { var isVerified = AuthenticationRepository.instance.verifyOTP(otp); - await isVerified ? Get.offAll(const ServiceScreen()) : Get.back(); + await isVerified + ? kIsWeb + ? Get.offAll(const ServiceWebScreen()) + : Get.to(const ServiceScreen()) + : Get.back(); } } diff --git a/lib/src/presentation/screens/map/service.dart b/lib/src/presentation/screens/map/service.dart index ae4ad40..877b79b 100644 --- a/lib/src/presentation/screens/map/service.dart +++ b/lib/src/presentation/screens/map/service.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; @@ -40,6 +41,8 @@ class _ServiceScreenState extends State { late String appVersion; final Uri _url = Uri.parse( 'https://play.google.com/store/apps/details?id=com.prosapp.prosapp'); + final Uri _urlIos = + Uri.parse('https://apps.apple.com/co/app/prosapp/id6469028900'); final Location _locationController = Location(); @@ -958,7 +961,11 @@ class _ServiceScreenState extends State { TextStyle(fontWeight: FontWeight.w600, fontSize: 20), ), onPressed: () { - launchUrl(_url); + if (Platform.isAndroid) { + launchUrl(_url); + } else { + launchUrl(_urlIos); + } }, ), ], diff --git a/lib/src/presentation/screens/profile/profile.dart b/lib/src/presentation/screens/profile/profile.dart index 4d0cec8..5abacc1 100644 --- a/lib/src/presentation/screens/profile/profile.dart +++ b/lib/src/presentation/screens/profile/profile.dart @@ -2,6 +2,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/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dart:io'; @@ -21,6 +22,7 @@ import 'package:prosappco/src/presentation/widgets/profile/gender_dropdown.dart' import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart'; import 'package:provider/provider.dart'; import '../../../components/photo_view.dart'; +import 'package:universal_html/html.dart' as html; class ProfileScreen extends StatefulWidget { const ProfileScreen({Key? key}) : super(key: key); @@ -302,6 +304,18 @@ class _ProfileScreenState extends State { } } + String? selectedCity = _ciudad; + + if (kIsWeb) { + try { + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'city': selectedCity, + }); + } catch (e) { + print('Error al actualizar la ciudad: $e'); + } + } + if (enableLoginWithEmail) { if (currentUser?.email != newEmail) { if (newPassword.isNotEmpty) { @@ -342,7 +356,6 @@ class _ProfileScreenState extends State { } else { final uploaded = await uploadImage(imagen_to_upload!); updateImage(photoTemp); - //image } } catch (e) { print('Error al actualizar la imagen de perfil $e'); @@ -428,8 +441,6 @@ class _ProfileScreenState extends State { message: 'Verifica tu contraseña actual y asegúrate de que el nuevo correo electrónico no se haya utilizado previamente.', ); - - print('Error al actualizar el correo electrónico: $e'); } } @@ -497,9 +508,10 @@ class _ProfileScreenState extends State { return true; } catch (e) { WarningSnackbar.show( - title: 'Inicia sesión de nuevo', - message: - 'Para agregar un correo debes haber iniciado sesión recientemente.'); + title: 'Inicia sesión de nuevo', + message: 'Inicia la sesión de nuevo para guardar los cambios.', + ); + AuthenticationRepository.instance.logout(uid!); } } return false; @@ -507,6 +519,42 @@ class _ProfileScreenState extends State { bool enableLoginWithEmail = false; + Future> _getCities() async { + List citys = []; + if (kIsWeb) { + try { + QuerySnapshot countries = await countriesCollection.get(); + for (DocumentSnapshot country in countries.docs) { + String countryName = country.id; + Map data = country.data() as Map; + Map> states = {}; + + for (var entry in data.entries) { + String key = entry.key; + Map cityData = + Map.from(entry.value); + states[key] = cityData; + } + + for (var state in states.entries) { + var citysState = state.value.entries.map((city) => City( + cityName: city.key, + coordsOfCity: city.value, + stateOfCity: state.key, + countryOfCity: countryName, + )); + + citys.addAll(citysState); + } + } + } catch (e) { + print('Error obteniendo las ciudades: $e'); + } + } + + return citys; + } + Future _showChoiceDialog(BuildContext context) async { return showDialog( context: context, @@ -560,10 +608,11 @@ class _ProfileScreenState extends State { return Scaffold( appBar: PopAppbar( - onPressed: () { - Navigator.pop(context); - }, - label: 'Perfil'), + onPressed: () { + Navigator.pop(context); + }, + label: 'Perfil', + ), body: SingleChildScrollView( reverse: true, child: Center( @@ -599,37 +648,76 @@ class _ProfileScreenState extends State { return null; }, decoration: const InputDecoration( - prefixIcon: Icon(Icons.person_outline), - hintText: 'Nombre (Obligatorio)'), - ), - const SizedBox(), - TextFormField( - readOnly: true, - onTap: () async { - final String? ciudad = await Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const CityScreen(); - }, - ), - ) as String?; - - if (ciudad != null) { - setState(() { - _ciudad = ciudad; - }); - } - }, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.near_me), - suffixIcon: const Icon(Icons.arrow_drop_down), - hintStyle: city == '' - ? const TextStyle() - : const TextStyle(color: Colors.black87), - hintText: city == '' ? 'Ciudad' : city, + prefixIcon: Icon(Icons.person_outline), + hintText: 'Nombre (Obligatorio)', ), ), + const SizedBox(), + kIsWeb + ? FutureBuilder>( + future: _getCities(), + builder: (context, snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.hasError) { + return const Center( + child: + Text('Error al obtener las ciudades'), + ); + } else { + List filteredCities = snapshot.data!; + + return DropdownButtonFormField( + value: _ciudad, + onChanged: (String? newValue) { + setState(() { + _ciudad = newValue!; + }); + }, + items: filteredCities.map((City city) { + return DropdownMenuItem( + value: city.cityName, + child: Text(city.cityName ?? ''), + ); + }).toList(), + decoration: InputDecoration( + prefixIcon: const Icon(Icons.near_me), + hintText: _ciudad, + ), + ); + } + }, + ) + : TextFormField( + readOnly: true, + onTap: () async { + final String? ciudad = await Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const CityScreen(); + }, + ), + ) as String?; + + if (ciudad != null) { + setState(() { + _ciudad = ciudad; + }); + } + }, + decoration: InputDecoration( + prefixIcon: const Icon(Icons.near_me), + suffixIcon: const Icon(Icons.arrow_drop_down), + hintStyle: city == '' + ? const TextStyle() + : const TextStyle(color: Colors.black87), + hintText: city == '' ? 'Ciudad' : city, + ), + ), const SizedBox(height: 20.0), TextFormField( controller: _phoneNumberController, @@ -732,8 +820,9 @@ class _ProfileScreenState extends State { } }, decoration: const InputDecoration( - prefixIcon: Icon(Icons.email_outlined), - hintText: 'Email'), + prefixIcon: Icon(Icons.email_outlined), + hintText: 'Email', + ), ), const SizedBox(height: 20.0), _email != null @@ -777,6 +866,47 @@ class _ProfileScreenState extends State { _email != null ? const SizedBox.shrink() : const SizedBox(height: 20), + Container( + margin: const EdgeInsets.only( + left: 5, + right: 5, + top: 5, + bottom: 5, + ), + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 8), + decoration: BoxDecoration( + color: const Color(0xFFD6F4FF), + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(1, 3), + ), + ], + ), + child: const Row( + children: [ + Icon( + Icons.error_outline, + size: 20, + color: Colors.black54, + ), + SizedBox(width: 10), + Expanded( + child: Text( + 'Al habilitar el inicio de sesión con correo, se cerrara la sesión actual.', + style: TextStyle( + color: Colors.black54, + fontSize: 13, + ), + ), + ), + ], + ), + ) ], ), ) @@ -808,11 +938,17 @@ class _ProfileScreenState extends State { minHeight: 45, ) : const SizedBox(height: 20), - const SizedBox(height: 60), + const SizedBox(height: 40), PrimaryButton( onPressed: () async { if (_formKey.currentState!.validate()) { - await updateInfo(); + if (kIsWeb) { + await updateInfo().whenComplete(() { + html.window.location.reload(); + }); + } else { + await updateInfo(); + } } await userProvider.updateUserDataAndScores(); diff --git a/lib/src/presentation/screens/profile/profile_web.dart b/lib/src/presentation/screens/profile/profile_web.dart deleted file mode 100644 index a2b0f8e..0000000 --- a/lib/src/presentation/screens/profile/profile_web.dart +++ /dev/null @@ -1,628 +0,0 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:get/get.dart'; -import 'package:intl/intl.dart'; -import 'package:firebase_storage/firebase_storage.dart'; -import 'package:flutter/material.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/foundation.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:prosappco/src/authentication/authentication_repository.dart'; -import 'package:prosappco/src/components/photo_view_web.dart'; -import 'package:prosappco/src/components/pop_appbar.dart'; -import 'package:prosappco/src/presentation/screens/city.dart'; -import 'package:prosappco/src/presentation/screens/new_number.dart'; -import 'package:prosappco/src/presentation/screens/new_password.dart'; -import 'package:universal_html/html.dart' as html; - -class ProfileWebScreen extends StatefulWidget { - const ProfileWebScreen({super.key}); - - @override - State createState() => _ProfileWebScreenState(); -} - -class _ProfileWebScreenState extends State { - final uid = AuthenticationRepository.instance.getCurrentUserUid(); - final FirebaseStorage storage = FirebaseStorage.instance; - late final FirebaseAuth _auth; - List? filteredCities; - - // variables imagen - String selectedImage = ''; - XFile? file; - Uint8List? selectedImagInBytes; - String photoTemp = ''; - - // controladores - final _formKey = GlobalKey(); - final TextEditingController _nameController = TextEditingController(); - final TextEditingController _emailController = TextEditingController(); - final TextEditingController _phoneNumberController = TextEditingController(); - final TextEditingController _passwordController = TextEditingController(); - bool _obscureText = true; - - // variables - String _ciudad = '...'; - String _photo = '...'; - String? _email = ''; - - @override - void initState() { - super.initState(); - - final uid = AuthenticationRepository.instance.getCurrentUserUid(); - _auth = FirebaseAuth.instance; - - final currentUser = _auth.currentUser; - - if (currentUser != null && currentUser.phoneNumber != null) { - _phoneNumberController.text = currentUser.phoneNumber!; - } - - if (currentUser != null && currentUser.displayName != null) { - _nameController.text = currentUser.displayName!; - } - if (currentUser != null && currentUser.email != null) { - _emailController.text = currentUser.email!; - } - - _email = currentUser?.email; - - if (_ciudad == '...') { - AuthenticationRepository.instance - .getCity(uid.toString()) - .then((String s) => setState(() { - _ciudad = s; - })); - } - - if (_photo == '...') { - AuthenticationRepository.instance - .getPhoto(uid.toString()) - .then((String s) => setState(() { - _photo = s; - })); - } - } - - _selectFile(bool imageFrom) async { - FilePickerResult? fileResult = await FilePicker.platform.pickFiles(); - - if (fileResult != null) { - setState(() { - selectedImage = fileResult.files.first.name; - selectedImagInBytes = fileResult.files.first.bytes; - }); - } - } - - _uploadFile() async { - try { - final now = DateTime.now(); - final formattedDate = DateFormat('HHmmssddMMyyyy').format(now); - final milliseconds = (now.microsecondsSinceEpoch / 1000).round(); - final random = '$formattedDate$milliseconds'; - - final Reference ref = FirebaseStorage.instance - .ref() - .child('users') - .child(uid!) - .child('profile') - .child(random); - - final metaData = SettableMetadata(contentType: 'image/jpeg'); - - final UploadTask uploadTask = ref.putData(selectedImagInBytes!, metaData); - - final TaskSnapshot snapshot = await uploadTask.whenComplete(() => true); - - photoTemp = ref.fullPath; - - if (snapshot.state == TaskState.success) { - return true; - } else { - return false; - } - } catch (e) { - print('web image error - $e'); - } - } - - Future updateInfo() async { - final currentUser = _auth.currentUser; - final currentPhoneNumber = _auth.currentUser!.phoneNumber; - - String newName = _nameController.text.trim(); - String newEmail = _emailController.text.trim(); - String newPassword = _passwordController.text.trim(); - - if (newName.isEmpty) { - // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario - Get.snackbar( - 'Nombre Invalido', - 'Ingresa un nombre válido.', - snackPosition: SnackPosition.BOTTOM, - ); - return; - } else { - try { - await FirebaseAuth.instance.currentUser!.updateDisplayName(newName); - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'name': newName, - 'lowerName': newName.toLowerCase(), - }); - } catch (e) { - print('Error al actualizar el nombre: $e'); - } - } - if (newEmail.isEmpty) { - // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario - Get.snackbar( - 'Correo Invalido', - 'Ingresa un email válido.', - snackPosition: SnackPosition.BOTTOM, - ); - return; - } - - try { - await FirebaseAuth.instance.currentUser!.updateDisplayName(newName); - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'name': newName, - 'lowerName': newName.toLowerCase(), - }); - } catch (e) { - print('Error al actualizar el nombre: $e'); - } - - if (currentUser?.email != newEmail) { - if (newPassword.isNotEmpty) { - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'email': newEmail, - }); - updateEmailAndPassword(newEmail, newPassword); - } else { - Get.snackbar( - 'Contraseña Invalida', - 'Por favor, ingresa una contraseña.', - snackPosition: SnackPosition.BOTTOM, - ); - } - } - - String? selectedCity = _ciudad; - - // Guardar la ciudad seleccionada en el documento del usuario - try { - await FirebaseFirestore.instance.collection('users').doc(uid).update({ - 'city': selectedCity, - }); - } catch (e) { - print('Error al actualizar la ciudad: $e'); - } - - try { - await FirebaseFirestore.instance - .collection('users') - .doc(uid) - .update({'phoneNumber': currentPhoneNumber}); - } catch (e) { - print('e'); - } - - try { - await FirebaseFirestore.instance - .collection('users') - .doc(uid) - .update({'email': newEmail}); - } catch (e) { - print('e'); - } - - try { - if (selectedImagInBytes == null) { - return; - } else { - await _uploadFile(); - updateImage(photoTemp); - } - } catch (e) { - print('Error al actualizar la imagen de perfil $e'); - } - } - - Future updateImage(image) async { - try { - await FirebaseFirestore.instance - .collection('users') - .doc(uid) - .update({'photo': image}); - } catch (e) { - try { - await FirebaseFirestore.instance - .collection('users') - .doc(uid) - .set({'photo': image}); - } catch (e) { - print('Error al agregar la imagen de perfil: $e'); - } - - print('Error al actualizar la imagen de perfil: $e'); - } - } - - Future updateEmailAndPassword(String email, String password) async { - final User? user = FirebaseAuth.instance.currentUser; - if (user != null) { - try { - await user.updateEmail(email); - await user.updatePassword(password); - } catch (e) { - Get.snackbar( - 'Agregar correo', - 'Inicia sesión para asegurarnos de que seas tú.', - snackPosition: SnackPosition.BOTTOM, - ); - AuthenticationRepository.instance.logout(uid!); - } - } - } - - Future> _getCities() async { - List citys = []; - try { - QuerySnapshot countries = await countriesCollection.get(); - for (DocumentSnapshot country in countries.docs) { - String countryName = country.id; - Map data = country.data() as Map; - Map> states = {}; - - for (var entry in data.entries) { - String key = entry.key; - Map cityData = Map.from(entry.value); - states[key] = cityData; - } - - for (var state in states.entries) { - var citysState = state.value.entries.map((city) => City( - cityName: city.key, - coordsOfCity: city.value, - stateOfCity: state.key, - countryOfCity: countryName, - )); - - citys.addAll(citysState); - } - } - } catch (e) { - print('Error obteniendo las ciudades: $e'); - } - return citys; - } - - Future _showEmailUpdateDialog(BuildContext context) async { - TextEditingController emailController = TextEditingController(); - String currentEmail = FirebaseAuth.instance.currentUser?.email ?? ''; - - await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Actualizar Correo Electrónico'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextFormField( - controller: emailController, - decoration: const InputDecoration( - labelText: 'Nuevo Correo Electrónico', - ), - ), - ], - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Cancelar'), - ), - ElevatedButton( - onPressed: () async { - String newEmail = emailController.text.trim(); - if (newEmail.isNotEmpty && newEmail != currentEmail) { - // Actualiza el correo electrónico aquí - try { - await FirebaseAuth.instance.currentUser - ?.updateEmail(newEmail); - await FirebaseFirestore.instance - .collection('users') - .doc(FirebaseAuth.instance.currentUser?.uid) - .update({'email': newEmail}); - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Correo Electrónico actualizado con éxito'), - ), - ); - } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Error al actualizar el correo electrónico'), - ), - ); - } - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Ingresa un nuevo correo electrónico válido'), - ), - ); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.blue, - ), - child: const Text('Guardar'), - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFD6F4FF), - appBar: PopAppbar( - onPressed: () { - Navigator.pop(context); - }, - label: 'Perfil'), - body: Center( - child: SizedBox( - width: 300, - height: 680, - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - color: Colors.white, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.only(top: 20, bottom: 20), - child: (selectedImagInBytes != null) - ? LocalPhotoWeb(file: selectedImagInBytes) - : ReferencePhotoWeb(ref: storage.ref().child(_photo)), - ), - TextFormField( - controller: _nameController, - maxLength: 50, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Porfavor ingrese un nombre.'; - } - if (value.length < 5) { - return 'Debe tener al menos 5 caracteres.'; - } - return null; - }, - decoration: const InputDecoration( - prefixIcon: Icon(Icons.person_outline), - hintText: 'Nombre (Obligatorio)', - ), - ), - _email != null - ? TextFormField( - onTap: () { - _showEmailUpdateDialog(context); - }, - readOnly: true, - controller: _emailController, - decoration: const InputDecoration( - prefixIcon: Icon(Icons.email_outlined), - hintText: 'Email (Obligatorio)', - ), - ) - : TextFormField( - controller: _emailController, - validator: (String? value) { - if (value == null || value.isEmpty) { - return 'Por favor ingrese un email'; - } - final RegExp emailRegExp = - RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); - if (!emailRegExp.hasMatch(value)) { - return 'Por favor ingrese un email válido'; - } - return null; - }, - decoration: const InputDecoration( - prefixIcon: Icon(Icons.email_outlined), - hintText: 'Email (Obligatorio)', - ), - ), - const SizedBox(height: 20.0), - _email != null - ? const SizedBox.shrink() - : TextFormField( - controller: _passwordController, - obscureText: _obscureText, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Porfavor ingrese una contraseña.'; - } - if (value.length < 5) { - return 'Debe tener al menos 5 caracteres.'; - } - return null; - }, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.lock_outline), - suffixIcon: IconButton( - icon: Icon( - _obscureText - ? Icons.visibility - : Icons.visibility_off, - color: Colors.grey, - ), - onPressed: () { - setState(() { - _obscureText = !_obscureText; - }); - }, - ), - hintText: 'Contraseña (Obligatorio)', - ), - ), - _email != null - ? const SizedBox.shrink() - : const SizedBox(height: 20.0), - FutureBuilder>( - future: _getCities(), - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.waiting) { - return const Center( - child: CircularProgressIndicator(), - ); - } else if (snapshot.hasError) { - return const Center( - child: Text('Error al obtener las ciudades'), - ); - } else { - List filteredCities = snapshot.data!; - - return DropdownButtonFormField( - value: _ciudad, - onChanged: (String? newValue) { - setState(() { - _ciudad = newValue!; - }); - }, - items: filteredCities.map((City city) { - return DropdownMenuItem( - value: city.cityName, - child: Text(city.cityName ?? ''), - ); - }).toList(), - decoration: InputDecoration( - prefixIcon: const Icon(Icons.near_me), - hintText: _ciudad, - ), - ); - } - }, - ), - const SizedBox(height: 20.0), - TextFormField( - controller: _phoneNumberController, - readOnly: true, - onTap: () { - Navigator.of(context).push( - CupertinoPageRoute( - builder: (BuildContext context) { - return const NewNumberScreen(); - }, - ), - ); - }, - decoration: const InputDecoration( - prefixIcon: Icon(Icons.phone_android), - suffixIcon: Icon(Icons.edit_outlined), - hintText: '+57'), - ), - Container( - alignment: Alignment.bottomCenter, - margin: const EdgeInsets.only(top: 30), - padding: const EdgeInsets.only(bottom: 30), - child: Column( - children: [ - _email != null - ? ElevatedButton( - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return NewPasswordScreen(); - }, - ), - ); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF2BA4EC), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - elevation: 0, - minimumSize: const Size(300, 45), - ), - child: const Text( - 'Cambiar Contraseña', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 17, - ), - ), - ) - : const SizedBox(height: 20), - const SizedBox(height: 60), - ElevatedButton( - onPressed: () async { - if (_formKey.currentState!.validate()) { - await updateInfo().whenComplete(() { - html.window.location.reload(); - - Get.snackbar( - 'Perfil', - 'Información actualizada correctamente.', - snackPosition: SnackPosition.TOP, - ); - }); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF2BA4EC), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(50), - ), - elevation: 0, - minimumSize: const Size(200, 50), - ), - child: const Text( - 'Guardar', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 17, - ), - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/lib/src/presentation/screens/service_after.dart b/lib/src/presentation/screens/service_after.dart index a69b6eb..e8e4e8b 100644 --- a/lib/src/presentation/screens/service_after.dart +++ b/lib/src/presentation/screens/service_after.dart @@ -1,4 +1,5 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:intl/intl.dart'; @@ -9,6 +10,7 @@ import 'package:prosappco/src/models/scores_model.dart'; import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/presentation/screens/map/service.dart'; +import 'package:prosappco/src/presentation/screens/service_web.dart'; class ServiceAfterScreen extends StatefulWidget { var eventoId; @@ -66,14 +68,23 @@ class _ServiceAfterScreenState extends State { return Scaffold( appBar: PopAppbar( onPressed: () { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ServiceScreen(); - }, - ), - ); + kIsWeb + ? Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ServiceWebScreen(); + }, + ), + ) + : Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ServiceScreen(); + }, + ), + ); }, label: 'Servicio'), body: Column( diff --git a/lib/src/presentation/screens/service_web.dart b/lib/src/presentation/screens/service_web.dart index f418313..a8ed3ea 100644 --- a/lib/src/presentation/screens/service_web.dart +++ b/lib/src/presentation/screens/service_web.dart @@ -3,31 +3,24 @@ import 'package:cloud_firestore/cloud_firestore.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'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; -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/presentation/screens/profile/profile.dart'; import 'package:prosappco/src/presentation/widgets/shared/drawer_menu.dart'; import 'package:prosappco/src/models/event_model.dart'; -import 'package:prosappco/src/models/setting_model.dart'; import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/presentation/screens/professional.dart'; import 'package:intl/intl.dart'; -import 'package:prosappco/src/presentation/screens/profile/profile.dart'; -import 'package:prosappco/src/presentation/screens/profile/profile_web.dart'; import 'package:prosappco/src/presentation/screens/service_after.dart'; -import 'package:prosappco/src/presentation/screens/service_type.dart'; import 'package:prosappco/src/presentation/screens/ubicacion.dart'; import 'package:http/http.dart' as http; import 'package:prosappco/src/components/network_utility.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:prosappco/src/presentation/widgets/shared/primary_button.dart'; import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:prosappco/src/providers/user_provider.dart'; +import 'package:provider/provider.dart'; class ServiceWebScreen extends StatefulWidget { const ServiceWebScreen({super.key}); @@ -199,7 +192,6 @@ class _ServiceOldScreenState extends State { final FirebaseStorage storage = FirebaseStorage.instance; final uid = AuthenticationRepository.instance.getCurrentUserUid(); - UserModel? user; final fcmToken = FirebaseMessaging.instance.getToken(); BitmapDescriptor? _markerIcon; @@ -320,14 +312,6 @@ class _ServiceOldScreenState extends State { _saveToken(); - if (user == null) { - UserModel.getUser(uid.toString()).then((UserModel s) => (value) { - if (mounted) { - setState(() => user = s); - } - }); - } - BitmapDescriptor.fromAssetImage( const ImageConfiguration(size: Size(6, 6)), 'images/pro_marke.png') .then((icon) { @@ -401,6 +385,9 @@ class _ServiceOldScreenState extends State { @override Widget build(BuildContext context) { + final userProvider = Provider.of(context); + UserModel? user = userProvider.user; + return Scaffold( backgroundColor: const Color(0xFFD6F4FF), drawer: DrawerMenu(), @@ -516,10 +503,10 @@ class _ServiceOldScreenState extends State { if (_profesionalController.text.isNotEmpty) { _selectDate(context); } else { - Get.snackbar( - 'Selecciona un profesional', - 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', - snackPosition: SnackPosition.BOTTOM, + WarningSnackbar.show( + title: 'Selecciona un profesional', + message: + 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', ); } }, @@ -542,10 +529,10 @@ class _ServiceOldScreenState extends State { if (_profesionalController.text.isNotEmpty) { _selectTime(context); } else { - Get.snackbar( - 'Selecciona un profesional', - 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', - snackPosition: SnackPosition.BOTTOM, + WarningSnackbar.show( + title: 'Selecciona un profesional', + message: + 'Selecciona un profesional antes de elegir la fecha y la hora de la cita.', ); } }, @@ -578,7 +565,7 @@ class _ServiceOldScreenState extends State { context, CupertinoPageRoute( builder: (BuildContext context) { - return const ProfileWebScreen(); + return const ProfileScreen(); }, ), ); @@ -630,10 +617,9 @@ class _ServiceOldScreenState extends State { }); }); } catch (e) { - Get.snackbar( - 'Llena todos los campos', - 'Asegurate de llenar todos los campos.', - snackPosition: SnackPosition.BOTTOM, + WarningSnackbar.show( + title: 'Llena todos los campos', + message: 'Asegurate de llenar todos los campos.', ); } } diff --git a/lib/src/presentation/widgets/shared/drawer_menu.dart b/lib/src/presentation/widgets/shared/drawer_menu.dart index bc8cb5c..b776cf4 100644 --- a/lib/src/presentation/widgets/shared/drawer_menu.dart +++ b/lib/src/presentation/widgets/shared/drawer_menu.dart @@ -9,10 +9,8 @@ import 'package:prosappco/src/models/user_model.dart'; import 'package:prosappco/src/presentation/widgets/shared/warning_snackbar.dart'; import 'package:prosappco/src/providers/user_provider.dart'; import 'package:prosappco/src/presentation/screens/configuracion.dart'; -import 'package:prosappco/src/presentation/screens/messages_user.dart'; import 'package:prosappco/src/presentation/screens/professional_profile_web.dart'; import 'package:prosappco/src/presentation/screens/profile/profile.dart'; -import 'package:prosappco/src/presentation/screens/profile/profile_web.dart'; import 'package:prosappco/src/presentation/screens/reputation.dart'; import 'package:prosappco/src/presentation/screens/support.dart'; import 'package:prosappco/src/presentation/screens/web_view.dart'; @@ -91,25 +89,14 @@ class DrawerMenu extends StatelessWidget { ), ListTile( onTap: () { - if (kIsWeb) { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileWebScreen(); - }, - ), - ); - } else { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileScreen(); - }, - ), - ); - } + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ProfileScreen(); + }, + ), + ); }, leading: const Icon( Icons.person_outline, @@ -170,8 +157,9 @@ class DrawerMenu extends StatelessWidget { CupertinoPageRoute( builder: (BuildContext context) { return WebViewScreen( - label: 'Sugerencias', - link: 'https://admin.prosapp.co/sugerencias'); + label: 'Sugerencias', + link: 'https://admin.prosapp.co/sugerencias', + ); }, ), ); @@ -186,26 +174,6 @@ class DrawerMenu extends StatelessWidget { style: TextStyle(fontSize: 15), ), ), - // ListTile( - // onTap: () { - // Navigator.push( - // context, - // CupertinoPageRoute( - // builder: (BuildContext context) { - // return const MessagesUserScreen(); - // }, - // ), - // ); - // }, - // leading: const Icon( - // Icons.messenger_outline, - // color: Colors.black, - // ), - // title: const Text( - // 'Mensajes', - // style: TextStyle(fontSize: 15), - // ), - // ), Builder(builder: (BuildContext context) { return ListTile( onTap: () { @@ -406,25 +374,14 @@ class DrawerMenu extends StatelessWidget { ListTile infoUser(BuildContext context, UserModel? user) { return ListTile( onTap: () { - if (kIsWeb) { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileWebScreen(); - }, - ), - ); - } else { - Navigator.push( - context, - CupertinoPageRoute( - builder: (BuildContext context) { - return const ProfileScreen(); - }, - ), - ); - } + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const ProfileScreen(); + }, + ), + ); }, title: Text(user?.name ?? '', style: const TextStyle(fontWeight: FontWeight.bold)), diff --git a/web/index.html b/web/index.html index 8700331..8218344 100644 --- a/web/index.html +++ b/web/index.html @@ -63,6 +63,8 @@ }); - +