diff --git a/modules/restricted-guests/element-web/src/AuthFooter.tsx b/modules/restricted-guests/element-web/src/AuthFooter.tsx new file mode 100644 index 0000000000..4b908ecb35 --- /dev/null +++ b/modules/restricted-guests/element-web/src/AuthFooter.tsx @@ -0,0 +1,59 @@ +/* +Copyright 2025 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { type FC } from "react"; +import { Button } from "@vector-im/compound-web"; +import { type AccountAuthInfo, type Api } from "@element-hq/element-web-module-api"; +import styled from "styled-components"; + +import { type ModuleConfig } from "./config.ts"; +import RegisterDialog from "./RegisterDialog.tsx"; + +interface Props { + api: Api; + config: ModuleConfig; + onLoggedIn(data: AccountAuthInfo): void; +} + +const Container = styled.aside` + margin: var(--cpd-space-3x) 0; + + button { + width: 100%; + } +`; + +const AuthFooter: FC = ({ api, config, onLoggedIn }) => { + const onTryJoin = async (): Promise => { + const { finished } = api.openDialog( + { + title: api.i18n.translate("register_dialog_title"), + }, + RegisterDialog, + { + api, + config, + }, + ); + + const { model: accountAuthInfo, ok } = await finished; + + if (ok && accountAuthInfo) { + onLoggedIn(accountAuthInfo); + } + }; + + return ( + + + + ); +}; + +export default AuthFooter; diff --git a/modules/restricted-guests/element-web/src/RegisterDialog.tsx b/modules/restricted-guests/element-web/src/RegisterDialog.tsx index 1c65708b03..1b445df251 100644 --- a/modules/restricted-guests/element-web/src/RegisterDialog.tsx +++ b/modules/restricted-guests/element-web/src/RegisterDialog.tsx @@ -15,6 +15,7 @@ import { type ModuleConfig } from "./config.ts"; interface RegisterDialogProps extends DialogProps { api: Api; config: ModuleConfig; + showLoginLink?: boolean; } const enum State { @@ -29,7 +30,7 @@ const StyledFormRoot = styled(Form.Root)` font-feature-settings: normal; `; -const RegisterDialog: FC = ({ api, config, onCancel, onSubmit }) => { +const RegisterDialog: FC = ({ api, config, onCancel, onSubmit, showLoginLink }) => { const [username, setUsername] = useState(""); const [state, setState] = useState(State.Idle); @@ -69,7 +70,7 @@ const RegisterDialog: FC = ({ api, config, onCancel, onSubm return ( - + {api.i18n.translate("register_dialog_register_username_label")} = ({ api, config, onCancel, onSubm {message} - - {api.i18n.translate("register_dialog_existing_account")} - + {showLoginLink && ( + + {api.i18n.translate("register_dialog_existing_account")} + + )} {api.i18n.translate("register_dialog_continue_label")} diff --git a/modules/restricted-guests/element-web/src/RoomPreviewBar.tsx b/modules/restricted-guests/element-web/src/RoomPreviewBar.tsx index 75a2b9741e..bda49e57c5 100644 --- a/modules/restricted-guests/element-web/src/RoomPreviewBar.tsx +++ b/modules/restricted-guests/element-web/src/RoomPreviewBar.tsx @@ -45,6 +45,7 @@ const RoomPreviewBar: FC = ({ api, config, roomId, roomAlia { api, config, + showLoginLink: true, }, ); diff --git a/modules/restricted-guests/element-web/src/config.ts b/modules/restricted-guests/element-web/src/config.ts index 07a86902c5..766a6571bb 100644 --- a/modules/restricted-guests/element-web/src/config.ts +++ b/modules/restricted-guests/element-web/src/config.ts @@ -40,5 +40,8 @@ export const CONFIG_KEY = "io.element.element-web-modules.restricted-guests"; declare module "@element-hq/element-web-module-api" { export interface Config { [CONFIG_KEY]: input; + sso_redirect_options?: { + immediate?: boolean; // incompatible option + }; } } diff --git a/modules/restricted-guests/element-web/src/index.tsx b/modules/restricted-guests/element-web/src/index.tsx index a28b5c6c5f..d11e4c0691 100644 --- a/modules/restricted-guests/element-web/src/index.tsx +++ b/modules/restricted-guests/element-web/src/index.tsx @@ -12,6 +12,7 @@ import Translations from "./translations.json"; import { ModuleConfig, CONFIG_KEY } from "./config"; import { name as ModuleName } from "../package.json"; import RoomPreviewBar from "./RoomPreviewBar.tsx"; +import AuthFooter from "./AuthFooter.tsx"; const GUEST_INVISIBLE_COMPONENTS = [ "UIComponent.sendInvites", @@ -41,14 +42,26 @@ class RestrictedGuestsModule implements Module { throw new Error(`Errors in module configuration for "${ModuleName}"`); } + const appConfig = this.api.config.get(); + if (appConfig.sso_redirect_options?.immediate) { + console.warn(`${ModuleName} found incompatible option 'sso_redirect_options.immediate', turning it off.`); + appConfig.sso_redirect_options.immediate = false; + } + + // Room preview bar customisations (for Matrix guest support) this.api.customComponents.registerRoomPreviewBar((props, OriginalComponent) => ( )); + this.api.customisations.registerShouldShowComponent(this.shouldShowComponent); - // TODO replace this with a more generic API - this.api._registerLegacyComponentVisibilityCustomisations(this); + // Login component customisations (for no guest support) + this.api.customComponents.registerLoginComponent((props, OriginalComponent) => ( + + + + )); } /** @@ -58,11 +71,12 @@ class RestrictedGuestsModule implements Module { * @returns true, if the user should see the component */ public readonly shouldShowComponent = (component: string): boolean => { - if (!this.config || !this.api.profile.value.userId?.startsWith(this.config.guest_user_prefix)) { - return true; + const profile = this.api.profile.value; + if (this.config && (profile.isGuest || profile.userId?.startsWith(this.config.guest_user_prefix))) { + return GUEST_INVISIBLE_COMPONENTS.includes(component); } - return GUEST_INVISIBLE_COMPONENTS.includes(component); + return true; }; } diff --git a/modules/restricted-guests/element-web/src/translations.json b/modules/restricted-guests/element-web/src/translations.json index bca1dc4a76..315a1e938d 100644 --- a/modules/restricted-guests/element-web/src/translations.json +++ b/modules/restricted-guests/element-web/src/translations.json @@ -4,8 +4,8 @@ "de": "Benutzername" }, "register_dialog_title": { - "en": "Request room access", - "de": "Raumbeitritt anfragen" + "en": "Request access", + "de": "Zugriff anfordern" }, "register_dialog_busy": { "en": "Creating your account...", @@ -32,7 +32,7 @@ "de": "Treten Sie dem Raum bei, um teilzunehmen" }, "join_cta": { - "en": "Join", - "de": "Verbinden" + "en": "Join as guest", + "de": "Als Gast beitreten" } }