From 2e00207343c4de6c70b7e1a5253f7a9b3fc23eef Mon Sep 17 00:00:00 2001 From: efrilm Date: Thu, 18 Sep 2025 09:17:25 +0700 Subject: [PATCH] Set Password --- .../datasources/remote_data_provider.dart | 8 +- .../components/toast/flushbar.dart | 4 +- .../create_password/create_password_page.dart | 142 ++++++++++++++---- lib/presentation/pages/auth/otp/otp_page.dart | 19 ++- lib/presentation/router/app_router.gr.dart | 37 ++++- 5 files changed, 170 insertions(+), 40 deletions(-) diff --git a/lib/infrastructure/auth/datasources/remote_data_provider.dart b/lib/infrastructure/auth/datasources/remote_data_provider.dart index ffa8d6c..579a3ae 100644 --- a/lib/infrastructure/auth/datasources/remote_data_provider.dart +++ b/lib/infrastructure/auth/datasources/remote_data_provider.dart @@ -161,12 +161,18 @@ class AuthRemoteDataProvider { if (response.data['success'] == false) { if ((response.data['errors'] as List).isNotEmpty) { - if (response.data['errors'][0]['code'] == "900") { + if (response.data['errors'][0]['code'] == 900) { return DC.error( AuthFailure.dynamicErrorMessage( 'Invalid Registration, Lakukan kembali dari awal', ), ); + } else if (response.data['errors'][0]['code'] == "304") { + return DC.error( + AuthFailure.dynamicErrorMessage( + response.data['errors'][0]['cause'], + ), + ); } else { return DC.error( AuthFailure.dynamicErrorMessage( diff --git a/lib/presentation/components/toast/flushbar.dart b/lib/presentation/components/toast/flushbar.dart index 845967c..0529649 100644 --- a/lib/presentation/components/toast/flushbar.dart +++ b/lib/presentation/components/toast/flushbar.dart @@ -16,7 +16,7 @@ class AppFlushbar { ), icon: const Icon(Icons.check_circle, color: Colors.white), duration: const Duration(seconds: 2), - flushbarPosition: FlushbarPosition.BOTTOM, + flushbarPosition: FlushbarPosition.TOP, backgroundColor: AppColor.secondary, borderRadius: BorderRadius.circular(12), margin: const EdgeInsets.all(12), @@ -35,7 +35,7 @@ class AppFlushbar { ), icon: const Icon(Icons.error, color: Colors.white), duration: const Duration(seconds: 3), - flushbarPosition: FlushbarPosition.BOTTOM, + flushbarPosition: FlushbarPosition.TOP, backgroundColor: AppColor.error, borderRadius: BorderRadius.circular(12), margin: const EdgeInsets.all(12), diff --git a/lib/presentation/pages/auth/create_password/create_password_page.dart b/lib/presentation/pages/auth/create_password/create_password_page.dart index a8ec3a2..48d912f 100644 --- a/lib/presentation/pages/auth/create_password/create_password_page.dart +++ b/lib/presentation/pages/auth/create_password/create_password_page.dart @@ -1,50 +1,134 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../application/auth/set_password/set_password_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 CreatePasswordPage extends StatelessWidget { - const CreatePasswordPage({super.key}); +class CreatePasswordPage extends StatelessWidget implements AutoRouteWrapper { + final String registrationToken; + const CreatePasswordPage({super.key, required this.registrationToken}); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Buat 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.failureOrSetPasswordOption != c.failureOrSetPasswordOption, + listener: (context, state) { + state.failureOrSetPasswordOption.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('Buat Kata Sandi')), + body: BlocBuilder( + builder: (context, state) { + return Form( + autovalidateMode: state.showErrorMessages + ? AutovalidateMode.always + : AutovalidateMode.disabled, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 40), - // Title - AppPasswordTextFormField( - title: 'Masukkan kata sandi', - hintText: '********', - ), - SizedBox(height: 24), - AppPasswordTextFormField( - title: 'Ulangi kata sandi', - hintText: '********', - ), + // Title + AppPasswordTextFormField( + title: 'Masukkan kata sandi', + hintText: '********', + onChanged: (value) => context + .read() + .add(SetPasswordFormEvent.passwordChanged(value)), + validator: (value) { + if (context + .read() + .state + .password + .isEmpty) { + return 'Masukkan kata sandi'; + } - const SizedBox(height: 50), + return null; + }, + ), + SizedBox(height: 24), + AppPasswordTextFormField( + title: 'Ulangi kata sandi', + hintText: '********', + onChanged: (value) => + context.read().add( + SetPasswordFormEvent.confirmPasswordChanged(value), + ), + validator: (value) { + if (context + .read() + .state + .password + .isEmpty) { + return 'Masukkan kata sandi'; + } - Spacer(), + if (context + .read() + .state + .password != + context + .read() + .state + .confirmPassword) { + return 'Kata sandi tidak cocok'; + } - // Continue Button - AppElevatedButton( - onPressed: () => context.router.push(const MainRoute()), - title: 'Konfirmasi', - ), + return null; + }, + ), - const SizedBox(height: 24), - ], + const SizedBox(height: 50), + + Spacer(), + + // Continue Button + AppElevatedButton( + onPressed: state.isSubmitting + ? null + : () => context.read().add( + SetPasswordFormEvent.submitted(), + ), + title: 'Konfirmasi', + isLoading: state.isSubmitting, + ), + + const SizedBox(height: 24), + ], + ), + ), + ); + }, ), ), ); } + + @override + Widget wrappedRoute(BuildContext context) => BlocProvider( + create: (context) => getIt() + ..add(SetPasswordFormEvent.registrationTokenChanged(registrationToken)), + child: this, + ); } diff --git a/lib/presentation/pages/auth/otp/otp_page.dart b/lib/presentation/pages/auth/otp/otp_page.dart index 83d200d..44a887f 100644 --- a/lib/presentation/pages/auth/otp/otp_page.dart +++ b/lib/presentation/pages/auth/otp/otp_page.dart @@ -143,10 +143,21 @@ class _OtpPageState extends State { (either) => either.fold( (f) => AppFlushbar.showAuthFailureToast(context, f), (data) { - AppFlushbar.showSuccess(context, data.message); - Future.delayed(Duration(milliseconds: 1000), () { - context.router.push(CreatePasswordRoute()); - }); + if (data.status == "FAILED") { + AppFlushbar.showSuccess(context, data.message); + Future.delayed(Duration(milliseconds: 1000), () { + context.router.replaceAll([LoginRoute()]); + }); + } else { + AppFlushbar.showSuccess(context, data.message); + Future.delayed(Duration(milliseconds: 1000), () { + context.router.push( + CreatePasswordRoute( + registrationToken: widget.registrationToken, + ), + ); + }); + } }, ), ); diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index f959757..eda2b70 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -102,20 +102,49 @@ class AddressRoute extends _i33.PageRouteInfo { /// generated route for /// [_i3.CreatePasswordPage] -class CreatePasswordRoute extends _i33.PageRouteInfo { - const CreatePasswordRoute({List<_i33.PageRouteInfo>? children}) - : super(CreatePasswordRoute.name, initialChildren: children); +class CreatePasswordRoute extends _i33.PageRouteInfo { + CreatePasswordRoute({ + _i34.Key? key, + required String registrationToken, + List<_i33.PageRouteInfo>? children, + }) : super( + CreatePasswordRoute.name, + args: CreatePasswordRouteArgs( + key: key, + registrationToken: registrationToken, + ), + initialChildren: children, + ); static const String name = 'CreatePasswordRoute'; static _i33.PageInfo page = _i33.PageInfo( name, builder: (data) { - return const _i3.CreatePasswordPage(); + final args = data.argsAs(); + return _i33.WrappedRoute( + child: _i3.CreatePasswordPage( + key: args.key, + registrationToken: args.registrationToken, + ), + ); }, ); } +class CreatePasswordRouteArgs { + const CreatePasswordRouteArgs({this.key, required this.registrationToken}); + + final _i34.Key? key; + + final String registrationToken; + + @override + String toString() { + return 'CreatePasswordRouteArgs{key: $key, registrationToken: $registrationToken}'; + } +} + /// generated route for /// [_i4.DrawDetailPage] class DrawDetailRoute extends _i33.PageRouteInfo {