Handle unknown screens better (#33793)
* Remove legacy export * Extract view map to a switch case statement with typescript checking that all cases are handled This lets us drop the `default` case as we know we will never reach it. Additionally move all the settings conditions to the state-setters rather than the renderer so we are never stuck in an undefined state * Fix comment * Handle unknown screens better Redirect to welcome/home rather than getting stuck at spinner
This commit is contained in:
committed by
GitHub
parent
6cac2730fd
commit
67295e2334
@@ -145,9 +145,6 @@ import { type URLParams } from "../../vector/url_utils.ts";
|
||||
import { type QrLoginCredentials } from "../views/auth/LoginWithQR.tsx";
|
||||
import { configureFromCompletedOAuthLogin } from "../../Lifecycle";
|
||||
|
||||
// legacy export
|
||||
export { default as Views } from "../../Views";
|
||||
|
||||
const AUTH_SCREENS = ["register", "mobile_register", "login", "forgot_password", "start_sso", "start_cas", "welcome"];
|
||||
|
||||
// Actions that are redirected through the onboarding process prior to being
|
||||
@@ -404,7 +401,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
* Called when:
|
||||
*
|
||||
* - We successfully completed an OIDC or token login, via {@link initSession}.
|
||||
* - The {@link Login} or {@link Register} components notify us that we successfully completed a non-OIDC login or
|
||||
* - The {@link Login} or {@link Registration} components notify us that we successfully completed a non-OIDC login or
|
||||
* registration.
|
||||
*
|
||||
* In both cases, {@link Action.OnLoggedIn} will already have been emitted, but the call to {@link onShowPostLoginScreen} will
|
||||
@@ -739,10 +736,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.viewLogin();
|
||||
break;
|
||||
case "start_password_recovery":
|
||||
this.setStateForNewView({
|
||||
view: Views.FORGOT_PASSWORD,
|
||||
});
|
||||
this.notifyNewScreen("forgot_password");
|
||||
if (SettingsStore.getValue(UIFeature.PasswordReset)) {
|
||||
this.setStateForNewView({
|
||||
view: Views.FORGOT_PASSWORD,
|
||||
});
|
||||
this.notifyNewScreen("forgot_password");
|
||||
}
|
||||
break;
|
||||
case "start_chat":
|
||||
createRoom(MatrixClientPeg.safeGet(), {
|
||||
@@ -2028,6 +2027,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
} else if (ModuleApi.instance.navigation.locationRenderers.get(screen)) {
|
||||
this.setState({ page_type: screen });
|
||||
} else {
|
||||
// Unknown screen requested
|
||||
return this.showScreen(isLoggedOutOrGuest ? "welcome" : "home");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2212,125 +2214,126 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
return fragmentAfterLogin;
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
private getView(): JSX.Element {
|
||||
const fragmentAfterLogin = this.getFragmentAfterLogin();
|
||||
let view: JSX.Element;
|
||||
|
||||
if (this.state.view === Views.LOADING) {
|
||||
view = (
|
||||
<div className="mx_MatrixChat_splash">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
} else if (this.state.view === Views.CONFIRM_LOCK_THEFT) {
|
||||
view = (
|
||||
<ConfirmSessionLockTheftView
|
||||
onConfirm={() => {
|
||||
this.setState({ view: Views.LOADING });
|
||||
this.startInitSession();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.COMPLETE_SECURITY) {
|
||||
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
} else if (this.state.view === Views.E2E_SETUP) {
|
||||
view = <E2eSetup onCancelled={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
} else if (this.state.view === Views.PENDING_CLIENT_START) {
|
||||
// we think we are logged in, but are still waiting for the /sync to complete
|
||||
view = (
|
||||
<LoginSplashView
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onLogoutClick={this.onLogoutClick}
|
||||
syncError={this.state.syncError}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.LOGGED_IN) {
|
||||
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
|
||||
// latter is set via the dispatcher). If we don't yet have a `page_type`,
|
||||
// keep showing the spinner for now.
|
||||
if (this.state.ready && this.state.page_type) {
|
||||
/* for now, we stuff the entirety of our props and state into the LoggedInView.
|
||||
* we should go through and figure out what we actually need to pass down, as well
|
||||
* as using something like redux to avoid having a billion bits of state kicking around.
|
||||
*/
|
||||
view = (
|
||||
<LoggedInView
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
ref={this.loggedInView}
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onRegistered={this.onRegistered}
|
||||
currentRoomId={this.state.currentRoomId}
|
||||
switch (this.state.view) {
|
||||
case Views.LOADING:
|
||||
return (
|
||||
<div className="mx_MatrixChat_splash">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
case Views.CONFIRM_LOCK_THEFT:
|
||||
return (
|
||||
<ConfirmSessionLockTheftView
|
||||
onConfirm={() => {
|
||||
this.setState({ view: Views.LOADING });
|
||||
this.startInitSession();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
case Views.COMPLETE_SECURITY:
|
||||
return <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
case Views.E2E_SETUP:
|
||||
return <E2eSetup onCancelled={this.onCompleteSecurityE2eSetupFinished} />;
|
||||
case Views.PENDING_CLIENT_START:
|
||||
// we think we are logged in, but are still waiting for the /sync to complete
|
||||
view = (
|
||||
return (
|
||||
<LoginSplashView
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onLogoutClick={this.onLogoutClick}
|
||||
syncError={this.state.syncError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (this.state.view === Views.WELCOME) {
|
||||
view = <Welcome {...this.getServerProperties()} />;
|
||||
} else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) {
|
||||
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
||||
view = (
|
||||
<Registration
|
||||
clientSecret={this.state.register_client_secret}
|
||||
sessionId={this.state.register_session_id}
|
||||
idSid={this.state.register_id_sid}
|
||||
email={email}
|
||||
brand={this.props.config.brand}
|
||||
onLoggedIn={this.onRegisterFlowComplete}
|
||||
onLoginClick={this.onLoginClick}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
mobileRegister={this.state.isMobileRegistration}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.FORGOT_PASSWORD && SettingsStore.getValue(UIFeature.PasswordReset)) {
|
||||
view = (
|
||||
<ForgotPassword
|
||||
onComplete={this.onLoginClick}
|
||||
onLoginClick={this.onLoginClick}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.LOGIN) {
|
||||
const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset);
|
||||
view = (
|
||||
<Login
|
||||
isSyncing={this.state.pendingInitialSync}
|
||||
onLoggedIn={this.onUserCompletedLoginFlow}
|
||||
onRegisterClick={this.onRegisterClick}
|
||||
fallbackHsUrl={this.getFallbackHsUrl()}
|
||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||
onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
defaultUsername={this.props.urlParams?.defaults?.defaultUsername}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.SOFT_LOGOUT) {
|
||||
view = (
|
||||
<SoftLogout
|
||||
urlParams={this.props.urlParams}
|
||||
onTokenLoginCompleted={this.props.onTokenLoginCompleted}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.LOCK_STOLEN) {
|
||||
view = <SessionLockStolenView />;
|
||||
} else {
|
||||
logger.error(`Unknown view ${this.state.view}`);
|
||||
return null;
|
||||
case Views.LOGGED_IN:
|
||||
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
|
||||
// latter is set via the dispatcher). If we don't yet have a `page_type`,
|
||||
// keep showing the spinner for now.
|
||||
if (this.state.ready && this.state.page_type) {
|
||||
/* for now, we stuff the entirety of our props and state into the LoggedInView.
|
||||
* we should go through and figure out what we actually need to pass down, as well
|
||||
* as using something like redux to avoid having a billion bits of state kicking around.
|
||||
*/
|
||||
return (
|
||||
<LoggedInView
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
ref={this.loggedInView}
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onRegistered={this.onRegistered}
|
||||
currentRoomId={this.state.currentRoomId}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// we think we are logged in, but are still waiting for the /sync to complete
|
||||
return (
|
||||
<LoginSplashView
|
||||
matrixClient={MatrixClientPeg.safeGet()}
|
||||
onLogoutClick={this.onLogoutClick}
|
||||
syncError={this.state.syncError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case Views.WELCOME:
|
||||
return <Welcome {...this.getServerProperties()} />;
|
||||
case Views.REGISTER:
|
||||
return (
|
||||
<Registration
|
||||
clientSecret={this.state.register_client_secret}
|
||||
sessionId={this.state.register_session_id}
|
||||
idSid={this.state.register_id_sid}
|
||||
email={ThreepidInviteStore.instance.pickBestInvite()?.toEmail}
|
||||
brand={this.props.config.brand}
|
||||
onLoggedIn={this.onRegisterFlowComplete}
|
||||
onLoginClick={this.onLoginClick}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
mobileRegister={this.state.isMobileRegistration}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
case Views.FORGOT_PASSWORD:
|
||||
return (
|
||||
<ForgotPassword
|
||||
onComplete={this.onLoginClick}
|
||||
onLoginClick={this.onLoginClick}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
case Views.LOGIN:
|
||||
return (
|
||||
<Login
|
||||
isSyncing={this.state.pendingInitialSync}
|
||||
onLoggedIn={this.onUserCompletedLoginFlow}
|
||||
onRegisterClick={this.onRegisterClick}
|
||||
fallbackHsUrl={this.getFallbackHsUrl()}
|
||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||
onForgotPasswordClick={
|
||||
SettingsStore.getValue(UIFeature.PasswordReset) ? this.onForgotPasswordClick : undefined
|
||||
}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
defaultUsername={this.props.urlParams?.defaults?.defaultUsername}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
case Views.SOFT_LOGOUT:
|
||||
return (
|
||||
<SoftLogout
|
||||
urlParams={this.props.urlParams}
|
||||
onTokenLoginCompleted={this.props.onTokenLoginCompleted}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
/>
|
||||
);
|
||||
case Views.LOCK_STOLEN:
|
||||
return <SessionLockStolenView />;
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const view = this.getView();
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
|
||||
Reference in New Issue
Block a user