diff --git a/lib/application/auth/login_form/login_form_bloc.dart b/lib/application/auth/login_form/login_form_bloc.dart index f14a8e1..47d7a75 100644 --- a/lib/application/auth/login_form/login_form_bloc.dart +++ b/lib/application/auth/login_form/login_form_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:bloc/bloc.dart'; import 'package:dartz/dartz.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -41,6 +43,10 @@ class LoginFormBloc extends Bloc { final phoneNumberValid = state.phoneNumber.isNotEmpty; final passwordValid = state.password.isNotEmpty; + log( + 'phoneNumberValid: $phoneNumberValid, passwordValid: $passwordValid, phoneNumber: ${state.phoneNumber}, password: ${state.password}', + ); + if (phoneNumberValid && passwordValid) { failureOrLogin = await _authRepository.login( phoneNumber: state.phoneNumber, diff --git a/lib/common/api/api_client.dart b/lib/common/api/api_client.dart index 0a9d355..5e2aafe 100644 --- a/lib/common/api/api_client.dart +++ b/lib/common/api/api_client.dart @@ -27,6 +27,7 @@ class ApiClient { ApiClient(this._dio, this._env) { _dio.options.baseUrl = _env.baseUrl; _dio.options.connectTimeout = const Duration(seconds: 20); + _dio.options.validateStatus = (status) => true; _dio.interceptors.add(BadNetworkErrorInterceptor()); _dio.interceptors.add(BadRequestErrorInterceptor()); _dio.interceptors.add(InternalServerErrorInterceptor()); diff --git a/lib/common/url/api_path.dart b/lib/common/url/api_path.dart index a897741..4a7cf4c 100644 --- a/lib/common/url/api_path.dart +++ b/lib/common/url/api_path.dart @@ -3,6 +3,6 @@ class ApiPath { static String register = '/api/v1/customer-auth/register/start'; static String verify = '/api/v1/customer-auth/register/verify-otp'; static String setPassword = '/api/v1/customer-auth/register/set-password'; - static String login = '/api/v1/customer-auth/register/login'; + static String login = '/api/v1/customer-auth/login'; static String resend = '/api/v1/customer-auth/register/resend-otp'; } diff --git a/lib/presentation/components/field/password_text_form_page.dart b/lib/presentation/components/field/password_text_form_page.dart index fdb5f58..01c36ac 100644 --- a/lib/presentation/components/field/password_text_form_page.dart +++ b/lib/presentation/components/field/password_text_form_page.dart @@ -10,6 +10,7 @@ class AppPasswordTextFormField extends StatefulWidget { this.prefixIcon, this.keyboardType, this.onChanged, + this.validator, }); final String? hintText; @@ -19,6 +20,7 @@ class AppPasswordTextFormField extends StatefulWidget { final Widget? prefixIcon; final TextInputType? keyboardType; final ValueChanged? onChanged; + final String? Function(String?)? validator; @override State createState() => @@ -26,7 +28,7 @@ class AppPasswordTextFormField extends StatefulWidget { } class _AppPasswordTextFormFieldState extends State { - bool isPasswordVisible = false; + bool isPasswordVisible = true; @override Widget build(BuildContext context) { return Column( @@ -48,6 +50,7 @@ class _AppPasswordTextFormFieldState extends State { color: AppColor.textPrimary, fontWeight: FontWeight.w500, ), + validator: widget.validator, decoration: InputDecoration( hintText: widget.hintText, prefixIcon: widget.prefixIcon, diff --git a/lib/presentation/pages/auth/login/login_page.dart b/lib/presentation/pages/auth/login/login_page.dart index ce827f2..ba71dd9 100644 --- a/lib/presentation/pages/auth/login/login_page.dart +++ b/lib/presentation/pages/auth/login/login_page.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../application/auth/check_phone_form/check_phone_form_bloc.dart'; +import '../../../../common/function/app_function.dart'; import '../../../../common/theme/theme.dart'; import '../../../../domain/auth/auth.dart'; import '../../../../injection.dart'; @@ -35,7 +36,9 @@ class LoginPage extends StatelessWidget implements AutoRouteWrapper { context.router.push(RegisterRoute()); } else if (data.status.isPasswordRequired) { context.router.push( - PasswordRoute(phoneNumber: data.phoneNumber), + PasswordRoute( + phoneNumber: getNormalizePhone(state.phoneNumber), + ), ); } }); diff --git a/lib/presentation/pages/auth/password/password_page.dart b/lib/presentation/pages/auth/password/password_page.dart index cfed788..3554506 100644 --- a/lib/presentation/pages/auth/password/password_page.dart +++ b/lib/presentation/pages/auth/password/password_page.dart @@ -1,46 +1,103 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../application/auth/login_form/login_form_bloc.dart'; +import '../../../../injection.dart'; import '../../../components/button/button.dart'; import '../../../components/field/field.dart'; +import '../../../components/toast/flushbar.dart'; import '../../../router/app_router.gr.dart'; @RoutePage() -class PasswordPage extends StatelessWidget { +class PasswordPage extends StatelessWidget implements AutoRouteWrapper { final String phoneNumber; const PasswordPage({super.key, required this.phoneNumber}); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Kata Sandi')), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 40), + return BlocListener( + listenWhen: (p, c) => p.failureOrLoginOption != c.failureOrLoginOption, + listener: (context, state) { + state.failureOrLoginOption.fold( + () => null, + (either) => either.fold( + (f) => AppFlushbar.showAuthFailureToast(context, f), + (data) { + AppFlushbar.showSuccess(context, data.message); + Future.delayed(Duration(milliseconds: 1000), () { + context.router.replaceAll([MainRoute()]); + }); + }, + ), + ); + }, + child: Scaffold( + appBar: AppBar(title: const Text('Kata Sandi')), + body: BlocBuilder( + builder: (context, state) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Form( + autovalidateMode: state.showErrorMessages + ? AutovalidateMode.always + : AutovalidateMode.disabled, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 40), - // Title - AppPasswordTextFormField( - title: 'Masukkan kata sandi', - hintText: '********', - ), + // Title + AppPasswordTextFormField( + title: 'Masukkan kata sandi', + hintText: '********', + onChanged: (value) => context.read().add( + LoginFormEvent.passwordChanged(value), + ), + validator: (value) { + if (context + .read() + .state + .password + .isEmpty) { + return 'Masukkan kata sandi'; + } - const SizedBox(height: 50), + return null; + }, + ), - Spacer(), + const SizedBox(height: 50), - // Continue Button - AppElevatedButton( - onPressed: () => context.router.push(const MainRoute()), - title: 'Konfirmasi', - ), + Spacer(), - const SizedBox(height: 24), - ], + // Continue Button + AppElevatedButton( + onPressed: state.isSubmitting + ? null + : () => context.read().add( + LoginFormEvent.submitted(), + ), + title: 'Konfirmasi', + isLoading: state.isSubmitting, + ), + + const SizedBox(height: 24), + ], + ), + ), + ); + }, ), ), ); } + + @override + Widget wrappedRoute(BuildContext context) => BlocProvider( + create: (context) => + getIt() + ..add(LoginFormEvent.phoneNumberChanged(phoneNumber)), + child: this, + ); }