From e00772f58a76af126a2c89388225b9e62e7343d4 Mon Sep 17 00:00:00 2001 From: Felipe Date: Tue, 20 Feb 2024 17:11:43 -0500 Subject: [PATCH] label --- lib/blocs/auth_bloc/auth_bloc.dart | 43 ++++ lib/blocs/auth_bloc/auth_event.dart | 20 ++ lib/blocs/auth_bloc/auth_state.dart | 26 +++ lib/blocs/sign_up_bloc/sign_up_bloc.dart | 2 +- lib/blocs/sign_up_bloc/sign_up_event.dart | 5 +- lib/components/general_drawer_header.dart | 4 +- lib/components/general_input_decoration.dart | 42 ++++ lib/components/textfield.dart | 25 +-- lib/dependency_user/user_di.dart | 4 + .../authentication/otp_auth_screen.dart | 102 +++++++++ .../authentication/sign_in_screen.dart | 10 +- lib/screens/authentication/sign_screen.dart | 52 ++--- .../authentication/sign_up_screen.dart | 7 +- .../authentication/welcome_screen.dart | 207 +++--------------- lib/screens/profile/profile_screen.dart | 2 +- .../authentication_repository.dart | 14 +- .../lib/src/entities/my_user_entity.dart | 12 +- .../lib/src/models/my_user.dart | 10 +- .../firebase_user_repository.dart | 70 +++--- .../lib/src/repositories/user_repo.dart | 4 +- pubspec.yaml | 4 +- 21 files changed, 386 insertions(+), 279 deletions(-) create mode 100644 lib/blocs/auth_bloc/auth_bloc.dart create mode 100644 lib/blocs/auth_bloc/auth_event.dart create mode 100644 lib/blocs/auth_bloc/auth_state.dart create mode 100644 lib/components/general_input_decoration.dart create mode 100644 lib/screens/authentication/otp_auth_screen.dart diff --git a/lib/blocs/auth_bloc/auth_bloc.dart b/lib/blocs/auth_bloc/auth_bloc.dart new file mode 100644 index 0000000..427c18d --- /dev/null +++ b/lib/blocs/auth_bloc/auth_bloc.dart @@ -0,0 +1,43 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:user_repository/user_repository.dart'; + +part 'auth_event.dart'; +part 'auth_state.dart'; + +class AuthBloc extends Bloc { + final UserRepository _userRepository; + + AuthBloc({required UserRepository userRepository}) + : _userRepository = userRepository, + super(AuthStateInitial()) { + on(_onAuthEventLoginOAuth); + on(_onAuthEventVerifyOAuth); + } + + void _onAuthEventLoginOAuth( + AuthEventLoginOAuth event, Emitter emit) async { + emit(AuthStateProcess()); + try { + await _userRepository.signInWithPhoneNumber(event.phone); + + emit(const AuthStateVerifyOAuth(false)); + } catch (e) { + emit(const AuthStateFailure()); + } + } + + void _onAuthEventVerifyOAuth( + AuthEventVerifyOAuth event, Emitter emit) async { + emit(AuthStateProcess()); + try { + final bool isVerified = await _userRepository.verifyOTP(event.code); + + (isVerified) + ? emit(AuthStateSuccess()) + : emit(const AuthStateVerifyOAuth(true)); + } catch (e) { + emit(const AuthStateFailure()); + } + } +} diff --git a/lib/blocs/auth_bloc/auth_event.dart b/lib/blocs/auth_bloc/auth_event.dart new file mode 100644 index 0000000..3afb717 --- /dev/null +++ b/lib/blocs/auth_bloc/auth_event.dart @@ -0,0 +1,20 @@ +part of 'auth_bloc.dart'; + +abstract class AuthEvent extends Equatable { + const AuthEvent(); + + @override + List get props => []; +} + +class AuthEventLoginOAuth extends AuthEvent { + final String phone; + + const AuthEventLoginOAuth({required this.phone}); +} + +class AuthEventVerifyOAuth extends AuthEvent { + final String code; + + const AuthEventVerifyOAuth({required this.code}); +} diff --git a/lib/blocs/auth_bloc/auth_state.dart b/lib/blocs/auth_bloc/auth_state.dart new file mode 100644 index 0000000..249d30b --- /dev/null +++ b/lib/blocs/auth_bloc/auth_state.dart @@ -0,0 +1,26 @@ +part of 'auth_bloc.dart'; + +abstract class AuthState extends Equatable { + const AuthState(); + + @override + List get props => []; +} + +class AuthStateInitial extends AuthState {} + +class AuthStateProcess extends AuthState {} + +class AuthStateVerifyOAuth extends AuthState { + final bool isWrongCode; + + const AuthStateVerifyOAuth(this.isWrongCode); +} + +class AuthStateSuccess extends AuthState {} + +class AuthStateFailure extends AuthState { + final String? message; + + const AuthStateFailure({this.message}); +} diff --git a/lib/blocs/sign_up_bloc/sign_up_bloc.dart b/lib/blocs/sign_up_bloc/sign_up_bloc.dart index f2e9b1e..60c21e4 100644 --- a/lib/blocs/sign_up_bloc/sign_up_bloc.dart +++ b/lib/blocs/sign_up_bloc/sign_up_bloc.dart @@ -18,7 +18,7 @@ class SignUpBloc extends Bloc { SignUpRequired event, Emitter emit) async { emit(SignUpProcess()); try { - MyUser user = await _userRepository.signUp(event.user, event.password); + MyUser user = await _userRepository.signUp(event.email, event.password); await _userRepository.setUserData(user); emit(SignUpSuccess()); } catch (e) { diff --git a/lib/blocs/sign_up_bloc/sign_up_event.dart b/lib/blocs/sign_up_bloc/sign_up_event.dart index 9243ab3..19f4089 100644 --- a/lib/blocs/sign_up_bloc/sign_up_event.dart +++ b/lib/blocs/sign_up_bloc/sign_up_event.dart @@ -8,8 +8,9 @@ abstract class SignUpEvent extends Equatable { } class SignUpRequired extends SignUpEvent { - final MyUser user; + final String email; final String password; - const SignUpRequired(this.user, this.password); + const SignUpRequired({required this.email, required this.password}); + // const SignUpRequired(this.email, this.password); } diff --git a/lib/components/general_drawer_header.dart b/lib/components/general_drawer_header.dart index 7c03211..d9fbf07 100644 --- a/lib/components/general_drawer_header.dart +++ b/lib/components/general_drawer_header.dart @@ -22,11 +22,11 @@ class GeneralDrawerHeader extends StatelessWidget { ); }, title: Text( - context.read().state.user!.name, + context.read().state.user!.name ?? '', style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( - context.read().state.user!.email, + context.read().state.user!.email ?? '', style: const TextStyle(fontSize: 12), ), leading: context.read().state.user!.picture == "" diff --git a/lib/components/general_input_decoration.dart b/lib/components/general_input_decoration.dart new file mode 100644 index 0000000..a89d51b --- /dev/null +++ b/lib/components/general_input_decoration.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +class GeneralInputDecoration { + static InputDecoration getCustomDecoration({ + required BuildContext context, + required String hintText, + String? labelText, + Widget? suffixIcon, + Widget? prefixIcon, + String? errorMsg, + }) { + Color? borderColor = errorMsg != null ? Colors.red : Colors.grey; + return InputDecoration( + labelText: labelText, + suffixIcon: suffixIcon, + prefixIcon: prefixIcon, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: borderColor), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(15), + borderSide: BorderSide(color: Theme.of(context).colorScheme.primary), + ), + errorBorder: OutlineInputBorder( + // Border when there's an error + borderRadius: BorderRadius.circular(20), + borderSide: BorderSide(color: Theme.of(context).colorScheme.error), + ), + focusedErrorBorder: OutlineInputBorder( + // Border when focused with error + borderRadius: BorderRadius.circular(20), + borderSide: BorderSide(color: Theme.of(context).colorScheme.error), + ), + fillColor: Colors.grey.shade200, + filled: true, + hintText: hintText, + hintStyle: TextStyle(color: Colors.grey[500]), + errorText: errorMsg, + ); + } +} diff --git a/lib/components/textfield.dart b/lib/components/textfield.dart index abac651..28c70a0 100644 --- a/lib/components/textfield.dart +++ b/lib/components/textfield.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:prosappco/components/general_input_decoration.dart'; class MyTextField extends StatelessWidget { final TextEditingController controller; + final String? labelText; final String hintText; final bool obscureText; final TextInputType keyboardType; @@ -15,6 +17,7 @@ class MyTextField extends StatelessWidget { const MyTextField( {super.key, + this.labelText, required this.controller, required this.hintText, required this.obscureText, @@ -38,23 +41,13 @@ class MyTextField extends StatelessWidget { onTap: onTap, textInputAction: TextInputAction.next, onChanged: onChanged, - decoration: InputDecoration( - suffixIcon: suffixIcon, - prefixIcon: prefixIcon, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide(color: Colors.transparent), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(20), - borderSide: - BorderSide(color: Theme.of(context).colorScheme.secondary), - ), - fillColor: Colors.grey.shade200, - filled: true, + decoration: GeneralInputDecoration.getCustomDecoration( + labelText: labelText, + context: context, hintText: hintText, - hintStyle: TextStyle(color: Colors.grey[500]), - errorText: errorMsg, + prefixIcon: prefixIcon, + errorMsg: errorMsg, + suffixIcon: suffixIcon, ), ); } diff --git a/lib/dependency_user/user_di.dart b/lib/dependency_user/user_di.dart index 22feab2..15c38d2 100644 --- a/lib/dependency_user/user_di.dart +++ b/lib/dependency_user/user_di.dart @@ -1,5 +1,6 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:injector/injector.dart'; +import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart'; import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart'; import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart'; @@ -32,5 +33,8 @@ class UserDI { injector.registerDependency( (() => SettingBloc(userRepository: injector.get()))); + + injector.registerDependency( + (() => AuthBloc(userRepository: injector.get()))); } } diff --git a/lib/screens/authentication/otp_auth_screen.dart b/lib/screens/authentication/otp_auth_screen.dart new file mode 100644 index 0000000..2566569 --- /dev/null +++ b/lib/screens/authentication/otp_auth_screen.dart @@ -0,0 +1,102 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_otp_text_field/flutter_otp_text_field.dart'; +import 'package:injector/injector.dart'; +import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart'; + +class OtpAuthScreen extends StatefulWidget { + final String phoneNumber; + + const OtpAuthScreen({super.key, required this.phoneNumber}); + + @override + State createState() => _OtpAuthScreenState(); +} + +class _OtpAuthScreenState extends State { + bool _isRequestSent = false; + + @override + Widget build(BuildContext context) { + final authBloc = Injector.appInstance.get(); + + if (!_isRequestSent) { + authBloc.add(AuthEventLoginOAuth(phone: widget.phoneNumber)); + _isRequestSent = true; + } + + return BlocProvider( + create: (context) => authBloc, + child: BlocConsumer( + listener: (context, state) { + if (state is AuthStateSuccess) { + Navigator.of(context).pop(); + } + if (state is AuthStateVerifyOAuth) { + if (state.isWrongCode) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('El Código es incorrecto'), + )); + } + } + }, + builder: (context, state) { + return Scaffold( + body: Column(children: [ + getContent(state, authBloc: authBloc), + ]), + ); + }, + ), + ); + } + + Widget getContent(AuthState state, {required AuthBloc authBloc}) { + if (state is AuthStateInitial) { + return const Text('Inicio'); + } else if (state is AuthStateProcess) { + return Center( + child: Column( + children: [ + Text('${widget.phoneNumber} - $_isRequestSent'), + OtpTextField( + numberOfFields: 6, + borderColor: const Color(0xFF512DA8), + showFieldAsBox: true, + onCodeChanged: (String code) {}, + onSubmit: (String verificationCode) { + authBloc.add(AuthEventVerifyOAuth(code: verificationCode)); + }, // end onSubmit + ), + ], + ), + ); + } else if (state is AuthStateVerifyOAuth) { + return Center( + child: Column( + children: [ + Text('${widget.phoneNumber} - $_isRequestSent'), + state.isWrongCode ? const Text('❌') : const Text(''), + OtpTextField( + numberOfFields: 6, + borderColor: const Color(0xFF512DA8), + showFieldAsBox: true, + onCodeChanged: (String code) {}, + onSubmit: (String verificationCode) { + authBloc.add(AuthEventVerifyOAuth(code: verificationCode)); + }, // end onSubmit + ), + ], + ), + ); + } else if (state is AuthStateSuccess) { + return const CircularProgressIndicator(); + } else if (state is AuthStateFailure) { + return const Text('❌'); + } else { + return const CircularProgressIndicator(); + } + } +} diff --git a/lib/screens/authentication/sign_in_screen.dart b/lib/screens/authentication/sign_in_screen.dart index 178f079..87dd311 100644 --- a/lib/screens/authentication/sign_in_screen.dart +++ b/lib/screens/authentication/sign_in_screen.dart @@ -53,7 +53,10 @@ class _SignInScreenState extends State { hintText: 'Email', obscureText: false, keyboardType: TextInputType.emailAddress, - prefixIcon: const Icon(CupertinoIcons.mail_solid), + prefixIcon: Icon( + CupertinoIcons.mail_solid, + color: Colors.grey[600], + ), errorMsg: _errorMsg, validator: (val) { if (val!.isEmpty) { @@ -72,7 +75,8 @@ class _SignInScreenState extends State { hintText: 'Password', obscureText: obscurePassword, keyboardType: TextInputType.visiblePassword, - prefixIcon: const Icon(CupertinoIcons.lock_fill), + prefixIcon: + Icon(CupertinoIcons.lock_fill, color: Colors.grey[600]), errorMsg: _errorMsg, validator: (val) { if (val!.isEmpty) { @@ -93,7 +97,7 @@ class _SignInScreenState extends State { } }); }, - icon: Icon(iconPassword), + icon: Icon(iconPassword, color: Colors.grey[600]), ), ), ), diff --git a/lib/screens/authentication/sign_screen.dart b/lib/screens/authentication/sign_screen.dart index 79a6f9c..099036e 100644 --- a/lib/screens/authentication/sign_screen.dart +++ b/lib/screens/authentication/sign_screen.dart @@ -58,32 +58,32 @@ class _SignScreenState extends State with TickerProviderStateMixin { ), ), ), - TabBar( - controller: tabController, - unselectedLabelColor: - Theme.of(context).colorScheme.onBackground, - labelColor: Theme.of(context).colorScheme.onBackground, - tabs: const [ - Padding( - padding: EdgeInsets.all(12.0), - child: Text( - 'Inicia sesión', - style: TextStyle( - fontSize: 18, - ), - ), - ), - Padding( - padding: EdgeInsets.all(12.0), - child: Text( - 'Registrate', - style: TextStyle( - fontSize: 18, - ), - ), - ), - ], - ), + // TabBar( + // controller: tabController, + // unselectedLabelColor: + // Theme.of(context).colorScheme.onBackground, + // labelColor: Theme.of(context).colorScheme.onBackground, + // tabs: const [ + // Padding( + // padding: EdgeInsets.all(12.0), + // child: Text( + // 'Inicia sesión', + // style: TextStyle( + // fontSize: 18, + // ), + // ), + // ), + // Padding( + // padding: EdgeInsets.all(12.0), + // child: Text( + // 'Registrate', + // style: TextStyle( + // fontSize: 18, + // ), + // ), + // ), + // ], + // ), ], ), ), diff --git a/lib/screens/authentication/sign_up_screen.dart b/lib/screens/authentication/sign_up_screen.dart index a9e3ae9..de8dd81 100644 --- a/lib/screens/authentication/sign_up_screen.dart +++ b/lib/screens/authentication/sign_up_screen.dart @@ -197,8 +197,9 @@ class _SignUpScreenState extends State { SizedBox( width: MediaQuery.of(context).size.width * 0.9, child: MyTextField( + labelText: 'Nombre', controller: nameController, - hintText: 'Name', + hintText: 'Ingresa tu nombre', obscureText: false, keyboardType: TextInputType.name, prefixIcon: const Icon(CupertinoIcons.person_fill), @@ -226,7 +227,9 @@ class _SignUpScreenState extends State { setState(() { context.read().add(SignUpRequired( - myUser, passwordController.text)); + email: emailController.text, + password: passwordController.text, + )); }); } }, diff --git a/lib/screens/authentication/welcome_screen.dart b/lib/screens/authentication/welcome_screen.dart index f54ce95..c3de2fb 100644 --- a/lib/screens/authentication/welcome_screen.dart +++ b/lib/screens/authentication/welcome_screen.dart @@ -3,14 +3,18 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl_phone_field/intl_phone_field.dart'; +import 'package:prosappco/components/general_input_decoration.dart'; +import 'package:prosappco/screens/authentication/otp_auth_screen.dart'; import 'package:prosappco/screens/authentication/sign_screen.dart'; class WelcomeScreen extends StatelessWidget { - const WelcomeScreen({Key? key}); + const WelcomeScreen({super.key}); @override Widget build(BuildContext context) { double width = MediaQuery.of(context).size.width; + String? _phoneNumber; + String? _errorMsg; return Scaffold( backgroundColor: Theme.of(context).colorScheme.tertiary, @@ -70,6 +74,22 @@ class WelcomeScreen extends StatelessWidget { inputFormatters: [ FilteringTextInputFormatter.digitsOnly ], + validator: (value) { + if (value == null) { + return 'Ingresa un numero'; + } else { + return null; + } + }, + onChanged: (phone) { + _phoneNumber = phone.completeNumber; + }, + decoration: + GeneralInputDecoration.getCustomDecoration( + context: context, + hintText: 'Ingresa tu numero', + errorMsg: _errorMsg, + ), ), ), Text( @@ -82,15 +102,19 @@ class WelcomeScreen extends StatelessWidget { ), ElevatedButton( onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - const SignScreen(initialIndex: 1), - ), - ); + final phoneNumber = _phoneNumber; + + if (phoneNumber != null && phoneNumber.isNotEmpty) { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + OtpAuthScreen(phoneNumber: phoneNumber), + ), + ); + } else {} }, - child: const Text('Iniciar Sesión'), + child: const Text('Enviar código'), ), TextButton( onPressed: () { @@ -148,170 +172,5 @@ class WelcomeScreen extends StatelessWidget { ], ), ); - - // Scaffold( - // backgroundColor: Theme.of(context).colorScheme.surface, - // body: Column( - // children: [ - // Container( - // color: Theme.of(context).colorScheme.tertiary, - // child: Column( - // children: [ - // const SizedBox(height: 20), - // Center( - // child: Image( - // width: width * 0.7, - // image: const AssetImage('images/logo_prosapp.png'), - // ), - // ), - // const SizedBox(height: 20), - // ], - // ), - // ), - // SizedBox( - // width: double.infinity, - // child: Text( - // 'Iniciar sesión', - // style: TextStyle( - // // fontSize: 30, - // fontSize: width * 0.08, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // Expanded( - // child: SingleChildScrollView( - // child: Column( - // children: [ - // const SizedBox(height: 10), - // SizedBox( - // width: double.infinity, - // child: Text( - // 'Numero de celular', - // style: TextStyle( - // fontSize: width * 0.045, - // color: Theme.of(context).colorScheme.onBackground, - // ), - // ), - // ), - // Form( - // child: IntlPhoneField( - // initialCountryCode: 'CO', - // keyboardType: TextInputType.number, - // inputFormatters: [FilteringTextInputFormatter.digitsOnly], - // ), - // ), - // Text( - // 'Un código será enviado a este numero de celular.', - // textAlign: TextAlign.center, - // style: TextStyle( - // fontSize: 13.0, - // color: Theme.of(context).colorScheme.onBackground, - // ), - // ), - // TextButton( - // onPressed: () { - // Navigator.push( - // context, - // CupertinoPageRoute( - // builder: (context) => SignScreen(initialIndex: 0), - // ), - // ); - // }, - // child: Text( - // 'Inicia sesión con tu correo electrónico', - // style: TextStyle( - // fontSize: width * 0.04, - // ), - // ), - // ), - // RichText( - // text: TextSpan( - // style: const TextStyle( - // fontSize: 16.0, - // color: Color(0xFF65676B), - // fontFamily: 'Poppins', - // ), - // children: [ - // const TextSpan(text: '¿No estás registrado? '), - // TextSpan( - // text: 'Regístrate', - // style: TextStyle( - // fontSize: width * 0.04, - // color: Colors.blue, - // fontWeight: FontWeight.w600, - // ), - // recognizer: TapGestureRecognizer() - // ..onTap = () { - // Navigator.push( - // context, - // CupertinoPageRoute( - // builder: (context) => - // SignScreen(initialIndex: 1), - // ), - // ); - // }, - // ), - // ], - // ), - // ), - // ], - // ), - // ), - // ), - // ], - // ), - // ); - - // Scaffold( - // backgroundColor: Theme.of(context).colorScheme.surface, - // body: ListView( - // children: [ - // Container( - // color: Theme.of(context).colorScheme.tertiary, - // padding: const EdgeInsets.symmetric(vertical: 20.0), - // child: Center( - // child: Image( - // width: width * 0.7, - // image: const AssetImage('images/logo_prosapp.png'), - // ), - // ), - // ), - // Container( - // decoration: const BoxDecoration( - // color: Colors.white, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(60), - // topRight: Radius.circular(60), - // ), - // ), - // child: Padding( - // padding: const EdgeInsets.all(20.0), - // child: Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // const TextField( - // decoration: InputDecoration( - // labelText: 'Usuario', - // border: OutlineInputBorder(), - // ), - // ), - // const SizedBox(height: 20.0), - // const TextField( - // decoration: InputDecoration( - // labelText: 'Contraseña', - // border: OutlineInputBorder(), - // ), - // obscureText: true, - // ), - // const SizedBox(height: 20.0), - // - // ], - // ), - // ), - // ), - // ], - // ), - // ); } } diff --git a/lib/screens/profile/profile_screen.dart b/lib/screens/profile/profile_screen.dart index a1a7006..d973285 100644 --- a/lib/screens/profile/profile_screen.dart +++ b/lib/screens/profile/profile_screen.dart @@ -39,7 +39,7 @@ class _ProfileScreenState extends State { ), body: BlocBuilder(builder: (context, state) { if (state.status == MyUserStatus.success) { - _nameController.text = state.user!.name; + _nameController.text = state.user!.name ?? ''; return Padding( padding: const EdgeInsets.all(20.0), diff --git a/lib/src/authentication/authentication_repository.dart b/lib/src/authentication/authentication_repository.dart index 208d8c0..e51b73e 100644 --- a/lib/src/authentication/authentication_repository.dart +++ b/lib/src/authentication/authentication_repository.dart @@ -58,6 +58,13 @@ class AuthenticationRepository extends GetxController { ); } + Future verifyOTP(String otp) async { + var credentials = await _auth.signInWithCredential( + PhoneAuthProvider.credential( + verificationId: verificationId.value, smsCode: otp)); + return credentials.user != null ? true : false; + } + Future updatePhoneNumber(String verificationId, String smsCode) async { try { PhoneAuthCredential credential = PhoneAuthProvider.credential( @@ -69,13 +76,6 @@ class AuthenticationRepository extends GetxController { } } - Future verifyOTP(String otp) async { - var credentials = await _auth.signInWithCredential( - PhoneAuthProvider.credential( - verificationId: verificationId.value, smsCode: otp)); - return credentials.user != null ? true : false; - } - Future createUserWithEmailAndPassword( String email, String password) async { try { diff --git a/packages/user_repository/lib/src/entities/my_user_entity.dart b/packages/user_repository/lib/src/entities/my_user_entity.dart index cc0a4a5..fd35f67 100644 --- a/packages/user_repository/lib/src/entities/my_user_entity.dart +++ b/packages/user_repository/lib/src/entities/my_user_entity.dart @@ -2,14 +2,14 @@ import 'package:equatable/equatable.dart'; class MyUserEntity extends Equatable { final String id; - final String email; - final String name; + final String? email; + final String? name; final String? picture; const MyUserEntity({ required this.id, - required this.email, - required this.name, + this.email, + this.name, this.picture, }); @@ -25,8 +25,8 @@ class MyUserEntity extends Equatable { static MyUserEntity fromDocument(Map doc) { return MyUserEntity( id: doc['id'] as String, - email: doc['email'] as String, - name: doc['name'] as String, + email: doc['email'] as String?, + name: doc['name'] as String?, picture: doc['picture'] as String?, ); } diff --git a/packages/user_repository/lib/src/models/my_user.dart b/packages/user_repository/lib/src/models/my_user.dart index 71965c5..fb0c5e2 100644 --- a/packages/user_repository/lib/src/models/my_user.dart +++ b/packages/user_repository/lib/src/models/my_user.dart @@ -4,14 +4,14 @@ import '../entities/entities.dart'; class MyUser extends Equatable { final String id; - final String email; - final String name; - String? picture; + final String? email; + final String? name; + final String? picture; MyUser({ required this.id, - required this.email, - required this.name, + this.email, + this.name, this.picture, }); diff --git a/packages/user_repository/lib/src/repositories/firebase_user_repository.dart b/packages/user_repository/lib/src/repositories/firebase_user_repository.dart index 35cb2cc..e7b9296 100644 --- a/packages/user_repository/lib/src/repositories/firebase_user_repository.dart +++ b/packages/user_repository/lib/src/repositories/firebase_user_repository.dart @@ -14,6 +14,7 @@ class FirebaseUserRepository implements UserRepository { final usersCollection = FirebaseFirestore.instance.collection('users'); final StreamController _userStreamController = StreamController.broadcast(); + String verificationId = ''; FirebaseUserRepository(this._firebaseAuth) { _firebaseAuth.userChanges().listen((user) async { @@ -49,18 +50,14 @@ class FirebaseUserRepository implements UserRepository { // Sign up @override - Future signUp(MyUser myUser, String password) async { + Future signUp(String email, String password) async { try { UserCredential user = await _firebaseAuth.createUserWithEmailAndPassword( - email: myUser.email, + email: email, password: password, ); - myUser = myUser.copyWith( - id: user.user!.uid, - ); - - return myUser; + return await getMyUser(user.user!.uid); } catch (e) { log(e.toString()); rethrow; @@ -71,34 +68,21 @@ class FirebaseUserRepository implements UserRepository { @override Future signInWithPhoneNumber(String phoneNumber) async { try { - await FirebaseAuth.instance.verifyPhoneNumber( + await _firebaseAuth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { - // Esta función se llama automáticamente cuando se completa la verificación del número de teléfono. - // Puedes usar 'credential' para iniciar sesión o vincular la cuenta. - // En la mayoría de los casos, no necesitas implementar esto, ya que Firebase manejará la autenticación automáticamente. - - await FirebaseAuth.instance.signInWithCredential(credential); - }, - verificationFailed: (FirebaseAuthException e) { - // Esta función se llama si la verificación del número de teléfono falla. - // Maneja los errores o muestra un mensaje al usuario. - if (e.code == 'invalid-phone-number') { - // Manejar el caso de número de teléfono no válido - } else if (e.code == 'network-request-failed') { - // Manejar problemas de conectividad - } else { - // Manejar otros errores - } + await _firebaseAuth.signInWithCredential(credential); }, codeSent: (String verificationId, int? resendToken) { - // Esta función se llama cuando se envía el código de verificación al número de teléfono del usuario. - // Debes guardar 'verificationId' para usarlo posteriormente en la verificación. - // Puedes mostrar un diálogo para que el usuario ingrese el código o puedes verificarlo automáticamente. + this.verificationId = verificationId; }, codeAutoRetrievalTimeout: (String verificationId) { - // Esta función se llama cuando el tiempo de espera de recuperación automática del código ha expirado. - // Puedes manejar esto como prefieras, por ejemplo, mostrando un mensaje al usuario o reenviando el código. + this.verificationId = verificationId; + }, + verificationFailed: (FirebaseAuthException e) { + if (e.code == 'invalid-phone-number') { + } else if (e.code == 'network-request-failed') { + } else {} }, ); } catch (e) { @@ -107,6 +91,26 @@ class FirebaseUserRepository implements UserRepository { } } + @override + Future verifyOTP(String code) async { + try { + var credentials = await _firebaseAuth.signInWithCredential( + PhoneAuthProvider.credential( + verificationId: verificationId, smsCode: code)); + return credentials.user != null ? true : false; + } catch (e) { + if (e is FirebaseAuthException) { + if (e.code == 'invalid-verification-code') { + return false; + } else { + rethrow; + } + } else { + rethrow; + } + } + } + // Sign in @override Future signIn(String email, String password) async { @@ -158,8 +162,12 @@ class FirebaseUserRepository implements UserRepository { @override Future getMyUser(String myUserId) async { try { - return usersCollection.doc(myUserId).get().then((value) => - MyUser.fromEntity(MyUserEntity.fromDocument(value.data()!))); + return usersCollection.doc(myUserId).get().then((value) { + log('xd -- ${value.data().toString()}'); // Imprime el valor de value + return MyUser.fromEntity( + MyUserEntity.fromDocument(value.data()!), + ); + }); } catch (e) { log(e.toString()); rethrow; diff --git a/packages/user_repository/lib/src/repositories/user_repo.dart b/packages/user_repository/lib/src/repositories/user_repo.dart index b5a8ac7..aefaf90 100644 --- a/packages/user_repository/lib/src/repositories/user_repo.dart +++ b/packages/user_repository/lib/src/repositories/user_repo.dart @@ -9,10 +9,12 @@ abstract class UserRepository { Future logOut(); - Future signUp(MyUser myUser, String password); + Future signUp(String email, String password); Future signInWithPhoneNumber(String phoneNumber); + Future verifyOTP(String code); + Future resetPassword(String email); Future setUserData(MyUser user); diff --git a/pubspec.yaml b/pubspec.yaml index 3ac66dc..0236e4e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: animate_do: ^3.0.2 animated_splash_screen: ^1.3.0 - cloud_firestore: null + cloud_firestore: ^4.15.4 community_material_icon: ^5.9.55 cupertino_icons: ^1.0.2 diacritic: null @@ -29,8 +29,8 @@ dependencies: flutter_localizations: sdk: flutter flutter_polyline_points: ^2.0.0 - flutter_otp_text_field: ^1.1.1 flutter_rating_bar: ^4.0.1 + flutter_otp_text_field: ^1.1.1 otp_timer_button: ^1.1.0 font_awesome_flutter: ^10.4.0 geocoding: ^2.1.0