Skip to content

Commit

Permalink
feat: adds Reset Password Screen
Browse files Browse the repository at this point in the history
  • Loading branch information
am-casper committed Dec 22, 2023
1 parent 533278c commit cc5df7e
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 6 deletions.
1 change: 1 addition & 0 deletions lib/data/core/router/registry/paths.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ class AppPathsRegistry {
static const String weekMenu = 'weekMenu';
static const String leavesAndRebate = 'leavesAndRebate';
static const String feedback = 'feedback';
static const String resetPassword = 'resetPassword';
}
4 changes: 4 additions & 0 deletions lib/data/core/router/registry/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class AppRoutesRegistry {
path: AppPathsRegistry.feedback,
page: FeedbackRoute.page,
),
CustomRoute(
path: AppPathsRegistry.resetPassword,
page: ResetPasswordRoute.page,
),
],
),
];
Expand Down
7 changes: 1 addition & 6 deletions lib/presentation/profile/profile_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,7 @@ class ProfileScreen extends StatelessWidget {
ProfileTextButton(
title: 'Reset Password',
onPressed: () {
const snackBar = SnackBar(
content: Text('Coming soon!'),
duration: Duration(milliseconds: 500),
);
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
context.router.push(ResetPasswordRoute());
},
),
],
Expand Down
57 changes: 57 additions & 0 deletions lib/presentation/reset_password/bloc/reset_password_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:async';

import 'package:appetizer/data/constants/constants.dart';
import 'package:appetizer/domain/repositories/user/user_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

part 'reset_password_event.dart';
part 'reset_password_state.dart';

class ResetPasswordBloc extends Bloc<ResetPasswordEvent, ResetPasswordState> {
final UserRepository userRepository;
ResetPasswordBloc({required this.userRepository})
: super(const ResetPasswordInitial()) {
on<ResetPasswordPressed>(_onResetPasswordPressed);
on<ToggleObscureResetPassword>(_onToggleObscureResetPassword);
}

FutureOr<void> _onResetPasswordPressed(event, emit) async {
if (event.newPassword.length < 8) {
emit(
const ResetPasswordInitial(
error: 'Password must be at least 8 characters long',
),
);
return;
}
if (event.newPassword != event.confirmPassword) {
emit(
const ResetPasswordInitial(
error: 'Passwords do not match',
),
);
return;
}
emit(Loading());
try {
await userRepository.changePassword(
event.oldPassword,
event.newPassword,
);
emit(const ResetPasswordSuccess());
} catch (e) {
emit(const ResetPasswordInitial(error: AppConstants.GENERIC_FAILURE));
}
}

FutureOr<void> _onToggleObscureResetPassword(event, emit) async {
emit(
(state as ResetPassword).copyWith(
showOldPassword: event.showOldPassword,
showNewPassword: event.showNewPassword,
showConfirmPassword: event.showConfirmPassword,
),
);
}
}
22 changes: 22 additions & 0 deletions lib/presentation/reset_password/bloc/reset_password_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
part of 'reset_password_bloc.dart';

abstract class ResetPasswordEvent {}

class ResetPasswordPressed extends ResetPasswordEvent {
final String oldPassword;
final String newPassword;
final String confirmPassword;
ResetPasswordPressed(
this.oldPassword, this.newPassword, this.confirmPassword);
}

class ToggleObscureResetPassword extends ResetPasswordEvent {
final bool showOldPassword;
final bool showNewPassword;
final bool showConfirmPassword;
ToggleObscureResetPassword({
required this.showOldPassword,
required this.showNewPassword,
required this.showConfirmPassword,
});
}
51 changes: 51 additions & 0 deletions lib/presentation/reset_password/bloc/reset_password_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
part of 'reset_password_bloc.dart';

abstract class ResetPasswordState extends Equatable {
const ResetPasswordState();

@override
List<Object?> get props => [];
}

class ResetPasswordInitial extends ResetPasswordState {
const ResetPasswordInitial({this.error});

final String? error;

@override
List<Object?> get props => [error];
}

class Loading extends ResetPasswordState {}

class ResetPasswordSuccess extends ResetPasswordState {
const ResetPasswordSuccess();
}

class ResetPassword extends ResetPasswordState {
const ResetPassword({
required this.showOldPassword,
required this.showNewPassword,
required this.showConfirmPassword,
});

final bool showOldPassword;
final bool showNewPassword;
final bool showConfirmPassword;

ResetPassword copyWith({
bool? showOldPassword,
bool? showNewPassword,
bool? showConfirmPassword,
}) {
return ResetPassword(
showOldPassword: showOldPassword ?? this.showOldPassword,
showNewPassword: showNewPassword ?? this.showNewPassword,
showConfirmPassword: showConfirmPassword ?? this.showConfirmPassword,
);
}

@override
List<Object?> get props =>
[showOldPassword, showNewPassword, showConfirmPassword];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:appetizer/app_theme.dart';
import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
import 'package:appetizer/presentation/components/app_banner.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';

class ResetPasswordBanner extends StatelessWidget {
const ResetPasswordBanner({super.key});

@override
Widget build(BuildContext context) {
return AppBanner(
height: 140.toAutoScaledHeight,
child: Row(
children: [
IconButton(
onPressed: context.router.pop,
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
),
),
Text(
"Reset Password",
style: AppTheme.headline1,
),
],
),
// ),
);
}
}
170 changes: 170 additions & 0 deletions lib/presentation/reset_password/reset_password_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
import 'package:appetizer/presentation/components/loading_indicator.dart';
import 'package:appetizer/presentation/login/components/login_button.dart';
import 'package:appetizer/presentation/reset_password/bloc/reset_password_bloc.dart';
import 'package:appetizer/presentation/reset_password/components/ResetPasswordTile/reset_password_banner.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';

@RoutePage()
class ResetPasswordScreen extends StatelessWidget {
final TextEditingController _oldPasswordController = TextEditingController();
final TextEditingController _newPasswordController = TextEditingController();
final TextEditingController _confirmPasswordController =
TextEditingController();
ResetPasswordScreen({super.key});

@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ResetPasswordBloc(userRepository: context.read()),
child: Scaffold(
backgroundColor: Colors.white,
body: BlocConsumer<ResetPasswordBloc, ResetPasswordState>(
listener: (context, state) {
if (state is ResetPasswordInitial && state.error != null) {
_confirmPasswordController.clear();
_newPasswordController.clear();
_oldPasswordController.clear();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.error!),
backgroundColor: Colors.red,
),
);
}
if (state is ResetPasswordSuccess) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Password reset successfully!'),
backgroundColor: Colors.green,
));
context.router.pop();
}
},
builder: (context, state) {
if (state is ResetPasswordInitial) {
return Column(
children: [
const ResetPasswordBanner(),
Expanded(
child: SingleChildScrollView(
padding: 24.toHorizontalPadding,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Enter your old password',
style: GoogleFonts.notoSans(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
20.toVerticalSizedBox,
TextField(
controller: _oldPasswordController,
obscureText: true,
decoration: InputDecoration(
hintText: 'Old Password',
hintStyle: GoogleFonts.lato(
fontSize: 12.toAutoScaledFont,
color: const Color(0xFF111111),
fontWeight: FontWeight.w600,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: const Color(0xFF111111)
.withOpacity(0.25)),
borderRadius: BorderRadius.circular(5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 20.toAutoScaledWidth),
),
),
20.toVerticalSizedBox,
Text(
'Enter your new password',
style: GoogleFonts.notoSans(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
20.toVerticalSizedBox,
TextField(
controller: _newPasswordController,
obscureText: true,
decoration: InputDecoration(
hintText: 'New Password',
hintStyle: GoogleFonts.lato(
fontSize: 12.toAutoScaledFont,
color: const Color(0xFF111111),
fontWeight: FontWeight.w600,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: const Color(0xFF111111)
.withOpacity(0.25)),
borderRadius: BorderRadius.circular(5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 20.toAutoScaledWidth),
),
),
20.toVerticalSizedBox,
Text(
'Confirm your new password',
style: GoogleFonts.notoSans(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
20.toVerticalSizedBox,
TextField(
controller: _confirmPasswordController,
obscureText: true,
decoration: InputDecoration(
hintText: 'Confirm Password',
hintStyle: GoogleFonts.lato(
fontSize: 12.toAutoScaledFont,
color: const Color(0xFF111111),
fontWeight: FontWeight.w600,
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: const Color(0xFF111111)
.withOpacity(0.25)),
borderRadius: BorderRadius.circular(5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 20.toAutoScaledWidth),
),
),
20.toVerticalSizedBox,
Center(
child: LoginButton(
text: "Reset Password",
onPressed: () {
context.read<ResetPasswordBloc>().add(
ResetPasswordPressed(
_oldPasswordController.text,
_newPasswordController.text,
_confirmPasswordController.text));
},
),
),
],
),
),
),
],
);
}
return const Center(child: LoadingIndicator());
},
),
),
);
}
}

0 comments on commit cc5df7e

Please sign in to comment.