diff --git a/lib/main.dart b/lib/main.dart index a7cebba..5cb4e60 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:prosappco/src/screens/city.dart'; import 'package:prosappco/src/screens/login.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:prosappco/src/screens/login_email.dart'; +import 'package:prosappco/src/screens/new_number.dart'; import 'package:prosappco/src/screens/profile.dart'; import 'package:prosappco/src/screens/register.dart'; import 'package:prosappco/src/screens/welcome.dart'; @@ -35,6 +36,7 @@ class MyApp extends StatelessWidget { '/profile': (context) => ProfileScreen(), '/register': (context) => RegisterScreen(), '/city': (context) => CityScreen(), + '/newNumber': (context) => NewNumberScreen(), }, onGenerateRoute: (settings) { throw Exception('Ruta desconocida: ${settings.name}'); diff --git a/lib/src/authentication/authentication_repository.dart b/lib/src/authentication/authentication_repository.dart index a882a78..f2d7fdd 100644 --- a/lib/src/authentication/authentication_repository.dart +++ b/lib/src/authentication/authentication_repository.dart @@ -27,9 +27,7 @@ class AuthenticationRepository extends GetxController { } _setInitialScreen(User? user) { - user == null - ? Get.offAll(() => const LoginScreen()) - : Get.offAll(() => const WelcomeScreen()); + user == null ? Get.offAll(LoginScreen()) : Get.offAll(WelcomeScreen()); } Future phoneAuthentication(String phoneNo) async { @@ -76,8 +74,8 @@ class AuthenticationRepository extends GetxController { email: email, password: password); firebaseUser.value != null - ? Get.offAll(() => WelcomeScreen()) - : Get.to(() => LoginScreen()); + ? Get.offAll(WelcomeScreen()) + : Get.to(LoginScreen()); } on FirebaseAuthException catch (e) { final ex = SignUpWithEmailAndPasswordFailure.code(e.code); print('FIREBASE AUTH EXCEPTION - ${ex.message}'); @@ -122,36 +120,13 @@ class AuthenticationRepository extends GetxController { return user?.uid; } - Future addNameAndEmail( - uid, String name, String email, String city) async { - final usersCollection = FirebaseFirestore.instance.collection('users'); - await usersCollection.doc(uid).set({ - 'name': name, - 'email': email, - 'city': city, - }); - } - - Future getName(String uid) async { - String name = '...'; - try { - final snapshot = - await FirebaseFirestore.instance.collection('users').doc(uid).get(); - final Map? data = snapshot.data(); - name = data?['name'] ?? '...'; - } catch (e) { - print('Error getting name: $e'); - } - return name; - } - Future getCity(String uid) async { - String city = '...'; + String city = ''; try { final snapshot = await FirebaseFirestore.instance.collection('users').doc(uid).get(); final Map? data = snapshot.data(); - city = data?['city'] ?? '...'; + city = data?['city'] ?? ''; } catch (e) { print('Error getting city: $e'); } diff --git a/lib/src/screens/city.dart b/lib/src/screens/city.dart index 5d4df77..31d9875 100644 --- a/lib/src/screens/city.dart +++ b/lib/src/screens/city.dart @@ -1,5 +1,8 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:diacritic/diacritic.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; class CityScreen extends StatefulWidget { const CityScreen({super.key}); @@ -139,7 +142,6 @@ List cities = [ class City { final String name; - City({required this.name}); } @@ -147,7 +149,12 @@ List citiesList = cities.map((city) => City(name: city)).toList(); class _CityScreenState extends State { List filteredCities = citiesList; + TextEditingController searchController = TextEditingController(); + final User? user = FirebaseAuth.instance.currentUser; + late final FirebaseAuth _auth; + + final uid = AuthenticationRepository.instance.getCurrentUserUid(); @override void initState() { @@ -162,12 +169,40 @@ class _CityScreenState extends State { }); } + Future updateCity(String cityName) async { + try { + await FirebaseFirestore.instance + .collection('users') + .doc(uid) + .update({'city': cityName}); + + print('Ciudad actualizada correctamente'); + } catch (e) { + try { + await FirebaseFirestore.instance + .collection('users') + .doc(uid) + .set({'city': cityName}); + } catch (e) { + print('Error al agregar la ciudad: $e'); + } + + print('Error al actualizar la ciudad: $e'); + } + } + @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( appBar: AppBar( backgroundColor: Colors.white, + leading: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pushReplacementNamed(context, '/profile'); + }, + ), iconTheme: IconThemeData( color: Colors.black, ), @@ -196,7 +231,8 @@ class _CityScreenState extends State { return ListTile( title: Text(filteredCities[index].name), onTap: () { - print(filteredCities[index].name); + updateCity(filteredCities[index].name); + Navigator.pushReplacementNamed(context, '/profile'); }, ); }, diff --git a/lib/src/screens/new_number.dart b/lib/src/screens/new_number.dart new file mode 100644 index 0000000..a0b1fe7 --- /dev/null +++ b/lib/src/screens/new_number.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:intl_phone_field/intl_phone_field.dart'; + +class NewNumberScreen extends StatefulWidget { + const NewNumberScreen({super.key}); + + @override + State createState() => _NewNumberScreenState(); +} + +class _NewNumberScreenState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar( + backgroundColor: Colors.white, + iconTheme: IconThemeData( + color: Colors.black, + ), + title: Text( + 'Añadir numero', + style: TextStyle( + color: Colors.black, + ), + )), + body: Container( + padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 20), + margin: const EdgeInsets.only(top: 30, left: 50, right: 50), + child: Column(children: [ + const Padding( + padding: EdgeInsets.only(bottom: 5), + child: Align( + alignment: Alignment.topLeft, + child: Text('Numero de celular', + style: TextStyle(fontSize: 18.0, color: Color(0xFF65676B))), + )), + Form( + // key: _formKey, + child: Padding( + padding: EdgeInsets.only(bottom: 5), + child: IntlPhoneField( + // controller: controller.phoneNo, + initialCountryCode: 'CO', + // onChanged: (phoneNo) { + // completePhoneNumber = phoneNo.completeNumber; + // }, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFECECEC)), + borderRadius: BorderRadius.all( + Radius.circular(50), + )), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFECECEC)), + borderRadius: BorderRadius.all( + Radius.circular(50), + )), + fillColor: Color.fromARGB(255, 239, 239, 239), + filled: true, + ), + ), + ), + ), + const Padding( + padding: EdgeInsets.only(bottom: 30), + child: Text('Un código será enviado a este numero de celular.', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 13.0, color: Color(0xFF65676B))), + ), + Padding( + padding: EdgeInsets.only(bottom: 30), + child: Center( + child: ElevatedButton( + onPressed: () { + // if (_formKey.currentState!.validate()) { + // PhoneAuthController.instance.phoneAuthentication( + // completePhoneNumber.trim(), + // ); + // Get.to(() => const CodeValidationScreen()); + // } + }, + child: Text( + 'Enviar código', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + style: ElevatedButton.styleFrom( + primary: Color(0xFF2BA4EC), // Color del botón + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), // Bordes redondeados + ), + elevation: 0, + minimumSize: Size(230, 60), // Tamaño mínimo del botón + ), + )), + ), + ]), + ), + )); + } +} diff --git a/lib/src/screens/profile.dart b/lib/src/screens/profile.dart index fb8ed16..aae3030 100644 --- a/lib/src/screens/profile.dart +++ b/lib/src/screens/profile.dart @@ -1,3 +1,5 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl_phone_field/countries.dart'; @@ -6,7 +8,7 @@ import 'package:prosappco/src/controllers/add_name_email_city.dart'; import 'package:prosappco/src/screens/welcome.dart'; class ProfileScreen extends StatefulWidget { - const ProfileScreen({super.key}); + ProfileScreen({Key? key}) : super(key: key); @override State createState() => _ProfileScreenState(); @@ -16,20 +18,31 @@ class _ProfileScreenState extends State { final uid = AuthenticationRepository.instance.getCurrentUserUid(); final _formKey = GlobalKey(); final controller = Get.put(NameEmailCityController()); + final _phoneNumberController = TextEditingController(); + final _nameController = TextEditingController(); + final _emailController = TextEditingController(); + late final FirebaseAuth _auth; - var _nombre = '...'; var _ciudad = '...'; @override void initState() { super.initState(); - if (_nombre == '...') { - AuthenticationRepository.instance - .getName(uid.toString()) - .then((String s) => setState(() { - _nombre = s; - })); + _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!; + } + if (_ciudad == '...') { AuthenticationRepository.instance .getCity(uid.toString()) @@ -39,9 +52,73 @@ class _ProfileScreenState extends State { } } + Future updateInfo() async { + String newName = _nameController.text.trim(); + String newEmail = _emailController.text.trim(); + + if (newName.isEmpty) { + // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Ingrese un nombre válido')), + ); + return; + } + if (newEmail.isEmpty) { + // Si el nuevo nombre está vacío, no lo actualizamos y mostramos un mensaje al usuario + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Ingrese un email válido')), + ); + return; + } + + try { + await FirebaseAuth.instance.currentUser!.updateDisplayName(newName); + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'name': newName, + }); + print('Nombre actualizado correctamente'); + } catch (e) { + print('Error al actualizar el nombre: $e'); + } + + try { + await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'email': newEmail, + }); + print('Correo electrónico actualizado correctamente'); + } catch (e) { + print('Error al actualizar el correo electrónico: $e'); + } + + AuthCredential credential = + EmailAuthProvider.credential(email: newEmail, password: '654321'); + + try { + // Reautentica al usuario con las credenciales proporcionadas + await FirebaseAuth.instance.currentUser! + .reauthenticateWithCredential(credential); + + // Actualiza el correo electrónico del usuario + await FirebaseAuth.instance.currentUser!.updateEmail(newEmail); + + // Actualiza los datos del usuario en tu base de datos + await FirebaseFirestore.instance.collection('users').doc(uid).update({ + 'email': newEmail, + }); + + print('Correo electrónico actualizado correctamente'); + } catch (e) { + print('Error al actualizar el correo electrónico: $e'); + } + } + + @override Widget build(BuildContext context) { - String name = _nombre.toString(); + final User? user = FirebaseAuth.instance.currentUser; + String city = _ciudad.toString(); + return SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, @@ -70,15 +147,13 @@ class _ProfileScreenState extends State { onTap: () { Scaffold.of(context).openEndDrawer(); }, - title: Text('$name', + title: Text('${user?.displayName}', style: TextStyle(fontWeight: FontWeight.bold)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - AuthenticationRepository.instance - .getCurrentUserPhone() - .toString(), + '${user?.phoneNumber}', style: TextStyle(fontSize: 12), ), Text( @@ -287,7 +362,7 @@ class _ProfileScreenState extends State { child: Column( children: [ TextFormField( - controller: controller.name, + controller: _nameController, decoration: InputDecoration( prefixIcon: Icon(Icons.person_outline), hintText: 'Nombre'), @@ -297,7 +372,7 @@ class _ProfileScreenState extends State { 20.0), // Agrega espacio vertical entre los TextFormFields TextFormField( - controller: controller.email, + controller: _emailController, decoration: InputDecoration( prefixIcon: Icon(Icons.email_outlined), hintText: 'Email'), @@ -306,24 +381,26 @@ class _ProfileScreenState extends State { height: 20.0), // Agrega espacio vertical entre los TextFormFields TextFormField( - controller: controller.city, readOnly: true, onTap: () { - Navigator.pushNamed(context, '/city'); + Navigator.pushReplacementNamed(context, '/city'); }, decoration: InputDecoration( prefixIcon: Icon(Icons.near_me), suffixIcon: Icon(Icons.arrow_drop_down), - hintText: 'Ciudad', + hintText: city == '' ? 'Ciudad' : '$city', ), ), SizedBox( height: 20.0), // Agrega espacio vertical entre los TextFormFields - TextFormField( - controller: controller.name, + controller: _phoneNumberController, + readOnly: true, + onTap: () { + Navigator.pushNamed(context, '/newNumber'); + }, decoration: InputDecoration( prefixIcon: Icon(Icons.phone_android), suffixIcon: Icon(Icons.edit_outlined), @@ -337,12 +414,9 @@ class _ProfileScreenState extends State { margin: EdgeInsets.only(top: 170), child: ElevatedButton( onPressed: () { - // AuthenticationRepository.instance.addNameAndEmail( - // uid, - // controller.name.text.trim(), - // controller.email.text.trim(), - // controller.city.text.trim(), - // ); + String newName = _nameController.text; + String newEmail = _emailController.text; + updateInfo(); }, child: Text( 'Guardar', diff --git a/lib/src/screens/welcome.dart b/lib/src/screens/welcome.dart index 00e1ea6..38410be 100644 --- a/lib/src/screens/welcome.dart +++ b/lib/src/screens/welcome.dart @@ -18,33 +18,27 @@ class _WelcomeScreenState extends State { final _formKey = GlobalKey(); final controller = Get.put(NameEmailCityController()); var _nombre = '...'; - var _ciudad = '...'; + var _ciudad = ''; @override void initState() { super.initState(); - // if (_nombre == '...') { - // AuthenticationRepository.instance - // .getName(uid.toString()) - // .then((String s) => setState(() { - // _nombre = s; - // })); - // } - // if (_ciudad == '...') { - // AuthenticationRepository.instance - // .getCity(uid.toString()) - // .then((String s) => setState(() { - // _ciudad = s; - // })); - // } + + if (_ciudad == '') { + AuthenticationRepository.instance + .getCity(uid.toString()) + .then((String s) => setState(() { + _ciudad = s; + })); + } } @override Widget build(BuildContext context) { - String name = 'Felipe el du'; - String city = 'Felipe el du'; + final User? user = FirebaseAuth.instance.currentUser; + // String name = _nombre.toString(); - // String city = _ciudad.toString(); + String city = _ciudad.toString(); return SafeArea( child: Scaffold( @@ -61,20 +55,17 @@ class _WelcomeScreenState extends State { onTap: () { Navigator.pushNamed(context, '/profile'); }, - title: Text('$name', + title: Text('${user?.displayName ?? user?.email}', style: TextStyle(fontWeight: FontWeight.bold)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'friki', - // AuthenticationRepository.instance - // .getCurrentUserPhone() - // .toString(), + '${user?.phoneNumber ?? ''}', style: TextStyle(fontSize: 12), ), Text( - '$city', + '${city ?? "a"}', style: TextStyle(fontSize: 12), ), ],