Factor out post-login splash screen to a new component (#12103)
* Factor out post-login splash screen to a new component * Move CSS classes to per-component file * Rename CSS classes ... to reflect the component that uses them * code review
This commit is contained in:
parent
baaf8ad68b
commit
fd64eccd4a
7 changed files with 220 additions and 37 deletions
|
@ -92,6 +92,7 @@
|
||||||
@import "./structures/auth/_CompleteSecurity.pcss";
|
@import "./structures/auth/_CompleteSecurity.pcss";
|
||||||
@import "./structures/auth/_ConfirmSessionLockTheftView.pcss";
|
@import "./structures/auth/_ConfirmSessionLockTheftView.pcss";
|
||||||
@import "./structures/auth/_Login.pcss";
|
@import "./structures/auth/_Login.pcss";
|
||||||
|
@import "./structures/auth/_LoginSplashView.pcss";
|
||||||
@import "./structures/auth/_Registration.pcss";
|
@import "./structures/auth/_Registration.pcss";
|
||||||
@import "./structures/auth/_SessionLockStolenView.pcss";
|
@import "./structures/auth/_SessionLockStolenView.pcss";
|
||||||
@import "./structures/auth/_SetupEncryptionBody.pcss";
|
@import "./structures/auth/_SetupEncryptionBody.pcss";
|
||||||
|
|
|
@ -19,13 +19,6 @@ limitations under the License.
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat_splashButtons {
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_MatrixChat_wrapper {
|
.mx_MatrixChat_wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
@ -50,18 +43,6 @@ limitations under the License.
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixChat_syncError {
|
|
||||||
color: $accent-fg-color;
|
|
||||||
background-color: #df2a8b; /* Only used here */
|
|
||||||
border-radius: 5px;
|
|
||||||
display: table;
|
|
||||||
padding: 30px;
|
|
||||||
position: absolute;
|
|
||||||
top: 100px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not the left panel, and not the resize handle, so the roomview and friends */
|
/* not the left panel, and not the resize handle, so the roomview and friends */
|
||||||
.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle):not(.mx_LeftPanel_outerWrapper) {
|
.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle):not(.mx_LeftPanel_outerWrapper) {
|
||||||
background-color: $background;
|
background-color: $background;
|
||||||
|
|
34
res/css/structures/auth/_LoginSplashView.pcss
Normal file
34
res/css/structures/auth/_LoginSplashView.pcss
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015-2024 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_LoginSplashView_splashButtons {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_LoginSplashView_syncError {
|
||||||
|
color: $accent-fg-color;
|
||||||
|
background-color: #df2a8b; /* Only used here */
|
||||||
|
border-radius: 5px;
|
||||||
|
display: table;
|
||||||
|
padding: 30px;
|
||||||
|
position: absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015-2022 The Matrix.org Foundation C.I.C.
|
Copyright 2015-2024 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -60,7 +60,6 @@ import { _t, _td, getCurrentLanguage } from "../../languageHandler";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import ThemeController from "../../settings/controllers/ThemeController";
|
import ThemeController from "../../settings/controllers/ThemeController";
|
||||||
import { startAnyRegistrationFlow } from "../../Registration";
|
import { startAnyRegistrationFlow } from "../../Registration";
|
||||||
import { messageForSyncError } from "../../utils/ErrorUtils";
|
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
|
||||||
import DMRoomMap from "../../utils/DMRoomMap";
|
import DMRoomMap from "../../utils/DMRoomMap";
|
||||||
|
@ -113,7 +112,7 @@ import { PosthogAnalytics } from "../../PosthogAnalytics";
|
||||||
import { initSentry } from "../../sentry";
|
import { initSentry } from "../../sentry";
|
||||||
import LegacyCallHandler from "../../LegacyCallHandler";
|
import LegacyCallHandler from "../../LegacyCallHandler";
|
||||||
import { showSpaceInvite } from "../../utils/space";
|
import { showSpaceInvite } from "../../utils/space";
|
||||||
import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton";
|
import { ButtonEvent } from "../views/elements/AccessibleButton";
|
||||||
import { ActionPayload } from "../../dispatcher/payloads";
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
import { SummarizedNotificationState } from "../../stores/notifications/SummarizedNotificationState";
|
import { SummarizedNotificationState } from "../../stores/notifications/SummarizedNotificationState";
|
||||||
import Views from "../../Views";
|
import Views from "../../Views";
|
||||||
|
@ -147,6 +146,7 @@ import { Filter } from "../views/dialogs/spotlight/Filter";
|
||||||
import { checkSessionLockFree, getSessionLock } from "../../utils/SessionLock";
|
import { checkSessionLockFree, getSessionLock } from "../../utils/SessionLock";
|
||||||
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
||||||
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
||||||
|
import { LoginSplashView } from "./auth/LoginSplashView";
|
||||||
|
|
||||||
// legacy export
|
// legacy export
|
||||||
export { default as Views } from "../../Views";
|
export { default as Views } from "../../Views";
|
||||||
|
@ -2119,22 +2119,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// we think we are logged in, but are still waiting for the /sync to complete
|
// we think we are logged in, but are still waiting for the /sync to complete
|
||||||
let errorBox;
|
// Suppress `InvalidStoreError`s here, since they have their own error dialog.
|
||||||
if (this.state.syncError && !isStoreError) {
|
|
||||||
errorBox = (
|
|
||||||
<div className="mx_MatrixChat_syncError">{messageForSyncError(this.state.syncError)}</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
view = (
|
view = (
|
||||||
<div className="mx_MatrixChat_splash">
|
<LoginSplashView
|
||||||
{errorBox}
|
onLogoutClick={this.onLogoutClick}
|
||||||
<Spinner />
|
syncError={isStoreError ? null : this.state.syncError}
|
||||||
<div className="mx_MatrixChat_splashButtons">
|
/>
|
||||||
<AccessibleButton kind="link_inline" onClick={this.onLogoutClick}>
|
|
||||||
{_t("action|logout")}
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (this.state.view === Views.WELCOME) {
|
} else if (this.state.view === Views.WELCOME) {
|
||||||
|
|
58
src/components/structures/auth/LoginSplashView.tsx
Normal file
58
src/components/structures/auth/LoginSplashView.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015-2024 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { messageForSyncError } from "../../../utils/ErrorUtils";
|
||||||
|
import Spinner from "../../views/elements/Spinner";
|
||||||
|
import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
|
||||||
|
import { _t } from "../../../languageHandler";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/**
|
||||||
|
* A callback function. Will be called if the user clicks the "logout" button on the splash screen.
|
||||||
|
*
|
||||||
|
* @param event - The click event
|
||||||
|
*/
|
||||||
|
onLogoutClick: (event: ButtonEvent) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error that caused `/sync` to fail. If set, an error message will be shown on the splash screen.
|
||||||
|
*/
|
||||||
|
syncError: Error | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The view that is displayed after we have logged in, before the first /sync is completed.
|
||||||
|
*/
|
||||||
|
export function LoginSplashView(props: Props): React.JSX.Element {
|
||||||
|
let errorBox: React.JSX.Element | undefined;
|
||||||
|
|
||||||
|
if (props.syncError) {
|
||||||
|
errorBox = <div className="mx_LoginSplashView_syncError">{messageForSyncError(props.syncError)}</div>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="mx_MatrixChat_splash">
|
||||||
|
{errorBox}
|
||||||
|
<Spinner />
|
||||||
|
<div className="mx_LoginSplashView_splashButtons">
|
||||||
|
<AccessibleButton kind="link_inline" onClick={props.onLogoutClick}>
|
||||||
|
{_t("action|logout")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
49
test/components/structures/auth/LoginSplashView-test.tsx
Normal file
49
test/components/structures/auth/LoginSplashView-test.tsx
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render, RenderResult } from "@testing-library/react";
|
||||||
|
import React, { ComponentProps } from "react";
|
||||||
|
|
||||||
|
import { LoginSplashView } from "../../../../src/components/structures/auth/LoginSplashView";
|
||||||
|
|
||||||
|
describe("<LoginSplashView />", () => {
|
||||||
|
function getComponent(props: Partial<ComponentProps<typeof LoginSplashView>> = {}): RenderResult {
|
||||||
|
const defaultProps = {
|
||||||
|
onLogoutClick: () => {},
|
||||||
|
syncError: null,
|
||||||
|
};
|
||||||
|
return render(<LoginSplashView {...defaultProps} {...props} />);
|
||||||
|
}
|
||||||
|
|
||||||
|
it("Renders a spinner", () => {
|
||||||
|
const rendered = getComponent();
|
||||||
|
expect(rendered.getByTestId("spinner")).toBeInTheDocument();
|
||||||
|
expect(rendered.asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Renders an error message", () => {
|
||||||
|
const rendered = getComponent({ syncError: new Error("boohoo") });
|
||||||
|
expect(rendered.asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Calls onLogoutClick", () => {
|
||||||
|
const onLogoutClick = jest.fn();
|
||||||
|
const rendered = getComponent({ onLogoutClick });
|
||||||
|
expect(onLogoutClick).not.toHaveBeenCalled();
|
||||||
|
rendered.getByRole("button", { name: "Logout" }).click();
|
||||||
|
expect(onLogoutClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<LoginSplashView /> Renders a spinner 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mx_MatrixChat_splash"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_Spinner"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="Loading…"
|
||||||
|
class="mx_Spinner_icon"
|
||||||
|
data-testid="spinner"
|
||||||
|
role="progressbar"
|
||||||
|
style="width: 32px; height: 32px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_LoginSplashView_splashButtons"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<LoginSplashView /> Renders an error message 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mx_MatrixChat_splash"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_LoginSplashView_syncError"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Unable to connect to Homeserver. Retrying…
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_Spinner"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-label="Loading…"
|
||||||
|
class="mx_Spinner_icon"
|
||||||
|
data-testid="spinner"
|
||||||
|
role="progressbar"
|
||||||
|
style="width: 32px; height: 32px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_LoginSplashView_splashButtons"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
Loading…
Reference in a new issue