From e3f43e1060f07d3d8600735722e0e2a43384e3da Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Thu, 13 Mar 2025 14:40:00 +0000 Subject: [PATCH] Complete the compounding --- src/components/views/auth/PassphraseField.tsx | 10 ++-- .../views/settings/ChangePassword.tsx | 51 +++++++++---------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index ad99debc48..e54fc68e6a 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -52,8 +52,8 @@ const DEFAULT_PROPS = { labelAllowedButUnsafe: _td("auth|password_field_weak_label"), }; -const NewPassphraseField: React.FC = (props) => { - const { labelEnterPassword, userInputs, minScore, label, labelStrongPassword, labelAllowedButUnsafe, className, id, fieldRef, autoFocus} = {...DEFAULT_PROPS, ...props}; +const PassphraseField: React.FC = (props) => { + const { labelEnterPassword, userInputs, minScore, label, labelStrongPassword, labelAllowedButUnsafe, className, id, fieldRef, autoFocus, onChange, onValidate} = {...DEFAULT_PROPS, ...props}; const validateFn = useMemo(() => withValidation<{}, ZxcvbnResult | null>({ description: function (complexity) { const score = complexity ? complexity.score : 0; @@ -103,12 +103,14 @@ const NewPassphraseField: React.FC = (props) => { const [feedback, setFeedback]= useState(); const onInputChange = useCallback>((ev) => { + onChange(ev); validateFn({ value: ev.target.value, focused: true, }).then((v) => { setFeedback(v.feedback); - }) + onValidate?.(v); + }); }, [validateFn]); @@ -119,4 +121,4 @@ const NewPassphraseField: React.FC = (props) => { } -export default NewPassphraseField; +export default PassphraseField; diff --git a/src/components/views/settings/ChangePassword.tsx b/src/components/views/settings/ChangePassword.tsx index 38cd6f28d1..e2deae4420 100644 --- a/src/components/views/settings/ChangePassword.tsx +++ b/src/components/views/settings/ChangePassword.tsx @@ -10,11 +10,10 @@ import React from "react"; import { type MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import AccessibleButton, { type AccessibleButtonKind } from "../elements/AccessibleButton"; import withValidation, { type IFieldState, type IValidationResult } from "../elements/Validation"; import { UserFriendlyError, _t, _td } from "../../../languageHandler"; import { PASSWORD_MIN_SCORE } from "../auth/RegistrationForm"; -import { Root, Field as CpdField, PasswordInput, Label, InlineSpinner, HelpMessage } from "@vector-im/compound-web"; +import { Root, Field as CpdField, PasswordInput, Label, InlineSpinner, HelpMessage, Button } from "@vector-im/compound-web"; import PassphraseField from "../auth/PassphraseField"; const FIELD_OLD_PASSWORD = "field_old_password"; @@ -31,8 +30,6 @@ enum Phase { interface IProps { onFinished: (outcome: { didSetEmail?: boolean }) => void; onError: (error: Error) => void; - buttonClassName?: string; - buttonKind?: AccessibleButtonKind; buttonLabel?: string; } @@ -250,26 +247,25 @@ export default class ChangePassword extends React.Component { activeElement.blur(); } + // Run all fields with stricter validation that no longer allows empty + // values for required fields. + await this.onOldPasswordValidate({ + value: this[FIELD_OLD_PASSWORD]?.value ?? null, + allowEmpty: false, + focused: true, + }); + await this.onNewPasswordConfirmValidate({ + value: this[FIELD_NEW_PASSWORD_CONFIRM]?.value ?? null, + allowEmpty: false, + focused: true, + }); + const fieldIDsInDisplayOrder: FieldType[] = [ FIELD_OLD_PASSWORD, FIELD_NEW_PASSWORD, FIELD_NEW_PASSWORD_CONFIRM, ]; - // Run all fields with stricter validation that no longer allows empty - // values for required fields. - for (const fieldID of fieldIDsInDisplayOrder) { - const field = this[fieldID]; - if (!field) { - continue; - } - // We must wait for these validations to finish before queueing - // up the setState below so our setState goes in the queue after - // all the setStates from these validate calls (that's how we - // know they've finished). - await field.validate({ allowEmpty: false }); - } - // Validation and state updates are async, so we need to wait for them to complete // first. Queue a `setState` callback and wait for it to resolve. await new Promise((resolve) => this.setState({}, resolve)); @@ -287,7 +283,8 @@ export default class ChangePassword extends React.Component { // Focus the first invalid field and show feedback in the stricter mode // that no longer allows empty values for required fields. invalidField.focus(); - invalidField.validate({ allowEmpty: false, focused: true }); + // TODO: HMM + // invalidField.validate({ allowEmpty: false, focused: true }); return false; } @@ -305,8 +302,6 @@ export default class ChangePassword extends React.Component { } public render(): React.ReactNode { - const buttonClassName = this.props.buttonClassName; - const { fieldValid, phase } = this.state; switch (phase) { @@ -317,7 +312,7 @@ export default class ChangePassword extends React.Component { - (this[FIELD_OLD_PASSWORD] = field)} data-invalid={fieldValid[FIELD_OLD_PASSWORD]?.valid} value={this.state.oldPassword} onChange={this.onChangeOldPassword} /> + (this[FIELD_OLD_PASSWORD] = field)} data-invalid={fieldValid[FIELD_OLD_PASSWORD]?.valid === false ? true : undefined} value={this.state.oldPassword} onChange={this.onChangeOldPassword} /> {fieldValid[FIELD_OLD_PASSWORD]?.feedback && {fieldValid[FIELD_OLD_PASSWORD]?.feedback} } @@ -337,18 +332,20 @@ export default class ChangePassword extends React.Component { - (this[FIELD_NEW_PASSWORD_CONFIRM] = field)} data-invalid={fieldValid[FIELD_NEW_PASSWORD_CONFIRM]} value={this.state.newPasswordConfirm} onChange={this.onChangeNewPasswordConfirm} /> + (this[FIELD_NEW_PASSWORD_CONFIRM] = field)} data-invalid={fieldValid[FIELD_NEW_PASSWORD_CONFIRM]?.valid === false ? true : undefined} value={this.state.newPasswordConfirm} onChange={this.onChangeNewPasswordConfirm} /> {fieldValid[FIELD_NEW_PASSWORD_CONFIRM]?.feedback && {fieldValid[FIELD_NEW_PASSWORD_CONFIRM]?.feedback} } - {this.props.buttonLabel || _t("auth|change_password_action")} - + ); case Phase.Uploading: