Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 47774f4

Browse files
committed
registration: redesign email verification page
1 parent fbb8581 commit 47774f4

File tree

12 files changed

+382
-147
lines changed

12 files changed

+382
-147
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
@import "./structures/_ViewSource.scss";
5858
@import "./structures/auth/_CompleteSecurity.scss";
5959
@import "./structures/auth/_Login.scss";
60+
@import "./structures/auth/_Registration.scss";
6061
@import "./structures/auth/_SetupEncryptionBody.scss";
6162
@import "./views/audio_messages/_AudioPlayer.scss";
6263
@import "./views/audio_messages/_PlayPauseButton.scss";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.mx_Register_mainContent {
2+
display: flex;
3+
flex-direction: column;
4+
flex-grow: 1;
5+
min-height: 270px;
6+
7+
p {
8+
font-size: $font-14px;
9+
color: $authpage-primary-color;
10+
11+
&.secondary {
12+
color: $authpage-secondary-color;
13+
}
14+
}
15+
16+
> img:first-child {
17+
margin-bottom: 16px;
18+
width: max-content;
19+
}
20+
21+
.mx_Login_submit {
22+
margin-bottom: 0;
23+
}
24+
}
25+
26+
.mx_Register_footerActions {
27+
display: flex;
28+
flex-direction: row;
29+
justify-content: space-between;
30+
padding-top: 16px;
31+
margin-top: 16px;
32+
border-top: 1px solid rgba(141, 151, 165, 0.2);
33+
34+
> * {
35+
flex-basis: content;
36+
}
37+
}

res/css/views/auth/_AuthBody.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ limitations under the License.
2424
padding: 25px 60px;
2525
box-sizing: border-box;
2626

27+
&.mx_AuthBody_flex {
28+
display: flex;
29+
flex-direction: column;
30+
}
31+
2732
h2 {
2833
font-size: $font-24px;
2934
font-weight: 600;

res/css/views/auth/_AuthPage.scss

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ limitations under the License.
2828
border-radius: 4px;
2929
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.33);
3030
background-color: $authpage-modal-bg-color;
31-
}
3231

33-
@media only screen and (max-width: 480px) {
34-
.mx_AuthPage_modal {
32+
@media only screen and (max-height: 768px) {
33+
margin-top: 50px;
34+
}
35+
36+
@media only screen and (max-width: 480px) {
3537
margin-top: 0;
3638
}
3739
}

res/css/views/auth/_InteractiveAuthEntryComponents.scss

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,6 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
.mx_InteractiveAuthEntryComponents_emailWrapper {
18-
padding-right: 100px;
19-
position: relative;
20-
margin-top: 32px;
21-
margin-bottom: 32px;
22-
23-
&::before, &::after {
24-
position: absolute;
25-
width: 116px;
26-
height: 116px;
27-
content: "";
28-
right: -10px;
29-
}
30-
31-
&::before {
32-
background-color: rgba(244, 246, 250, 0.91);
33-
border-radius: 50%;
34-
top: -20px;
35-
}
36-
37-
&::after {
38-
background-image: url('$(res)/img/element-icons/email-prompt.svg');
39-
background-repeat: no-repeat;
40-
background-position: center;
41-
background-size: contain;
42-
top: -25px;
43-
}
44-
}
45-
4617
.mx_InteractiveAuthEntryComponents_msisdnWrapper {
4718
text-align: center;
4819
}
Lines changed: 5 additions & 12 deletions
Loading

src/components/structures/InteractiveAuth.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
IStageStatus,
2424
} from "matrix-js-sdk/src/interactive-auth";
2525
import { MatrixClient } from "matrix-js-sdk/src/client";
26-
import React, { createRef } from 'react';
26+
import React, { createRef, ReactNode } from 'react';
2727
import { logger } from "matrix-js-sdk/src/logger";
2828

2929
import getEntryComponentForLoginType, { IStageComponent } from '../views/auth/InteractiveAuthEntryComponents';
@@ -52,6 +52,7 @@ interface IProps {
5252
// continueText and continueKind are passed straight through to the AuthEntryComponent.
5353
continueText?: string;
5454
continueKind?: string;
55+
serverPicker?: ReactNode;
5556
// callback
5657
makeRequest(auth: IAuthData): Promise<IAuthData>;
5758
// callback called when the auth process has finished,
@@ -269,9 +270,11 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
269270
setEmailSid={this.setEmailSid}
270271
showContinue={!this.props.continueIsManaged}
271272
onPhaseChange={this.onPhaseChange}
273+
requestEmailToken={this.authLogic.requestEmailToken}
272274
continueText={this.props.continueText}
273275
continueKind={this.props.continueKind}
274276
onCancel={this.onStageCancel}
277+
serverPicker={this.props.serverPicker}
275278
/>
276279
);
277280
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { isEqual } from "lodash";
18+
import React, {
19+
createContext, Dispatch,
20+
Fragment,
21+
PropsWithChildren,
22+
ReactNode,
23+
Reducer,
24+
ReducerState,
25+
useContext,
26+
useEffect,
27+
useReducer,
28+
} from "react";
29+
30+
interface AuthHeaderContextValue {
31+
title: ReactNode;
32+
icon?: ReactNode;
33+
hideServerPicker?: boolean;
34+
}
35+
36+
enum AuthHeaderContextActionType {
37+
ADD,
38+
REMOVE
39+
}
40+
41+
interface AuthHeaderContextAction {
42+
type: AuthHeaderContextActionType;
43+
value: AuthHeaderContextValue;
44+
}
45+
46+
type AuthContextReducer = Reducer<AuthHeaderContextValue[], AuthHeaderContextAction>;
47+
48+
interface AuthHeaderContextType {
49+
state: ReducerState<AuthContextReducer>;
50+
dispatch: Dispatch<AuthHeaderContextAction>;
51+
}
52+
53+
const AuthHeaderContext = createContext<AuthHeaderContextType>(undefined);
54+
55+
export function AuthHeader(content: AuthHeaderContextValue) {
56+
const context = useContext(AuthHeaderContext);
57+
const dispatch = context ? context.dispatch : null;
58+
useEffect(() => {
59+
if (!dispatch) {
60+
return;
61+
}
62+
dispatch({ type: AuthHeaderContextActionType.ADD, value: content });
63+
return () => dispatch({ type: AuthHeaderContextActionType.REMOVE, value: content });
64+
}, [content, dispatch]);
65+
return null;
66+
}
67+
68+
interface Props {
69+
title: ReactNode;
70+
icon?: ReactNode;
71+
serverPicker: ReactNode;
72+
}
73+
74+
export function AuthHeaderDisplay({ title, icon, serverPicker, children }: PropsWithChildren<Props>) {
75+
const context = useContext(AuthHeaderContext);
76+
if (!context) {
77+
return null;
78+
}
79+
const current = context.state.length ? context.state[0] : null;
80+
return (
81+
<Fragment>
82+
{ current?.icon ?? icon }
83+
<h2>{ current?.title ?? title }</h2>
84+
{ children }
85+
{ current?.hideServerPicker !== true && serverPicker }
86+
</Fragment>
87+
);
88+
}
89+
90+
export function AuthHeaderProvider({ children }: PropsWithChildren<{}>) {
91+
const [state, dispatch] = useReducer<AuthContextReducer>(
92+
(state: AuthHeaderContextValue[], action: AuthHeaderContextAction) => {
93+
switch (action.type) {
94+
case AuthHeaderContextActionType.ADD:
95+
return [action.value, ...state];
96+
case AuthHeaderContextActionType.REMOVE:
97+
return (state.length && isEqual(state[0], action.value)) ? state.slice(1) : state;
98+
}
99+
},
100+
[] as AuthHeaderContextValue[],
101+
);
102+
return (
103+
<AuthHeaderContext.Provider value={{ state, dispatch }}>
104+
{ children }
105+
</AuthHeaderContext.Provider>
106+
);
107+
}

src/components/structures/auth/Registration.tsx

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ limitations under the License.
1515
*/
1616

1717
import { createClient } from 'matrix-js-sdk/src/matrix';
18-
import React, { ReactNode } from 'react';
18+
import React, { Fragment, ReactNode } from 'react';
1919
import { MatrixClient } from "matrix-js-sdk/src/client";
2020
import classNames from "classnames";
2121
import { logger } from "matrix-js-sdk/src/logger";
@@ -25,6 +25,7 @@ import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
2525
import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils";
2626
import * as Lifecycle from '../../../Lifecycle';
2727
import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg";
28+
import { AuthHeaderDisplay, AuthHeaderProvider } from "./AuthHeaderContext";
2829
import AuthPage from "../../views/auth/AuthPage";
2930
import Login, { ISSOFlow } from "../../../Login";
3031
import dis from "../../../dispatcher/dispatcher";
@@ -619,28 +620,37 @@ export default class Registration extends React.Component<IProps, IState> {
619620
{ regDoneText }
620621
</div>;
621622
} else {
622-
body = <div>
623-
<h2>{ _t('Create account') }</h2>
624-
{ errorText }
625-
{ serverDeadSection }
626-
<ServerPicker
627-
title={_t("Host account on")}
628-
dialogTitle={_t("Decide where your account is hosted")}
629-
serverConfig={this.props.serverConfig}
630-
onServerConfigChange={this.state.doingUIAuth ? undefined : this.props.onServerConfigChange}
631-
/>
632-
{ this.renderRegisterComponent() }
633-
{ goBack }
634-
{ signIn }
635-
</div>;
623+
body = <Fragment>
624+
<div className="mx_Register_mainContent">
625+
<AuthHeaderDisplay
626+
title={_t('Create account')}
627+
serverPicker={<ServerPicker
628+
title={_t("Host account on")}
629+
dialogTitle={_t("Decide where your account is hosted")}
630+
serverConfig={this.props.serverConfig}
631+
onServerConfigChange={this.state.doingUIAuth ? undefined : this.props.onServerConfigChange}
632+
/>}
633+
>
634+
{ errorText }
635+
{ serverDeadSection }
636+
</AuthHeaderDisplay>
637+
{ this.renderRegisterComponent() }
638+
</div>
639+
<div className="mx_Register_footerActions">
640+
{ goBack }
641+
{ signIn }
642+
</div>
643+
</Fragment>;
636644
}
637645

638646
return (
639647
<AuthPage>
640648
<AuthHeader />
641-
<AuthBody>
642-
{ body }
643-
</AuthBody>
649+
<AuthHeaderProvider>
650+
<AuthBody flex>
651+
{ body }
652+
</AuthBody>
653+
</AuthHeaderProvider>
644654
</AuthPage>
645655
);
646656
}

src/components/views/auth/AuthBody.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React from 'react';
17+
import classNames from "classnames";
18+
import React, { PropsWithChildren } from 'react';
1819

19-
export default class AuthBody extends React.PureComponent {
20-
public render(): React.ReactNode {
21-
return <div className="mx_AuthBody">
22-
{ this.props.children }
23-
</div>;
24-
}
20+
interface Props {
21+
flex?: boolean;
22+
}
23+
24+
export default function AuthBody({ flex, children }: PropsWithChildren<Props>) {
25+
return <div className={classNames("mx_AuthBody", { ["mx_AuthBody_flex"]: flex })}>
26+
{ children }
27+
</div>;
2528
}

0 commit comments

Comments
 (0)