From 1a51965f00f64c2e1e8880c13dfc3b1058611c5f Mon Sep 17 00:00:00 2001 From: etachott Date: Wed, 22 Mar 2023 14:57:49 -0300 Subject: [PATCH 1/3] feat: added register page skeleton Co-authored-by: wleite Co-authored-by: sgkhusal --- .../lib/app/modules/login/login_module.dart | 9 ++- .../modules/login/pages/login_controller.dart | 21 ++++++- .../modules/login/pages/onboarding_page.dart | 4 +- .../register/presenter/register_page.dart | 40 ++++++++++++ .../modules/register/register_controller.dart | 10 +++ .../app/modules/register/register_module.dart | 20 ++++++ .../mentorme_generic_big_app_bar.dart | 63 +++++++++++++++++++ 7 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 front/mentorme/lib/app/modules/register/presenter/register_page.dart create mode 100644 front/mentorme/lib/app/modules/register/register_controller.dart create mode 100644 front/mentorme/lib/app/modules/register/register_module.dart create mode 100644 front/mentorme/lib/app/shared/components/mentorme_generic_big_app_bar.dart diff --git a/front/mentorme/lib/app/modules/login/login_module.dart b/front/mentorme/lib/app/modules/login/login_module.dart index 08eabed..c53d56f 100644 --- a/front/mentorme/lib/app/modules/login/login_module.dart +++ b/front/mentorme/lib/app/modules/login/login_module.dart @@ -3,12 +3,14 @@ import 'package:mentorme/app/modules/home/home_module.dart'; import 'package:mentorme/app/modules/login/pages/login_controller.dart'; import 'package:mentorme/app/modules/login/pages/login_page.dart'; import 'package:mentorme/app/modules/login/pages/onboarding_page.dart'; +import 'package:mentorme/app/modules/register/presenter/register_page.dart'; +import 'package:mentorme/app/modules/register/register_module.dart'; class LoginModule extends Module { @override List get binds => [ - Bind((i) => LoginController(i(), i())), - ]; + Bind((i) => LoginController(i(), i())), + ]; @override final List routes = [ @@ -19,9 +21,10 @@ class LoginModule extends Module { ), ChildRoute( '/onboarding', - child: (__, args) => const OnboardingPage(), + child: (__, args) => const RegisterPage(), transition: TransitionType.rightToLeft, ), ModuleRoute('/home', module: HomeModule()), + ModuleRoute('/register', module: RegisterModule()), ]; } diff --git a/front/mentorme/lib/app/modules/login/pages/login_controller.dart b/front/mentorme/lib/app/modules/login/pages/login_controller.dart index 57d8955..8744c1c 100644 --- a/front/mentorme/lib/app/modules/login/pages/login_controller.dart +++ b/front/mentorme/lib/app/modules/login/pages/login_controller.dart @@ -23,12 +23,29 @@ class LoginController { } _goToLogin() { - goToHome(); + //goToHome(); + goToRegister(); + } + + goToRegister() async { + await Future.delayed( + const Duration(milliseconds: 500), + () { + Modular.to.pushReplacementNamed( + '/register/', + forRoot: true, + arguments: { + 'wasLoginNow': false, + }, + ); + }, + ); } goToHome() async { await Future.delayed( - const Duration(milliseconds: 500), () { + const Duration(milliseconds: 500), + () { Modular.to.pushReplacementNamed( '/home/', forRoot: true, diff --git a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart index 0c2d9ae..fc225c6 100644 --- a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart +++ b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart @@ -55,7 +55,7 @@ class _OnboardingPageState extends State { flex: 18, child: Container( padding: - const EdgeInsets.symmetric(vertical: 20, horizontal: 20), + const EdgeInsets.symmetric(vertical: 20, horizontal: 20), alignment: Alignment.bottomCenter, child: SizedBox( width: double.infinity, @@ -80,4 +80,4 @@ class _OnboardingPageState extends State { ), ); } -} \ No newline at end of file +} diff --git a/front/mentorme/lib/app/modules/register/presenter/register_page.dart b/front/mentorme/lib/app/modules/register/presenter/register_page.dart new file mode 100644 index 0000000..ce2ad62 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/presenter/register_page.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:mentorme/app/shared/components/mentor_me_button.dart'; +import 'package:mentorme/app/shared/components/mentorme_big_app_bar.dart'; +import 'package:mentorme/app/shared/components/mentorme_content_page.dart'; +import 'package:mentorme/app/shared/components/mentorme_generic_big_app_bar.dart'; + +class RegisterPage extends StatelessWidget { + const RegisterPage({super.key}); + + @override + Widget build(BuildContext context) { + return MentorMeContentPage( + appBar: const MentorMeGenericBigAppBar(pageName: "Criar perfil"), + pageName: "Cadastro", + child: Form( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + children: [ + TextFormField( + decoration: const InputDecoration(hintText: "Nome")), + const SizedBox(height: 15), + TextFormField(decoration: const InputDecoration(hintText: "Bio")), + const SizedBox(height: 15), + TextFormField( + decoration: const InputDecoration(hintText: "Contato")), + const SizedBox(height: 15), + const MentorMeButton( + label: "Cadastrar", + isActive: true, + height: 50, + radius: 6, + ), + ], + ), + ), + ), + ); + } +} diff --git a/front/mentorme/lib/app/modules/register/register_controller.dart b/front/mentorme/lib/app/modules/register/register_controller.dart new file mode 100644 index 0000000..0fbdbd3 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/register_controller.dart @@ -0,0 +1,10 @@ +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/shared/services/http_service/http_service.dart'; +import 'package:mentorme/app/shared/storage/i_custom_app_storage.dart'; + +class RegisterController { + final HttpService _httpService; + final ICustomAppStorage _storage; + + RegisterController(this._httpService, this._storage); +} diff --git a/front/mentorme/lib/app/modules/register/register_module.dart b/front/mentorme/lib/app/modules/register/register_module.dart new file mode 100644 index 0000000..130c07d --- /dev/null +++ b/front/mentorme/lib/app/modules/register/register_module.dart @@ -0,0 +1,20 @@ +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/modules/home/home_module.dart'; +import 'package:mentorme/app/modules/register/presenter/register_page.dart'; +import 'package:mentorme/app/modules/register/register_controller.dart'; + +class RegisterModule extends Module { + @override + List get binds => [ + Bind((i) => RegisterController(i(), i())), + ]; + + @override + final List routes = [ + ChildRoute( + '/', + child: (__, args) => const RegisterPage(), + transition: TransitionType.rightToLeft, + ), + ]; +} diff --git a/front/mentorme/lib/app/shared/components/mentorme_generic_big_app_bar.dart b/front/mentorme/lib/app/shared/components/mentorme_generic_big_app_bar.dart new file mode 100644 index 0000000..e9052c0 --- /dev/null +++ b/front/mentorme/lib/app/shared/components/mentorme_generic_big_app_bar.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/core/domain/entities/mentor_entity.dart'; + +class MentorMeGenericBigAppBar extends StatelessWidget { + final String pageName; + + const MentorMeGenericBigAppBar({Key? key, required this.pageName}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: const Color(0xFF0A7DB8), + flexibleSpace: Container( + padding: const EdgeInsets.only(top: 10), + width: MediaQuery.of(context).size.width, + margin: EdgeInsets.only(top: AppBar().preferredSize.height), + height: 210, + color: const Color(0xFF0A7DB8), + child: Column( + children: [ + SizedBox( + height: 30, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + pageName, + style: const TextStyle( + fontSize: 18, + color: Colors.white, + fontWeight: FontWeight.w700, + ), + ) + ], + ), + ), + Container( + margin: const EdgeInsets.only(top: 10), + child: const CircleAvatar( + radius: 50, + backgroundImage: NetworkImage( + "https://user-images.githubusercontent.com/11250/39013954-f5091c3a-43e6-11e8-9cac-37cf8e8c8e4e.jpg"), + backgroundColor: Colors.transparent, + ), + ), + const SizedBox(height: 5), + const Text("Alterar foto de perfil", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Color(0xFF00F0FF), + )), + const SizedBox(height: 19) + ], + ), + ), + ); + } +} From cca1afba4d9a2e10f312b5a265e3271154065812 Mon Sep 17 00:00:00 2001 From: etachott Date: Thu, 23 Mar 2023 14:41:18 -0300 Subject: [PATCH 2/3] feat: added mentor register form and integrated with api --- .../lib/app/modules/login/login_module.dart | 2 +- .../modules/login/pages/onboarding_page.dart | 2 +- .../domain/entities/register_entity.dart | 20 +++ .../domain/entities/register_response.dart | 7 + .../i_repositories/i_register_repository.dart | 8 + .../domain/params/register_params.dart | 20 +++ .../usecases/contact_history_usecase.dart | 20 +++ .../datasources/register_datasource.dart | 41 ++++++ .../i_datasources/i_register_datasource.dart | 6 + .../repositories/register_repository.dart | 24 +++ .../presenter/register_controller.dart | 16 ++ .../register/presenter/register_page.dart | 139 +++++++++++++++--- .../modules/register/register_controller.dart | 10 -- .../app/modules/register/register_module.dart | 13 +- .../lib/app/shared/data/endpoints.dart | 1 + 15 files changed, 294 insertions(+), 35 deletions(-) create mode 100644 front/mentorme/lib/app/modules/register/domain/entities/register_entity.dart create mode 100644 front/mentorme/lib/app/modules/register/domain/entities/register_response.dart create mode 100644 front/mentorme/lib/app/modules/register/domain/i_repositories/i_register_repository.dart create mode 100644 front/mentorme/lib/app/modules/register/domain/params/register_params.dart create mode 100644 front/mentorme/lib/app/modules/register/domain/usecases/contact_history_usecase.dart create mode 100644 front/mentorme/lib/app/modules/register/external/datasources/register_datasource.dart create mode 100644 front/mentorme/lib/app/modules/register/infra/i_datasources/i_register_datasource.dart create mode 100644 front/mentorme/lib/app/modules/register/infra/repositories/register_repository.dart create mode 100644 front/mentorme/lib/app/modules/register/presenter/register_controller.dart delete mode 100644 front/mentorme/lib/app/modules/register/register_controller.dart diff --git a/front/mentorme/lib/app/modules/login/login_module.dart b/front/mentorme/lib/app/modules/login/login_module.dart index c53d56f..096d578 100644 --- a/front/mentorme/lib/app/modules/login/login_module.dart +++ b/front/mentorme/lib/app/modules/login/login_module.dart @@ -21,7 +21,7 @@ class LoginModule extends Module { ), ChildRoute( '/onboarding', - child: (__, args) => const RegisterPage(), + child: (__, args) => OnboardingPage(), transition: TransitionType.rightToLeft, ), ModuleRoute('/home', module: HomeModule()), diff --git a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart index fc225c6..5d3ac60 100644 --- a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart +++ b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart @@ -62,7 +62,7 @@ class _OnboardingPageState extends State { height: 50, child: ElevatedButton( onPressed: () { - controller.goToHome(); + controller.goToRegister(); }, child: const Text( "Iniciar", diff --git a/front/mentorme/lib/app/modules/register/domain/entities/register_entity.dart b/front/mentorme/lib/app/modules/register/domain/entities/register_entity.dart new file mode 100644 index 0000000..64fd7d2 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/domain/entities/register_entity.dart @@ -0,0 +1,20 @@ +import 'package:mentorme/app/core/domain/entities/contacts.dart'; + +class RegisterEntity { + int id; + String name; + String description; + List> contacts; + String image; + bool canTeach; + bool wantToLearn; + + RegisterEntity( + {required this.id, + required this.name, + required this.description, + required this.contacts, + required this.image, + required this.canTeach, + required this.wantToLearn}); +} diff --git a/front/mentorme/lib/app/modules/register/domain/entities/register_response.dart b/front/mentorme/lib/app/modules/register/domain/entities/register_response.dart new file mode 100644 index 0000000..64fff35 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/domain/entities/register_response.dart @@ -0,0 +1,7 @@ +import 'package:mentorme/app/core/domain/entities/mentor_entity.dart'; + +class RegisterResponse { + final int statusCode; + + RegisterResponse(this.statusCode); +} diff --git a/front/mentorme/lib/app/modules/register/domain/i_repositories/i_register_repository.dart b/front/mentorme/lib/app/modules/register/domain/i_repositories/i_register_repository.dart new file mode 100644 index 0000000..a7d3ece --- /dev/null +++ b/front/mentorme/lib/app/modules/register/domain/i_repositories/i_register_repository.dart @@ -0,0 +1,8 @@ +import 'package:dartz/dartz.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_response.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; +import 'package:mentorme/app/shared/contracts/i_error.dart'; + +abstract class IRegisterRepository { + Future> call(RegisterParams params); +} diff --git a/front/mentorme/lib/app/modules/register/domain/params/register_params.dart b/front/mentorme/lib/app/modules/register/domain/params/register_params.dart new file mode 100644 index 0000000..787b76f --- /dev/null +++ b/front/mentorme/lib/app/modules/register/domain/params/register_params.dart @@ -0,0 +1,20 @@ +import 'package:mentorme/app/modules/home/domain/entities/contact_history_entity.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_entity.dart'; + +class RegisterParams { + final RegisterEntity registerEntity; + + RegisterParams( + this.registerEntity, + ); + + Map toBodyRequest() => { + "id": registerEntity.id, + "name": registerEntity.name, + "description": registerEntity.description, + "contacts": registerEntity.contacts, + "image": registerEntity.image, + "can_teach": registerEntity.canTeach, + "want_to_learn": registerEntity.wantToLearn, + }; +} diff --git a/front/mentorme/lib/app/modules/register/domain/usecases/contact_history_usecase.dart b/front/mentorme/lib/app/modules/register/domain/usecases/contact_history_usecase.dart new file mode 100644 index 0000000..5b37aaa --- /dev/null +++ b/front/mentorme/lib/app/modules/register/domain/usecases/contact_history_usecase.dart @@ -0,0 +1,20 @@ +import 'package:dartz/dartz.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_response.dart'; +import 'package:mentorme/app/modules/register/domain/i_repositories/i_register_repository.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; +import 'package:mentorme/app/shared/contracts/i_error.dart'; + +abstract class IRegisterUsecase { + Future> call(RegisterParams params); +} + +class RegisterUsecase extends IRegisterUsecase { + final IRegisterRepository repository; + + RegisterUsecase(this.repository); + @override + Future> call(RegisterParams params) async { + final result = await repository(params); + return result; + } +} diff --git a/front/mentorme/lib/app/modules/register/external/datasources/register_datasource.dart b/front/mentorme/lib/app/modules/register/external/datasources/register_datasource.dart new file mode 100644 index 0000000..6ebecff --- /dev/null +++ b/front/mentorme/lib/app/modules/register/external/datasources/register_datasource.dart @@ -0,0 +1,41 @@ +import 'package:dio/dio.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_response.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; +import 'package:mentorme/app/modules/register/infra/i_datasources/i_register_datasource.dart'; +import 'package:mentorme/app/shared/data/api_constants.dart'; +import 'package:mentorme/app/shared/data/endpoints.dart'; +import 'package:mentorme/app/shared/errors/api_datasource_error.dart'; +import 'package:mentorme/app/shared/errors/datasource_error.dart'; +import 'package:mentorme/app/shared/errors/socket_exception_error.dart'; +import 'package:mentorme/app/shared/services/http_service/http_service.dart'; + +class RegisterDatasource extends IRegisterDatasource { + final IHttpService httpService; + + RegisterDatasource(this.httpService); + + @override + Future call(RegisterParams params) async { + try { + const _enviroment = ApiConstants.mentormeEnv; + httpService.setEnviroment(_enviroment); + httpService.disableCertificates(httpService); + + final _response = await httpService.post( + Endpoints.register, + data: params.toBodyRequest(), + ); + + return RegisterResponse(_response.statusCode ?? 0); + } on DioError catch (e, s) { + e.type == DioErrorType.connectTimeout + ? throw SocketExceptionError( + message: e.error, + stackTrace: s, + ) + : throw ApiDataSourceError.fromError(e.response?.data, s); + } catch (e, s) { + throw DataSourceError(message: e.toString(), stackTrace: s); + } + } +} diff --git a/front/mentorme/lib/app/modules/register/infra/i_datasources/i_register_datasource.dart b/front/mentorme/lib/app/modules/register/infra/i_datasources/i_register_datasource.dart new file mode 100644 index 0000000..fd8cc51 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/infra/i_datasources/i_register_datasource.dart @@ -0,0 +1,6 @@ +import 'package:mentorme/app/modules/register/domain/entities/register_response.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; + +abstract class IRegisterDatasource { + Future call(RegisterParams params); +} diff --git a/front/mentorme/lib/app/modules/register/infra/repositories/register_repository.dart b/front/mentorme/lib/app/modules/register/infra/repositories/register_repository.dart new file mode 100644 index 0000000..282050e --- /dev/null +++ b/front/mentorme/lib/app/modules/register/infra/repositories/register_repository.dart @@ -0,0 +1,24 @@ +import 'package:dartz/dartz.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_response.dart'; +import 'package:mentorme/app/modules/register/domain/i_repositories/i_register_repository.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; +import 'package:mentorme/app/modules/register/infra/i_datasources/i_register_datasource.dart'; +import 'package:mentorme/app/shared/contracts/i_error.dart'; +import 'package:mentorme/app/shared/errors/datasource_error.dart'; + +class RegisterRepository extends IRegisterRepository { + final IRegisterDatasource datasource; + + RegisterRepository(this.datasource); + @override + Future> call(RegisterParams params) async { + try { + var result = await datasource(params); + return Right(result); + } on DataSourceError catch (e) { + return Left(e); + } catch (e, s) { + return Left(DataSourceError(message: e.toString(), stackTrace: s)); + } + } +} diff --git a/front/mentorme/lib/app/modules/register/presenter/register_controller.dart b/front/mentorme/lib/app/modules/register/presenter/register_controller.dart new file mode 100644 index 0000000..abf72b8 --- /dev/null +++ b/front/mentorme/lib/app/modules/register/presenter/register_controller.dart @@ -0,0 +1,16 @@ +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_entity.dart'; +import 'package:mentorme/app/modules/register/domain/params/register_params.dart'; +import 'package:mentorme/app/modules/register/domain/usecases/contact_history_usecase.dart'; +import 'package:mentorme/app/shared/services/http_service/http_service.dart'; +import 'package:mentorme/app/shared/storage/i_custom_app_storage.dart'; + +class RegisterController { + final RegisterUsecase _registerUsecase; + + RegisterController(this._registerUsecase); + void doRegisterMentor(RegisterEntity register) async { + final params = RegisterParams(register); + final response = await _registerUsecase(params); + } +} diff --git a/front/mentorme/lib/app/modules/register/presenter/register_page.dart b/front/mentorme/lib/app/modules/register/presenter/register_page.dart index ce2ad62..4647db6 100644 --- a/front/mentorme/lib/app/modules/register/presenter/register_page.dart +++ b/front/mentorme/lib/app/modules/register/presenter/register_page.dart @@ -1,11 +1,45 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/core/domain/entities/contacts.dart'; +import 'package:mentorme/app/modules/register/domain/entities/register_entity.dart'; +import 'package:mentorme/app/modules/register/presenter/register_controller.dart'; import 'package:mentorme/app/shared/components/mentor_me_button.dart'; -import 'package:mentorme/app/shared/components/mentorme_big_app_bar.dart'; import 'package:mentorme/app/shared/components/mentorme_content_page.dart'; import 'package:mentorme/app/shared/components/mentorme_generic_big_app_bar.dart'; +import 'package:mentorme/app/shared/theme/images.dart'; + +class ContactFormField extends StatelessWidget { + const ContactFormField( + {super.key, required this.name, required this.image, this.onSaved}); + + final String name; + final AssetImage image; + final Function(String?)? onSaved; + + @override + Widget build(BuildContext context) { + return TextFormField( + decoration: InputDecoration( + hintText: name, + icon: Image( + image: image, + width: 24, + height: 24, + color: Colors.grey, + ), + ), + onSaved: onSaved, + ); + } +} class RegisterPage extends StatelessWidget { - const RegisterPage({super.key}); + RegisterPage({super.key}); + final controller = Modular.get(); + final GlobalKey _formKey = GlobalKey(); + String name = ""; + String bio = ""; + String? linkedIn, whatsapp, telegram, instagram = ""; @override Widget build(BuildContext context) { @@ -13,25 +47,92 @@ class RegisterPage extends StatelessWidget { appBar: const MentorMeGenericBigAppBar(pageName: "Criar perfil"), pageName: "Cadastro", child: Form( + key: _formKey, child: Padding( padding: const EdgeInsets.all(15.0), - child: Column( - children: [ - TextFormField( - decoration: const InputDecoration(hintText: "Nome")), - const SizedBox(height: 15), - TextFormField(decoration: const InputDecoration(hintText: "Bio")), - const SizedBox(height: 15), - TextFormField( - decoration: const InputDecoration(hintText: "Contato")), - const SizedBox(height: 15), - const MentorMeButton( - label: "Cadastrar", - isActive: true, - height: 50, - radius: 6, - ), - ], + child: SingleChildScrollView( + child: Column( + children: [ + TextFormField( + decoration: const InputDecoration(hintText: "Nome"), + onSaved: (value) { + name = value ?? ""; + }), + const SizedBox(height: 15), + TextFormField( + decoration: const InputDecoration(hintText: "Bio"), + onSaved: (value) { + bio = value ?? ""; + }), + const SizedBox(height: 15), + const Text("Contato", textAlign: TextAlign.left), + ContactFormField( + name: "LinkedIn", + image: AssetImage(ThemeImages.linkedin), + onSaved: (value) { + linkedIn = value ?? ""; + }, + ), + ContactFormField( + name: "Whatsapp", + image: AssetImage(ThemeImages.whatsapp), + onSaved: (value) { + whatsapp = value ?? ""; + }, + ), + ContactFormField( + name: "Telegram", + image: AssetImage(ThemeImages.telegram), + onSaved: (value) { + telegram = value ?? ""; + }), + ContactFormField( + name: "Instagram", + image: AssetImage(ThemeImages.instagram), + onSaved: (value) { + instagram = value ?? ""; + }), + const SizedBox(height: 15), + const Text("Habilidades", textAlign: TextAlign.left), + const SizedBox(height: 15), + const SizedBox(height: 15), + MentorMeButton( + label: "Cadastrar", + isActive: true, + height: 50, + radius: 6, + onPressed: () { + final List> contacts = []; + if (whatsapp != null) { + contacts.add({"type": "WHATSAPP", "url": whatsapp ?? ""}); + } + if (linkedIn != null) { + contacts.add({"type": "LINKEDIN", "url": linkedIn ?? ""}); + } + if (instagram != null) { + contacts + .add({"type": "INSTAGRAM", "url": instagram ?? ""}); + } + if (telegram != null) { + contacts.add({"type": "TELEGRAM", "url": telegram ?? ""}); + } + _formKey.currentState?.save(); + controller.doRegisterMentor( + RegisterEntity( + id: 0, + name: name, + description: bio, + contacts: contacts, + image: + "https://i0.wp.com/newspack-washingtoncitypaper.s3.amazonaws.com/uploads/2009/04/contexts.org_socimages_files_2009_04_d_silhouette.png?fit=1200%2C756&ssl=1", + canTeach: true, + wantToLearn: true, + ), + ); + }, + ), + ], + ), ), ), ), diff --git a/front/mentorme/lib/app/modules/register/register_controller.dart b/front/mentorme/lib/app/modules/register/register_controller.dart deleted file mode 100644 index 0fbdbd3..0000000 --- a/front/mentorme/lib/app/modules/register/register_controller.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:mentorme/app/shared/services/http_service/http_service.dart'; -import 'package:mentorme/app/shared/storage/i_custom_app_storage.dart'; - -class RegisterController { - final HttpService _httpService; - final ICustomAppStorage _storage; - - RegisterController(this._httpService, this._storage); -} diff --git a/front/mentorme/lib/app/modules/register/register_module.dart b/front/mentorme/lib/app/modules/register/register_module.dart index 130c07d..ee55af0 100644 --- a/front/mentorme/lib/app/modules/register/register_module.dart +++ b/front/mentorme/lib/app/modules/register/register_module.dart @@ -1,19 +1,24 @@ import 'package:flutter_modular/flutter_modular.dart'; -import 'package:mentorme/app/modules/home/home_module.dart'; +import 'package:mentorme/app/modules/register/domain/usecases/contact_history_usecase.dart'; +import 'package:mentorme/app/modules/register/external/datasources/register_datasource.dart'; +import 'package:mentorme/app/modules/register/infra/repositories/register_repository.dart'; import 'package:mentorme/app/modules/register/presenter/register_page.dart'; -import 'package:mentorme/app/modules/register/register_controller.dart'; +import 'package:mentorme/app/modules/register/presenter/register_controller.dart'; class RegisterModule extends Module { @override List get binds => [ - Bind((i) => RegisterController(i(), i())), + Bind((i) => RegisterController(i())), + Bind((i) => RegisterUsecase(i())), + Bind((i) => RegisterDatasource(i())), + Bind((i) => RegisterRepository(i())), ]; @override final List routes = [ ChildRoute( '/', - child: (__, args) => const RegisterPage(), + child: (__, args) => RegisterPage(), transition: TransitionType.rightToLeft, ), ]; diff --git a/front/mentorme/lib/app/shared/data/endpoints.dart b/front/mentorme/lib/app/shared/data/endpoints.dart index 27bc8ae..8f180aa 100644 --- a/front/mentorme/lib/app/shared/data/endpoints.dart +++ b/front/mentorme/lib/app/shared/data/endpoints.dart @@ -2,4 +2,5 @@ class Endpoints { static const String getMentorMe = '/person/listMentorsBySkills'; static const String contactHistory = '/contactHistory/register'; static const String listSkills = '/skill/list'; + static const String register = '/person/register'; } From d18c4e63cc4deea84021a0e428b2a8ce8efc73f8 Mon Sep 17 00:00:00 2001 From: etachott Date: Fri, 24 Mar 2023 13:44:57 -0300 Subject: [PATCH 3/3] feat: implemented simple mentor register page Co-authored-by: wleite Co-authored-by: sgkhusal --- .../lib/app/modules/home/home_module.dart | 34 ++--- .../home/presenter/home_controller.dart | 6 + .../app/modules/home/presenter/home_page.dart | 142 ++++++++++++------ .../lib/app/modules/login/login_module.dart | 1 - .../modules/login/pages/onboarding_page.dart | 2 +- .../presenter/register_controller.dart | 15 ++ .../register/presenter/register_page.dart | 133 ++++++++++++---- 7 files changed, 235 insertions(+), 98 deletions(-) diff --git a/front/mentorme/lib/app/modules/home/home_module.dart b/front/mentorme/lib/app/modules/home/home_module.dart index bd9ab87..f58e4c3 100644 --- a/front/mentorme/lib/app/modules/home/home_module.dart +++ b/front/mentorme/lib/app/modules/home/home_module.dart @@ -12,26 +12,23 @@ import 'package:mentorme/app/modules/home/presenter/home_controller.dart'; import 'package:mentorme/app/modules/home/presenter/home_page.dart'; import 'package:mentorme/app/modules/home/presenter/home_store.dart'; import 'package:mentorme/app/modules/home/presenter/mentor_profile/mentor_profile_page.dart'; - +import 'package:mentorme/app/modules/register/register_module.dart'; class HomeModule extends Module { @override List get binds => [ - Bind((i) => HomeController(i(), i(), i(), i())), - Bind((i) => HomeStore()), - - Bind((i) => GetMentorMeUsecase(i())), - Bind((i) => GetMentorMeDatasource(i())), - Bind((i) => GetMentorMeRepository(i())), - - Bind((i) => ContactHistoryUsecase(i())), - Bind((i) => ContactHistoryDatasource(i())), - Bind((i) => ContactHistoryRepository(i())), - - Bind((i) => SkillUsecase(i())), - Bind((i) => SkillDatasource(i())), - Bind((i) => SkillRepository(i())), - ]; + Bind((i) => HomeController(i(), i(), i(), i())), + Bind((i) => HomeStore()), + Bind((i) => GetMentorMeUsecase(i())), + Bind((i) => GetMentorMeDatasource(i())), + Bind((i) => GetMentorMeRepository(i())), + Bind((i) => ContactHistoryUsecase(i())), + Bind((i) => ContactHistoryDatasource(i())), + Bind((i) => ContactHistoryRepository(i())), + Bind((i) => SkillUsecase(i())), + Bind((i) => SkillDatasource(i())), + Bind((i) => SkillRepository(i())), + ]; @override final List routes = [ @@ -42,8 +39,11 @@ class HomeModule extends Module { ), ChildRoute( '/mentor_profile_page', - child: (__, args) => MentorProfilePage(mentorEntity: args.data['mentor'],), + child: (__, args) => MentorProfilePage( + mentorEntity: args.data['mentor'], + ), transition: TransitionType.rightToLeft, ), + ModuleRoute('/register', module: RegisterModule()), ]; } diff --git a/front/mentorme/lib/app/modules/home/presenter/home_controller.dart b/front/mentorme/lib/app/modules/home/presenter/home_controller.dart index 3ae8f03..355f1cd 100644 --- a/front/mentorme/lib/app/modules/home/presenter/home_controller.dart +++ b/front/mentorme/lib/app/modules/home/presenter/home_controller.dart @@ -69,6 +69,12 @@ class HomeController { ); } + void goToRegister() { + Modular.to.pushNamed( + './register', + ); + } + void goToMentorProfile() { Modular.to.pushNamed( './mentor_profile_page', diff --git a/front/mentorme/lib/app/modules/home/presenter/home_page.dart b/front/mentorme/lib/app/modules/home/presenter/home_page.dart index 9a69041..d1f63dd 100644 --- a/front/mentorme/lib/app/modules/home/presenter/home_page.dart +++ b/front/mentorme/lib/app/modules/home/presenter/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:mentorme/app/shared/components/mentor_me_button.dart'; import 'package:mentorme/app/shared/components/mentorme_air_spin_ring.dart'; import 'package:mentorme/app/shared/components/mentorme_content_page.dart'; import 'package:mentorme/app/shared/theme/theme_colors.dart'; @@ -37,7 +38,8 @@ class _HomePageState extends State { width: MediaQuery.of(context).size.width, color: ThemeColors.backgroundColour, child: Visibility( - visible: controller.store.homeState == MentorMeStates.loading, + visible: + controller.store.homeState == MentorMeStates.loading, replacement: RefreshIndicator( onRefresh: () async { controller.doFetchmentor(); @@ -47,16 +49,25 @@ class _HomePageState extends State { child: Column( children: [ Container( - margin: const EdgeInsets.only(right: 15, left: 15), + margin: + const EdgeInsets.only(right: 15, left: 15), child: Column( children: [ const SizedBox(height: 10), Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ + ElevatedButton( + onPressed: () { + controller.goToRegister(); + }, + child: const Text("Quero mentorar"), + ), InkWell( onTap: () { - controller.openBottomsheetFilterskills(); + controller + .openBottomsheetFilterskills(); }, child: Row( children: const [ @@ -69,7 +80,8 @@ class _HomePageState extends State { ), ), Icon( - Icons.keyboard_arrow_down_outlined, + Icons + .keyboard_arrow_down_outlined, color: Color(0XFF0497E3), ) ], @@ -77,55 +89,85 @@ class _HomePageState extends State { ), ], ), - controller.store.listSkillsSelected.isEmpty ? Container() : const SizedBox(height: 15), + controller.store.listSkillsSelected.isEmpty + ? Container() + : const SizedBox(height: 15), Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, children: [ SingleChildScrollView( - physics: const BouncingScrollPhysics(), + physics: + const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, child: Row( - children: controller.store.listSkillsSelected + children: controller + .store.listSkillsSelected .map( (e) => Container( - padding: const EdgeInsets.only(left: 13, right: 13), - margin: EdgeInsets.only( - right: controller.store.listSkillsSelected.last == e ? 0 : 10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - border: Border.all( - color: const Color(0xFF535353), - ), - ), - child: Row( - children: [ - Text( - e.name, - style: const TextStyle( - fontSize: 14, - color: Color(0xFF535353), - fontWeight: FontWeight.w400, + padding: + const EdgeInsets.only( + left: 13, + right: 13), + margin: EdgeInsets.only( + right: controller + .store + .listSkillsSelected + .last == + e + ? 0 + : 10), + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular( + 50), + border: Border.all( + color: const Color( + 0xFF535353), ), ), - const SizedBox(width: 10), - InkWell( - onTap: () { - controller.store.listSkillsSelected.remove(e); - controller.doFetchmentor(); - }, - child: const Icon( - Icons.close, - color: Color(0xFF535353), - ), - ) - ], - ), - ), - ).toList(), + child: Row( + children: [ + Text( + e.name, + style: + const TextStyle( + fontSize: 14, + color: Color( + 0xFF535353), + fontWeight: + FontWeight.w400, + ), + ), + const SizedBox( + width: 10), + InkWell( + onTap: () { + controller.store + .listSkillsSelected + .remove(e); + controller + .doFetchmentor(); + }, + child: const Icon( + Icons.close, + color: Color( + 0xFF535353), + ), + ) + ], + ), + ), + ) + .toList(), ), ), - controller.store.listSkillsSelected.isEmpty ? Container() : const SizedBox(height: 10), + controller.store.listSkillsSelected + .isEmpty + ? Container() + : const SizedBox(height: 10), ], ) ], @@ -133,8 +175,10 @@ class _HomePageState extends State { ), controller.store.listMentors.isEmpty ? Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, children: const [ Text( 'Nenhum mentor encontrado!', @@ -150,12 +194,16 @@ class _HomePageState extends State { children: controller.store.listMentors .map( (e) => Container( - margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 5), + margin: + const EdgeInsets.symmetric( + horizontal: 15, + vertical: 5), child: MentorCardWidget( mentor: e, ), ), - ).toList(), + ) + .toList(), ), ], ), diff --git a/front/mentorme/lib/app/modules/login/login_module.dart b/front/mentorme/lib/app/modules/login/login_module.dart index 096d578..4aec9f0 100644 --- a/front/mentorme/lib/app/modules/login/login_module.dart +++ b/front/mentorme/lib/app/modules/login/login_module.dart @@ -25,6 +25,5 @@ class LoginModule extends Module { transition: TransitionType.rightToLeft, ), ModuleRoute('/home', module: HomeModule()), - ModuleRoute('/register', module: RegisterModule()), ]; } diff --git a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart index 5d3ac60..fc225c6 100644 --- a/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart +++ b/front/mentorme/lib/app/modules/login/pages/onboarding_page.dart @@ -62,7 +62,7 @@ class _OnboardingPageState extends State { height: 50, child: ElevatedButton( onPressed: () { - controller.goToRegister(); + controller.goToHome(); }, child: const Text( "Iniciar", diff --git a/front/mentorme/lib/app/modules/register/presenter/register_controller.dart b/front/mentorme/lib/app/modules/register/presenter/register_controller.dart index abf72b8..f7d7fcb 100644 --- a/front/mentorme/lib/app/modules/register/presenter/register_controller.dart +++ b/front/mentorme/lib/app/modules/register/presenter/register_controller.dart @@ -13,4 +13,19 @@ class RegisterController { final params = RegisterParams(register); final response = await _registerUsecase(params); } + + goToHome() async { + await Future.delayed( + const Duration(milliseconds: 500), + () { + Modular.to.pushReplacementNamed( + '/home/', + forRoot: true, + arguments: { + 'wasLoginNow': false, + }, + ); + }, + ); + } } diff --git a/front/mentorme/lib/app/modules/register/presenter/register_page.dart b/front/mentorme/lib/app/modules/register/presenter/register_page.dart index 4647db6..2829916 100644 --- a/front/mentorme/lib/app/modules/register/presenter/register_page.dart +++ b/front/mentorme/lib/app/modules/register/presenter/register_page.dart @@ -1,20 +1,31 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:mentorme/app/core/domain/entities/contacts.dart'; import 'package:mentorme/app/modules/register/domain/entities/register_entity.dart'; import 'package:mentorme/app/modules/register/presenter/register_controller.dart'; import 'package:mentorme/app/shared/components/mentor_me_button.dart'; +import 'package:mentorme/app/shared/components/mentorme_alert.dart'; import 'package:mentorme/app/shared/components/mentorme_content_page.dart'; import 'package:mentorme/app/shared/components/mentorme_generic_big_app_bar.dart'; import 'package:mentorme/app/shared/theme/images.dart'; class ContactFormField extends StatelessWidget { const ContactFormField( - {super.key, required this.name, required this.image, this.onSaved}); + {super.key, + this.name, + required this.image, + this.onSaved, + this.prefixIcon, + this.keyboardType, + this.inputFormatters}); - final String name; + final String? name; final AssetImage image; final Function(String?)? onSaved; + final Widget? prefixIcon; + final TextInputType? keyboardType; + final List? inputFormatters; @override Widget build(BuildContext context) { @@ -27,8 +38,12 @@ class ContactFormField extends StatelessWidget { height: 24, color: Colors.grey, ), + prefixIcon: prefixIcon, + prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0), ), onSaved: onSaved, + keyboardType: keyboardType, + inputFormatters: inputFormatters, ); } } @@ -39,7 +54,7 @@ class RegisterPage extends StatelessWidget { final GlobalKey _formKey = GlobalKey(); String name = ""; String bio = ""; - String? linkedIn, whatsapp, telegram, instagram = ""; + String? linkedIn, whatsapp, telegram, instagram; @override Widget build(BuildContext context) { @@ -54,16 +69,30 @@ class RegisterPage extends StatelessWidget { child: Column( children: [ TextFormField( - decoration: const InputDecoration(hintText: "Nome"), - onSaved: (value) { - name = value ?? ""; - }), + decoration: const InputDecoration(hintText: "Nome"), + onSaved: (value) { + name = value ?? ""; + }, + validator: (value) { + if (value == null || value.isEmpty) { + return ("Esse campo não pode ser vazio!!"); + } + return null; + }, + ), const SizedBox(height: 15), TextFormField( - decoration: const InputDecoration(hintText: "Bio"), - onSaved: (value) { - bio = value ?? ""; - }), + decoration: const InputDecoration(hintText: "Bio"), + onSaved: (value) { + bio = value ?? "null"; + }, + validator: (value) { + if (value == null || value.isEmpty) { + return ("Esse campo não pode ser vazio!!"); + } + return null; + }, + ), const SizedBox(height: 15), const Text("Contato", textAlign: TextAlign.left), ContactFormField( @@ -72,6 +101,10 @@ class RegisterPage extends StatelessWidget { onSaved: (value) { linkedIn = value ?? ""; }, + prefixIcon: Text( + "linkedin.com/in/", + style: TextStyle(fontSize: 17), + ), ), ContactFormField( name: "Whatsapp", @@ -79,21 +112,31 @@ class RegisterPage extends StatelessWidget { onSaved: (value) { whatsapp = value ?? ""; }, + prefixIcon: Text("+55 ", style: TextStyle(fontSize: 17)), + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], ), ContactFormField( - name: "Telegram", - image: AssetImage(ThemeImages.telegram), - onSaved: (value) { - telegram = value ?? ""; - }), + name: "Telegram", + image: AssetImage(ThemeImages.telegram), + onSaved: (value) { + telegram = value ?? ""; + }, + prefixIcon: + Text("telegram.me/", style: TextStyle(fontSize: 17)), + ), ContactFormField( - name: "Instagram", - image: AssetImage(ThemeImages.instagram), - onSaved: (value) { - instagram = value ?? ""; - }), + name: "Instagram", + image: AssetImage(ThemeImages.instagram), + onSaved: (value) { + instagram = value ?? ""; + }, + prefixIcon: Text("@", style: TextStyle(fontSize: 17)), + ), const SizedBox(height: 15), - const Text("Habilidades", textAlign: TextAlign.left), + // const Text("Habilidades", textAlign: TextAlign.left), const SizedBox(height: 15), const SizedBox(height: 15), MentorMeButton( @@ -102,21 +145,46 @@ class RegisterPage extends StatelessWidget { height: 50, radius: 6, onPressed: () { + _formKey.currentState?.save(); final List> contacts = []; - if (whatsapp != null) { - contacts.add({"type": "WHATSAPP", "url": whatsapp ?? ""}); + if (whatsapp != null && whatsapp!.isNotEmpty) { + contacts.add({ + "type": "WHATSAPP", + "url": + "https://api.whatsapp.com/send?phone=55$whatsapp&Olá, encontrei seu contato no Mentorme e gostaria de agendar uma mentoria com você. Qual é a sua disponibilidade para falarmos?" + }); } - if (linkedIn != null) { - contacts.add({"type": "LINKEDIN", "url": linkedIn ?? ""}); + if (linkedIn != null && linkedIn!.isNotEmpty) { + contacts.add({ + "type": "LINKEDIN", + "url": "https://linkedin.com/in/$linkedIn" + }); } - if (instagram != null) { - contacts - .add({"type": "INSTAGRAM", "url": instagram ?? ""}); + if (instagram != null && instagram!.isNotEmpty) { + contacts.add({ + "type": "INSTAGRAM", + "url": "https://instagram.com/$instagram" + }); } - if (telegram != null) { - contacts.add({"type": "TELEGRAM", "url": telegram ?? ""}); + if (telegram != null && telegram!.isNotEmpty) { + contacts.add({ + "type": "TELEGRAM", + "url": "https://telegram.me/$telegram" + }); + } + if (name.isEmpty || bio.isEmpty) { + return (MentorMeAlerts.showInfo( + title: "Erro de validação", + description: "Nome e Bio não podem ser vazios!", + alertHeight: 120, + )); + } + if (contacts.isEmpty) { + return (MentorMeAlerts.showInfo( + title: "Erro de validação", + description: "Adicione pelo menos um contato!", + )); } - _formKey.currentState?.save(); controller.doRegisterMentor( RegisterEntity( id: 0, @@ -129,6 +197,7 @@ class RegisterPage extends StatelessWidget { wantToLearn: true, ), ); + controller.goToHome(); }, ), ],