registration: redesign email verification page (#8554)

This commit is contained in:
Janne Mareike Koschinski 2022-05-13 16:10:22 +02:00 committed by GitHub
parent 438e66bb3f
commit 6d6cfcde11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 382 additions and 90 deletions

View file

@ -14,18 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ChangeEvent, createRef, FormEvent, MouseEvent } from 'react';
import classNames from 'classnames';
import { MatrixClient } from "matrix-js-sdk/src/client";
import { AuthType, IAuthDict, IInputs, IStageStatus } from 'matrix-js-sdk/src/interactive-auth';
import { logger } from "matrix-js-sdk/src/logger";
import React, { ChangeEvent, createRef, FormEvent, Fragment, MouseEvent } from 'react';
import EmailPromptIcon from '../../../../res/img/element-icons/email-prompt.svg';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from "../elements/AccessibleButton";
import Spinner from "../elements/Spinner";
import { LocalisedPolicy, Policies } from '../../../Terms';
import { AuthHeaderModifier } from "../../structures/auth/header/AuthHeaderModifier";
import AccessibleButton from "../elements/AccessibleButton";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import Field from '../elements/Field';
import Spinner from "../elements/Spinner";
import { Alignment } from "../elements/Tooltip";
import CaptchaForm from "./CaptchaForm";
/* This file contains a collection of components which are used by the
@ -86,6 +90,7 @@ interface IAuthEntryProps {
busy?: boolean;
onPhaseChange: (phase: number) => void;
submitAuthDict: (auth: IAuthDict) => void;
requestEmailToken?: () => Promise<void>;
}
interface IPasswordAuthEntryState {
@ -205,7 +210,9 @@ export class RecaptchaAuthEntry extends React.Component<IRecaptchaAuthEntryProps
render() {
if (this.props.busy) {
return <Spinner />;
return (
<Spinner />
);
}
let errorText = this.props.errorText;
@ -349,7 +356,9 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
render() {
if (this.props.busy) {
return <Spinner />;
return (
<Spinner />
);
}
const checkboxes = [];
@ -405,9 +414,24 @@ interface IEmailIdentityAuthEntryProps extends IAuthEntryProps {
};
}
export class EmailIdentityAuthEntry extends React.Component<IEmailIdentityAuthEntryProps> {
interface IEmailIdentityAuthEntryState {
requested: boolean;
requesting: boolean;
}
export class EmailIdentityAuthEntry extends
React.Component<IEmailIdentityAuthEntryProps, IEmailIdentityAuthEntryState> {
static LOGIN_TYPE = AuthType.Email;
constructor(props: IEmailIdentityAuthEntryProps) {
super(props);
this.state = {
requested: false,
requesting: false,
};
}
componentDidMount() {
this.props.onPhaseChange(DEFAULT_PHASE);
}
@ -440,11 +464,51 @@ export class EmailIdentityAuthEntry extends React.Component<IEmailIdentityAuthEn
} else {
return (
<div className="mx_InteractiveAuthEntryComponents_emailWrapper">
<p>{ _t("A confirmation email has been sent to %(emailAddress)s",
<AuthHeaderModifier
title={_t("Check your email to continue")}
icon={<img
src={EmailPromptIcon}
alt={_t("Unread email icon")}
width={16}
/>}
hideServerPicker={true}
/>
<p>{ _t("To create your account, open the link in the email we just sent to %(emailAddress)s.",
{ emailAddress: <b>{ this.props.inputs.emailAddress }</b> },
) }
</p>
<p>{ _t("Open the link in the email to continue registration.") }</p>
) }</p>
{ this.state.requesting ? (
<p className="secondary">{ _t("Did not receive it? <a>Resend it</a>", {}, {
a: (text: string) => <Fragment>
<AccessibleButton
kind='link_inline'
onClick={() => null}
disabled
>{ text } <Spinner w={14} h={14} /></AccessibleButton>
</Fragment>,
}) }</p>
) : <p className="secondary">{ _t("Did not receive it? <a>Resend it</a>", {}, {
a: (text: string) => <AccessibleTooltipButton
kind='link_inline'
title={this.state.requested
? _t("Resent!")
: _t("Resend")}
alignment={Alignment.Right}
tooltipClassName="mx_Tooltip_noMargin"
onHideTooltip={this.state.requested
? () => this.setState({ requested: false })
: undefined}
onClick={async () => {
this.setState({ requesting: true });
try {
await this.props.requestEmailToken?.();
} catch (e) {
logger.warn("Email token request failed: ", e);
} finally {
this.setState({ requested: true, requesting: false });
}
}}
>{ text }</AccessibleTooltipButton>,
}) }</p> }
{ errorSection }
</div>
);
@ -560,7 +624,9 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
render() {
if (this.state.requestingToken) {
return <Spinner />;
return (
<Spinner />
);
} else {
const enableSubmit = Boolean(this.state.token);
const submitClasses = classNames({
@ -726,13 +792,15 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
);
}
return <React.Fragment>
{ errorSection }
<div className="mx_InteractiveAuthEntryComponents_sso_buttons">
{ cancelButton }
{ continueButton }
</div>
</React.Fragment>;
return (
<Fragment>
{ errorSection }
<div className="mx_InteractiveAuthEntryComponents_sso_buttons">
{ cancelButton }
{ continueButton }
</div>
</Fragment>
);
}
}
@ -817,6 +885,7 @@ export interface IStageComponentProps extends IAuthEntryProps {
fail?(e: Error): void;
setEmailSid?(sid: string): void;
onCancel?(): void;
requestEmailToken?(): Promise<void>;
}
export interface IStageComponent extends React.ComponentClass<React.PropsWithRef<IStageComponentProps>> {