2 Commits

Author SHA1 Message Date
0c6229331f Merge pull request 'Password field checks for match with old password from db and check so that new password feild matches with the confirm password field' (#143) from SEND013 into main
Some checks failed
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/chain_gateway Pipeline is pending
ci/woodpecker/push/db Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/mntx_gateway Pipeline is pending
ci/woodpecker/push/nats Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #143
2025-12-24 16:07:58 +00:00
Arseni
43020f3eb6 Password field checks for match with old password from db and check so that new password feild matches with the confirm password field 2025-12-24 16:18:52 +03:00
7 changed files with 93 additions and 10 deletions

View File

@@ -10,6 +10,8 @@ class ConfirmPasswordField extends StatelessWidget {
required this.newPasswordController,
required this.missingPasswordError,
required this.passwordsDoNotMatchError,
required this.obscureText,
required this.onToggleVisibility,
});
final TextEditingController controller;
@@ -19,6 +21,8 @@ class ConfirmPasswordField extends StatelessWidget {
final TextEditingController newPasswordController;
final String missingPasswordError;
final String passwordsDoNotMatchError;
final bool obscureText;
final VoidCallback onToggleVisibility;
@override
Widget build(BuildContext context) {
@@ -26,11 +30,18 @@ class ConfirmPasswordField extends StatelessWidget {
width: fieldWidth,
child: TextFormField(
controller: controller,
obscureText: true,
obscureText: obscureText,
enabled: isEnabled,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
labelText: confirmPasswordLabel,
border: const OutlineInputBorder(),
suffixIcon: IconButton(
onPressed: onToggleVisibility,
icon: Icon(
obscureText ? Icons.visibility_off : Icons.visibility,
),
),
),
validator: (value) {
if (value == null || value.isEmpty) return missingPasswordError;

View File

@@ -7,6 +7,8 @@ class PasswordField extends StatelessWidget {
required this.labelText,
required this.fieldWidth,
required this.isEnabled,
required this.obscureText,
required this.onToggleVisibility,
required this.validator,
});
@@ -14,6 +16,8 @@ class PasswordField extends StatelessWidget {
final String labelText;
final double fieldWidth;
final bool isEnabled;
final bool obscureText;
final VoidCallback onToggleVisibility;
final String? Function(String?) validator;
@override
@@ -22,11 +26,18 @@ class PasswordField extends StatelessWidget {
width: fieldWidth,
child: TextFormField(
controller: controller,
obscureText: true,
obscureText: obscureText,
enabled: isEnabled,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
labelText: labelText,
border: const OutlineInputBorder(),
suffixIcon: IconButton(
onPressed: onToggleVisibility,
icon: Icon(
obscureText ? Icons.visibility_off : Icons.visibility,
),
),
),
validator: validator,
),

View File

@@ -18,6 +18,12 @@ class PasswordFields extends StatelessWidget {
required this.fieldWidth,
required this.gapSmall,
required this.isEnabled,
required this.showOldPassword,
required this.showNewPassword,
required this.showConfirmPassword,
required this.onToggleOldPassword,
required this.onToggleNewPassword,
required this.onToggleConfirmPassword,
});
final TextEditingController oldPasswordController;
@@ -31,6 +37,12 @@ class PasswordFields extends StatelessWidget {
final double fieldWidth;
final double gapSmall;
final bool isEnabled;
final bool showOldPassword;
final bool showNewPassword;
final bool showConfirmPassword;
final VoidCallback onToggleOldPassword;
final VoidCallback onToggleNewPassword;
final VoidCallback onToggleConfirmPassword;
@override
Widget build(BuildContext context) {
@@ -41,6 +53,8 @@ class PasswordFields extends StatelessWidget {
labelText: oldPasswordLabel,
fieldWidth: fieldWidth,
isEnabled: isEnabled,
obscureText: !showOldPassword,
onToggleVisibility: onToggleOldPassword,
validator: (value) =>
(value == null || value.isEmpty) ? missingPasswordError : null,
),
@@ -50,6 +64,8 @@ class PasswordFields extends StatelessWidget {
labelText: newPasswordLabel,
fieldWidth: fieldWidth,
isEnabled: isEnabled,
obscureText: !showNewPassword,
onToggleVisibility: onToggleNewPassword,
validator: (value) =>
(value == null || value.isEmpty) ? missingPasswordError : null,
),
@@ -62,6 +78,8 @@ class PasswordFields extends StatelessWidget {
newPasswordController: newPasswordController,
missingPasswordError: missingPasswordError,
passwordsDoNotMatchError: passwordsDoNotMatchError,
obscureText: !showConfirmPassword,
onToggleVisibility: onToggleConfirmPassword,
),
],
);

View File

@@ -0,0 +1 @@
enum PasswordFieldType { old, newPassword, confirmPassword }

View File

@@ -0,0 +1 @@
enum VisibilityState { hidden, visible }

View File

@@ -4,6 +4,7 @@ import 'package:pshared/provider/account.dart';
import 'package:pshared/widgets/password/fields.dart';
import 'package:pshared/utils/snackbar.dart';
import 'package:pweb/models/password_field_type.dart';
import 'package:pweb/providers/password_form.dart';
import 'package:pweb/pages/settings/profile/account/password/form/error_text.dart';
import 'package:pweb/pages/settings/profile/account/password/form/submit_button.dart';
@@ -65,6 +66,18 @@ class PasswordForm extends StatelessWidget {
fieldWidth: _fieldWidth,
gapSmall: _gapSmall,
isEnabled: !isFormBusy,
showOldPassword:
formProvider.isPasswordVisible(PasswordFieldType.old),
showNewPassword:
formProvider.isPasswordVisible(PasswordFieldType.newPassword),
showConfirmPassword: formProvider
.isPasswordVisible(PasswordFieldType.confirmPassword),
onToggleOldPassword: () =>
formProvider.togglePasswordVisibility(PasswordFieldType.old),
onToggleNewPassword: () => formProvider
.togglePasswordVisibility(PasswordFieldType.newPassword),
onToggleConfirmPassword: () => formProvider
.togglePasswordVisibility(PasswordFieldType.confirmPassword),
),
const SizedBox(height: _gapMedium),
PasswordSubmitButton(
@@ -72,10 +85,11 @@ class PasswordForm extends StatelessWidget {
label: savePassword,
onSubmit: () async {
try {
await formProvider.submit(
final success = await formProvider.submit(
accountProvider: accountProvider,
errorText: errorText,
);
if (!success) return;
if (!context.mounted) return;
notifyUser(context, successText);
} catch (e) {

View File

@@ -3,6 +3,9 @@ import 'package:flutter/material.dart';
import 'package:pshared/provider/account.dart';
import 'package:pweb/models/edit_state.dart';
import 'package:pshared/api/responses/error/server.dart';
import 'package:pweb/models/password_field_type.dart';
import 'package:pweb/models/visibility.dart';
class PasswordFormProvider extends ChangeNotifier {
@@ -11,6 +14,11 @@ class PasswordFormProvider extends ChangeNotifier {
final newPasswordController = TextEditingController();
final confirmPasswordController = TextEditingController();
final Map<PasswordFieldType, VisibilityState> _visibility = {
PasswordFieldType.old: VisibilityState.hidden,
PasswordFieldType.newPassword: VisibilityState.hidden,
PasswordFieldType.confirmPassword: VisibilityState.hidden,
};
EditState _state = EditState.view;
String _errorText = '';
bool _disposed = false;
@@ -19,6 +27,8 @@ class PasswordFormProvider extends ChangeNotifier {
bool get isSaving => _state == EditState.saving;
String get errorText => _errorText;
EditState get state => _state;
bool isPasswordVisible(PasswordFieldType type) =>
_visibility[type] == VisibilityState.visible;
void toggleExpanded() {
if (_state == EditState.saving) return;
@@ -26,12 +36,21 @@ class PasswordFormProvider extends ChangeNotifier {
_setError('');
}
Future<void> submit({
void togglePasswordVisibility(PasswordFieldType type) {
final current = _visibility[type];
if (current == null) return;
_visibility[type] = current == VisibilityState.hidden
? VisibilityState.visible
: VisibilityState.hidden;
notifyListeners();
}
Future<bool> submit({
required AccountProvider accountProvider,
required String errorText,
}) async {
final currentForm = formKey.currentState;
if (currentForm == null || !currentForm.validate()) return;
if (currentForm == null || !currentForm.validate()) return false;
_setState(EditState.saving);
_setError('');
@@ -45,14 +64,22 @@ class PasswordFormProvider extends ChangeNotifier {
oldPasswordController.clear();
newPasswordController.clear();
confirmPasswordController.clear();
_setState(EditState.view);
return true;
} catch (e) {
_setError(errorText);
rethrow;
} finally {
_setError(_errorMessageForException(e, errorText));
_setState(EditState.edit);
rethrow;
}
}
String _errorMessageForException(Object exception, String fallback) {
if (exception is ErrorResponse && exception.details.isNotEmpty) {
return exception.details;
}
return fallback;
}
void _setState(EditState value) {
if (_state == value || _disposed) return;
_state = value;