{
break;
case PageTypes.HomePage:
- pageElement =
;
+ pageElement =
;
break;
case PageTypes.UserView:
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index f417bd6045a..9d3114c67cb 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -55,7 +55,6 @@ import { FontWatcher } from "../../settings/watchers/FontWatcher";
import { storeRoomAliasInCache } from "../../RoomAliasCache";
import ToastStore from "../../stores/ToastStore";
import * as StorageManager from "../../utils/StorageManager";
-import { UseCase } from "../../settings/enums/UseCase";
import type LoggedInViewType from "./LoggedInView";
import LoggedInView from "./LoggedInView";
import { Action } from "../../dispatcher/actions";
@@ -114,7 +113,6 @@ import { ShowThreadPayload } from "../../dispatcher/payloads/ShowThreadPayload";
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
import { TimelineRenderingType } from "../../contexts/RoomContext";
-import { UseCaseSelection } from "../views/elements/UseCaseSelection";
import { ValidatedServerConfig } from "../../utils/ValidatedServerConfig";
import { isLocalRoom } from "../../utils/localRoom/isLocalRoom";
import { SDKContext, SdkContextClass } from "../../contexts/SDKContext";
@@ -866,8 +864,7 @@ export default class MatrixChat extends React.PureComponent
{
this.state.view !== Views.LOGIN &&
this.state.view !== Views.REGISTER &&
this.state.view !== Views.COMPLETE_SECURITY &&
- this.state.view !== Views.E2E_SETUP &&
- this.state.view !== Views.USE_CASE_SELECTION
+ this.state.view !== Views.E2E_SETUP
) {
this.onLoggedIn();
}
@@ -1359,12 +1356,7 @@ export default class MatrixChat extends React.PureComponent {
await this.onShowPostLoginScreen();
}
- private async onShowPostLoginScreen(useCase?: UseCase): Promise {
- if (useCase) {
- PosthogAnalytics.instance.setProperty("ftueUseCaseSelection", useCase);
- SettingsStore.setValue("FTUE.useCaseSelection", null, SettingLevel.ACCOUNT, useCase);
- }
-
+ private async onShowPostLoginScreen(): Promise {
this.setStateForNewView({ view: Views.LOGGED_IN });
// If a specific screen is set to be shown after login, show that above
// all else, as it probably means the user clicked on something already.
@@ -2010,33 +2002,10 @@ export default class MatrixChat extends React.PureComponent {
// complete security / e2e setup has finished
private onCompleteSecurityE2eSetupFinished = (): void => {
- if (MatrixClientPeg.currentUserIsJustRegistered() && SettingsStore.getValue("FTUE.useCaseSelection") === null) {
- this.setStateForNewView({ view: Views.USE_CASE_SELECTION });
-
- // Listen to changes in settings and hide the use case screen if appropriate - this is necessary because
- // account settings can still be changing at this point in app init (due to the initial sync being cached,
- // then subsequent syncs being received from the server)
- //
- // This seems unlikely for something that should happen directly after registration, but if a user does
- // their initial login on another device/browser than they registered on, we want to avoid asking this
- // question twice
- //
- // initPosthogAnalyticsToast pioneered this technique, we’re just reusing it here.
- SettingsStore.watchSetting(
- "FTUE.useCaseSelection",
- null,
- (originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
- if (newValue !== null && this.state.view === Views.USE_CASE_SELECTION) {
- this.onShowPostLoginScreen();
- }
- },
- );
- } else {
- // This is async but we makign this function async to wait for it isn't useful
- this.onShowPostLoginScreen().catch((e) => {
- logger.error("Exception showing post-login screen", e);
- });
- }
+ // This is async but we making this function async to wait for it isn't useful
+ this.onShowPostLoginScreen().catch((e) => {
+ logger.error("Exception showing post-login screen", e);
+ });
};
private getFragmentAfterLogin(): string {
@@ -2156,8 +2125,6 @@ export default class MatrixChat extends React.PureComponent {
fragmentAfterLogin={fragmentAfterLogin}
/>
);
- } else if (this.state.view === Views.USE_CASE_SELECTION) {
- view = => this.onShowPostLoginScreen(useCase)} />;
} else if (this.state.view === Views.LOCK_STOLEN) {
view = ;
} else {
diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx
index f71a6331d9e..7325f607ad8 100644
--- a/src/components/structures/UserView.tsx
+++ b/src/components/structures/UserView.tsx
@@ -17,7 +17,7 @@ import RightPanel from "./RightPanel";
import Spinner from "../views/elements/Spinner";
import ResizeNotifier from "../../utils/ResizeNotifier";
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
-import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage";
+import HomePage from "./HomePage.tsx";
import MatrixClientContext from "../../contexts/MatrixClientContext";
interface IProps {
@@ -93,7 +93,7 @@ export default class UserView extends React.Component {
defaultSize={420}
analyticsRoomType="user_profile"
>
-
+
);
} else {
diff --git a/src/components/views/dialogs/AppDownloadDialog.tsx b/src/components/views/dialogs/AppDownloadDialog.tsx
deleted file mode 100644
index a934b5825a6..00000000000
--- a/src/components/views/dialogs/AppDownloadDialog.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React, { FC } from "react";
-
-import { Icon as FDroidBadge } from "../../../../res/img/badges/f-droid.svg";
-import { Icon as GooglePlayBadge } from "../../../../res/img/badges/google-play.svg";
-import { Icon as IOSBadge } from "../../../../res/img/badges/ios.svg";
-import { _t } from "../../../languageHandler";
-import SdkConfig from "../../../SdkConfig";
-import AccessibleButton from "../elements/AccessibleButton";
-import QRCode from "../elements/QRCode";
-import Heading from "../typography/Heading";
-import BaseDialog from "./BaseDialog";
-
-interface Props {
- onFinished(): void;
-}
-
-export const showAppDownloadDialogPrompt = (): boolean => {
- const desktopBuilds = SdkConfig.getObject("desktop_builds");
- const mobileBuilds = SdkConfig.getObject("mobile_builds");
-
- return (
- !!desktopBuilds?.get("available") ||
- !!mobileBuilds?.get("ios") ||
- !!mobileBuilds?.get("android") ||
- !!mobileBuilds?.get("fdroid")
- );
-};
-
-export const AppDownloadDialog: FC = ({ onFinished }) => {
- const brand = SdkConfig.get("brand");
- const desktopBuilds = SdkConfig.getObject("desktop_builds");
- const mobileBuilds = SdkConfig.getObject("mobile_builds");
-
- const urlAppStore = mobileBuilds?.get("ios");
-
- const urlGooglePlay = mobileBuilds?.get("android");
- const urlFDroid = mobileBuilds?.get("fdroid");
- const urlAndroid = urlGooglePlay ?? urlFDroid;
-
- return (
-
- {desktopBuilds?.get("available") && (
-
-
{_t("onboarding|download_brand_desktop", { brand })}
-
{}}
- >
- {_t("onboarding|download_brand_desktop", { brand })}
-
-
- )}
-
- {urlAppStore && (
-
-
{_t("common|ios")}
-
-
- {_t("onboarding|qr_or_app_links", {
- appLinks: "",
- qrCode: "",
- })}
-
-
-
- )}
- {urlAndroid && (
-
-
{_t("common|android")}
-
-
- {_t("onboarding|qr_or_app_links", {
- appLinks: "",
- qrCode: "",
- })}
-
-
- {urlGooglePlay && (
-
{}}
- >
-
-
- )}
- {urlFDroid && (
-
{}}
- >
-
-
- )}
-
-
- )}
-
-
-
{_t("onboarding|apple_trademarks")}
-
{_t("onboarding|google_trademarks")}
-
-
- );
-};
diff --git a/src/components/views/elements/UseCaseSelection.tsx b/src/components/views/elements/UseCaseSelection.tsx
deleted file mode 100644
index 7d2019e0896..00000000000
--- a/src/components/views/elements/UseCaseSelection.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React, { useEffect, useState } from "react";
-
-import { _t } from "../../../languageHandler";
-import { UseCase } from "../../../settings/enums/UseCase";
-import SplashPage from "../../structures/SplashPage";
-import AccessibleButton from "../elements/AccessibleButton";
-import { UseCaseSelectionButton } from "./UseCaseSelectionButton";
-
-interface Props {
- onFinished: (useCase: UseCase) => void;
-}
-
-const TIMEOUT = 1500;
-
-export function UseCaseSelection({ onFinished }: Props): JSX.Element {
- const [selection, setSelected] = useState(null);
-
- // Call onFinished 1.5s after `selection` becomes truthy, to give time for the animation to run
- useEffect(() => {
- if (selection) {
- let handler: number | null = window.setTimeout(() => {
- handler = null;
- onFinished(selection);
- }, TIMEOUT);
- return () => {
- if (handler !== null) clearTimeout(handler);
- handler = null;
- };
- }
- }, [selection, onFinished]);
-
- return (
-
-
-
{_t("onboarding|use_case_heading1")}
-
-
-
{_t("onboarding|use_case_heading2")}
- {_t("onboarding|use_case_heading3")}
-
-
-
-
-
-
-
-
setSelected(UseCase.Skip)}>
- {_t("action|skip")}
-
-
-
- );
-}
diff --git a/src/components/views/elements/UseCaseSelectionButton.tsx b/src/components/views/elements/UseCaseSelectionButton.tsx
deleted file mode 100644
index c1b33a63b68..00000000000
--- a/src/components/views/elements/UseCaseSelectionButton.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React from "react";
-
-import { _t } from "../../../languageHandler";
-import { UseCase } from "../../../settings/enums/UseCase";
-import AccessibleButton from "./AccessibleButton";
-
-interface Props {
- useCase: UseCase;
- selected: boolean;
- onClick: (useCase: UseCase) => void;
-}
-
-export function UseCaseSelectionButton({ useCase, onClick, selected }: Props): JSX.Element {
- let label: string | undefined;
- switch (useCase) {
- case UseCase.PersonalMessaging:
- label = _t("onboarding|use_case_personal_messaging");
- break;
- case UseCase.WorkMessaging:
- label = _t("onboarding|use_case_work_messaging");
- break;
- case UseCase.CommunityMessaging:
- label = _t("onboarding|use_case_community_messaging");
- break;
- }
-
- return (
- onClick(useCase)}
- >
-
- {label}
-
-
- );
-}
diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
index 5fc8fba7e3d..8ad00f350fc 100644
--- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx
@@ -22,7 +22,6 @@ import { UserTab } from "../../../dialogs/UserTab";
import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
import { Action } from "../../../../../dispatcher/actions";
import SdkConfig from "../../../../../SdkConfig";
-import { showUserOnboardingPage } from "../../../user-onboarding/UserOnboardingPage";
import { SettingsSubsection } from "../../shared/SettingsSubsection";
import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection";
@@ -117,7 +116,7 @@ const SpellCheckSection: React.FC = () => {
};
export default class PreferencesUserSettingsTab extends React.Component {
- private static ROOM_LIST_SETTINGS: BooleanSettingKey[] = ["breadcrumbs", "FTUE.userOnboardingButton"];
+ private static ROOM_LIST_SETTINGS: BooleanSettingKey[] = ["breadcrumbs"];
private static SPACES_SETTINGS: BooleanSettingKey[] = ["Spaces.allRoomsInHome"];
@@ -237,10 +236,7 @@ export default class PreferencesUserSettingsTab extends React.Component it !== "FTUE.userOnboardingButton" || showUserOnboardingPage(useCase));
+ const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS;
const browserTimezoneLabel: string = _t("settings|preferences|default_timezone", {
timezone: TimezoneHandler.shortBrowserTimezone(),
diff --git a/src/components/views/user-onboarding/UserOnboardingButton.tsx b/src/components/views/user-onboarding/UserOnboardingButton.tsx
deleted file mode 100644
index 6d009f378b5..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingButton.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import React, { useCallback } from "react";
-
-import { Action } from "../../../dispatcher/actions";
-import defaultDispatcher from "../../../dispatcher/dispatcher";
-import { useSettingValue } from "../../../hooks/useSettings";
-import { _t } from "../../../languageHandler";
-import PosthogTrackers from "../../../PosthogTrackers";
-import { SettingLevel } from "../../../settings/SettingLevel";
-import SettingsStore from "../../../settings/SettingsStore";
-import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-import { showUserOnboardingPage } from "./UserOnboardingPage";
-
-interface Props {
- selected: boolean;
- minimized: boolean;
-}
-
-export function UserOnboardingButton({ selected, minimized }: Props): JSX.Element {
- const useCase = useSettingValue("FTUE.useCaseSelection");
- const visible = useSettingValue("FTUE.userOnboardingButton");
-
- if (!visible || minimized || !showUserOnboardingPage(useCase)) {
- return <>>;
- }
-
- return ;
-}
-
-function UserOnboardingButtonInternal({ selected, minimized }: Props): JSX.Element {
- const onDismiss = useCallback((ev: ButtonEvent) => {
- ev.preventDefault();
- ev.stopPropagation();
-
- PosthogTrackers.trackInteraction("WebRoomListUserOnboardingIgnoreButton", ev);
- SettingsStore.setValue("FTUE.userOnboardingButton", null, SettingLevel.ACCOUNT, false);
- }, []);
-
- const onClick = useCallback((ev: ButtonEvent) => {
- ev.preventDefault();
- ev.stopPropagation();
-
- PosthogTrackers.trackInteraction("WebRoomListUserOnboardingButton", ev);
- defaultDispatcher.fire(Action.ViewHomePage);
- }, []);
-
- return (
-
- {!minimized && (
- <>
-
-
- {_t("common|welcome")}
-
-
-
- >
- )}
-
- );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingHeader.tsx b/src/components/views/user-onboarding/UserOnboardingHeader.tsx
deleted file mode 100644
index d4702ed372e..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingHeader.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as React from "react";
-
-import defaultDispatcher from "../../../dispatcher/dispatcher";
-import { _t } from "../../../languageHandler";
-import PosthogTrackers from "../../../PosthogTrackers";
-import SdkConfig from "../../../SdkConfig";
-import { UseCase } from "../../../settings/enums/UseCase";
-import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-
-const onClickSendDm = (ev: ButtonEvent): void => {
- PosthogTrackers.trackInteraction("WebUserOnboardingHeaderSendDm", ev);
- defaultDispatcher.dispatch({ action: "view_create_chat" });
-};
-
-interface Props {
- useCase: UseCase | null;
-}
-
-export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
- let title: string;
- let description = _t("onboarding|free_e2ee_messaging_unlimited_voip", {
- brand: SdkConfig.get("brand"),
- });
- let image: string;
- let actionLabel: string;
-
- switch (useCase) {
- /* eslint-disable @typescript-eslint/no-require-imports */
- case UseCase.PersonalMessaging:
- title = _t("onboarding|personal_messaging_title");
- image = require("../../../../res/img/user-onboarding/PersonalMessaging.png");
- actionLabel = _t("onboarding|personal_messaging_action");
- break;
- case UseCase.WorkMessaging:
- title = _t("onboarding|work_messaging_title");
- description = _t("onboarding|free_e2ee_messaging_unlimited_voip", {
- brand: SdkConfig.get("brand"),
- });
- image = require("../../../../res/img/user-onboarding/WorkMessaging.png");
- actionLabel = _t("onboarding|work_messaging_action");
- break;
- case UseCase.CommunityMessaging:
- title = _t("onboarding|community_messaging_title");
- description = _t("onboarding|community_messaging_description");
- image = require("../../../../res/img/user-onboarding/CommunityMessaging.png");
- actionLabel = _t("onboarding|community_messaging_action");
- break;
- default:
- title = _t("onboarding|welcome_to_brand", {
- brand: SdkConfig.get("brand"),
- });
- image = require("../../../../res/img/user-onboarding/PersonalMessaging.png");
- actionLabel = _t("onboarding|personal_messaging_action");
- break;
- /* eslint-enable @typescript-eslint/no-require-imports */
- }
-
- return (
-
-
-
- {title}
- .
-
-
{description}
-
- {actionLabel}
-
-
-
-
- );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingList.tsx b/src/components/views/user-onboarding/UserOnboardingList.tsx
deleted file mode 100644
index 0f0298eb654..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingList.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import * as React from "react";
-
-import { UserOnboardingTaskWithResolvedCompletion } from "../../../hooks/useUserOnboardingTasks";
-import { _t } from "../../../languageHandler";
-import SdkConfig from "../../../SdkConfig";
-import ProgressBar from "../../views/elements/ProgressBar";
-import Heading from "../../views/typography/Heading";
-import { UserOnboardingTask } from "./UserOnboardingTask";
-
-export const getUserOnboardingCounters = (
- tasks: UserOnboardingTaskWithResolvedCompletion[],
-): {
- completed: number;
- waiting: number;
- total: number;
-} => {
- const completed = tasks.filter((task) => task.completed === true).length;
- const waiting = tasks.filter((task) => task.completed === false).length;
-
- return {
- completed: completed,
- waiting: waiting,
- total: completed + waiting,
- };
-};
-
-interface Props {
- tasks: UserOnboardingTaskWithResolvedCompletion[];
-}
-
-export function UserOnboardingList({ tasks }: Props): JSX.Element {
- const { completed, waiting, total } = getUserOnboardingCounters(tasks);
-
- return (
-
-
-
- {waiting > 0
- ? _t("onboarding|only_n_steps_to_go", {
- count: waiting,
- })
- : _t("onboarding|you_did_it")}
-
-
- {_t("onboarding|complete_these", {
- brand: SdkConfig.get("brand"),
- })}
-
-
-
-
- {tasks.map((task) => (
-
- ))}
-
-
- );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingPage.tsx b/src/components/views/user-onboarding/UserOnboardingPage.tsx
deleted file mode 100644
index 3f7a1e80dd8..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingPage.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2020-2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { useEffect, useState } from "react";
-import * as React from "react";
-
-import { useInitialSyncComplete } from "../../../hooks/useIsInitialSyncComplete";
-import { useSettingValue } from "../../../hooks/useSettings";
-import { useUserOnboardingContext } from "../../../hooks/useUserOnboardingContext";
-import { useUserOnboardingTasks } from "../../../hooks/useUserOnboardingTasks";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
-import SdkConfig from "../../../SdkConfig";
-import { UseCase } from "../../../settings/enums/UseCase";
-import { getHomePageUrl } from "../../../utils/pages";
-import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
-import EmbeddedPage from "../../structures/EmbeddedPage";
-import HomePage from "../../structures/HomePage";
-import { UserOnboardingHeader } from "./UserOnboardingHeader";
-import { UserOnboardingList } from "./UserOnboardingList";
-import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
-
-interface Props {
- justRegistered?: boolean;
-}
-
-// We decided to only show the new user onboarding page to new users
-// For now, that means we set the cutoff at 2022-07-01 00:00 UTC
-const USER_ONBOARDING_CUTOFF_DATE = new Date(1_656_633_600);
-export function showUserOnboardingPage(useCase: UseCase | null): boolean {
- return useCase !== null || MatrixClientPeg.userRegisteredAfter(USER_ONBOARDING_CUTOFF_DATE);
-}
-
-const ANIMATION_DURATION = 2800;
-export function UserOnboardingPage({ justRegistered = false }: Props): JSX.Element {
- const cli = useMatrixClientContext();
- const config = SdkConfig.get();
- const pageUrl = getHomePageUrl(config, cli);
-
- const useCase = useSettingValue("FTUE.useCaseSelection");
- const context = useUserOnboardingContext();
- const tasks = useUserOnboardingTasks(context);
-
- const initialSyncComplete = useInitialSyncComplete();
- const [showList, setShowList] = useState(false);
- useEffect(() => {
- if (initialSyncComplete) {
- const handler = window.setTimeout(() => {
- setShowList(true);
- }, ANIMATION_DURATION);
- return () => {
- clearTimeout(handler);
- };
- } else {
- setShowList(false);
- }
- }, [initialSyncComplete, setShowList]);
-
- // Only show new onboarding list to users who registered after a given date or have chosen a use case
- if (!showUserOnboardingPage(useCase)) {
- return ;
- }
-
- if (pageUrl) {
- return ;
- }
-
- return (
-
-
- {showList && }
-
- );
-}
diff --git a/src/components/views/user-onboarding/UserOnboardingTask.tsx b/src/components/views/user-onboarding/UserOnboardingTask.tsx
deleted file mode 100644
index c379cbc3d11..00000000000
--- a/src/components/views/user-onboarding/UserOnboardingTask.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import classNames from "classnames";
-import * as React from "react";
-
-import { UserOnboardingTaskWithResolvedCompletion } from "../../../hooks/useUserOnboardingTasks";
-import AccessibleButton from "../../views/elements/AccessibleButton";
-import Heading from "../../views/typography/Heading";
-
-interface Props {
- task: UserOnboardingTaskWithResolvedCompletion;
- completed?: boolean;
-}
-
-export function UserOnboardingTask({ task, completed = false }: Props): JSX.Element {
- const title = typeof task.title === "function" ? task.title() : task.title;
- const description = typeof task.description === "function" ? task.description() : task.description;
-
- return (
-
-
-
-
- {title}
-
-
{description}
-
- {task.action && (!task.action.hideOnComplete || !completed) && (
-
- {task.action.label}
-
- )}
-
- );
-}
diff --git a/src/hooks/useIsInitialSyncComplete.ts b/src/hooks/useIsInitialSyncComplete.ts
deleted file mode 100644
index 25cd8f52bd5..00000000000
--- a/src/hooks/useIsInitialSyncComplete.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { ClientEvent } from "matrix-js-sdk/src/matrix";
-
-import { useEventEmitterState } from "./useEventEmitter";
-import { useMatrixClientContext } from "../contexts/MatrixClientContext";
-
-export function useInitialSyncComplete(): boolean {
- const cli = useMatrixClientContext();
- return useEventEmitterState(cli, ClientEvent.Sync, () => cli.isInitialSyncComplete());
-}
diff --git a/src/hooks/useUserOnboardingContext.ts b/src/hooks/useUserOnboardingContext.ts
deleted file mode 100644
index 48517bd1924..00000000000
--- a/src/hooks/useUserOnboardingContext.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { logger } from "matrix-js-sdk/src/logger";
-import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
-
-import { Notifier, NotifierEvent } from "../Notifier";
-import DMRoomMap from "../utils/DMRoomMap";
-import { useMatrixClientContext } from "../contexts/MatrixClientContext";
-import { useSettingValue } from "./useSettings";
-import { useEventEmitter, useTypedEventEmitter } from "./useEventEmitter";
-
-export interface UserOnboardingContext {
- hasAvatar: boolean;
- hasDevices: boolean;
- hasDmRooms: boolean;
- showNotificationsPrompt: boolean;
-}
-
-const USER_ONBOARDING_CONTEXT_INTERVAL = 5000;
-
-/**
- * Returns a persistent, non-changing reference to a function
- * This function proxies all its calls to the current value of the given input callback
- *
- * This allows you to use the current value of e.g., a state in a callback that’s used by e.g., a useEventEmitter or
- * similar hook without re-registering the hook when the state changes
- * @param value changing callback
- */
-function useRefOf(value: (...values: T) => R): (...values: T) => R {
- const ref = useRef(value);
- ref.current = value;
- return useCallback((...values: T) => ref.current(...values), []);
-}
-
-function useUserOnboardingContextValue(defaultValue: T, callback: (cli: MatrixClient) => Promise): T {
- const [value, setValue] = useState(defaultValue);
- const cli = useMatrixClientContext();
-
- const handler = useRefOf(callback);
-
- useEffect(() => {
- if (value) {
- return;
- }
-
- let handle: number | null = null;
- let enabled = true;
- const repeater = async (): Promise => {
- if (handle !== null) {
- clearTimeout(handle);
- handle = null;
- }
- setValue(await handler(cli));
- if (enabled) {
- handle = window.setTimeout(repeater, USER_ONBOARDING_CONTEXT_INTERVAL);
- }
- };
- repeater().catch((err) => logger.warn("could not update user onboarding context", err));
- cli.on(ClientEvent.AccountData, repeater);
- return () => {
- enabled = false;
- cli.off(ClientEvent.AccountData, repeater);
- if (handle !== null) {
- clearTimeout(handle);
- handle = null;
- }
- };
- }, [cli, handler, value]);
- return value;
-}
-
-function useShowNotificationsPrompt(): boolean {
- const client = useMatrixClientContext();
-
- const [value, setValue] = useState(client.pushRules ? Notifier.shouldShowPrompt() : true);
-
- const updateValue = useCallback(() => {
- setValue(client.pushRules ? Notifier.shouldShowPrompt() : true);
- }, [client]);
-
- useEventEmitter(Notifier, NotifierEvent.NotificationHiddenChange, () => {
- updateValue();
- });
-
- const setting = useSettingValue("notificationsEnabled");
- useEffect(() => {
- updateValue();
- }, [setting, updateValue]);
-
- // shouldShowPrompt is dependent on the client having push rules. There isn't an event for the client
- // fetching its push rules, but we'll know it has them by the time it sync, so we update this on sync.
- useTypedEventEmitter(client, ClientEvent.Sync, updateValue);
-
- return value;
-}
-
-export function useUserOnboardingContext(): UserOnboardingContext {
- const hasAvatar = useUserOnboardingContextValue(false, async (cli) => {
- const profile = await cli.getProfileInfo(cli.getUserId()!);
- return Boolean(profile?.avatar_url);
- });
- const hasDevices = useUserOnboardingContextValue(false, async (cli) => {
- const myDevice = cli.getDeviceId();
- const devices = await cli.getDevices();
- return Boolean(devices.devices.find((device) => device.device_id !== myDevice));
- });
- const hasDmRooms = useUserOnboardingContextValue(false, async () => {
- const dmRooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals() ?? {};
- return Boolean(Object.keys(dmRooms).length);
- });
- const showNotificationsPrompt = useShowNotificationsPrompt();
-
- return useMemo(
- () => ({ hasAvatar, hasDevices, hasDmRooms, showNotificationsPrompt }),
- [hasAvatar, hasDevices, hasDmRooms, showNotificationsPrompt],
- );
-}
diff --git a/src/hooks/useUserOnboardingTasks.ts b/src/hooks/useUserOnboardingTasks.ts
deleted file mode 100644
index 87fec0d78d1..00000000000
--- a/src/hooks/useUserOnboardingTasks.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { useMemo } from "react";
-
-import { AppDownloadDialog, showAppDownloadDialogPrompt } from "../components/views/dialogs/AppDownloadDialog";
-import { UserTab } from "../components/views/dialogs/UserTab";
-import { ButtonEvent } from "../components/views/elements/AccessibleButton";
-import { Action } from "../dispatcher/actions";
-import defaultDispatcher from "../dispatcher/dispatcher";
-import { _t } from "../languageHandler";
-import Modal from "../Modal";
-import { Notifier } from "../Notifier";
-import PosthogTrackers from "../PosthogTrackers";
-import SdkConfig from "../SdkConfig";
-import { UseCase } from "../settings/enums/UseCase";
-import { useSettingValue } from "./useSettings";
-import { UserOnboardingContext } from "./useUserOnboardingContext";
-
-interface UserOnboardingTask {
- id: string;
- title: string | (() => string);
- description: string | (() => string);
- relevant?: UseCase[];
- action?: {
- label: string;
- onClick?: (ev: ButtonEvent) => void;
- href?: string;
- hideOnComplete?: boolean;
- };
- completed: (ctx: UserOnboardingContext) => boolean;
- disabled?(): boolean;
-}
-
-export interface UserOnboardingTaskWithResolvedCompletion extends Omit {
- completed: boolean;
-}
-
-const onClickStartDm = (ev: ButtonEvent): void => {
- PosthogTrackers.trackInteraction("WebUserOnboardingTaskSendDm", ev);
- defaultDispatcher.dispatch({ action: "view_create_chat" });
-};
-
-const tasks: UserOnboardingTask[] = [
- {
- id: "create-account",
- title: _t("auth|create_account_title"),
- description: _t("onboarding|you_made_it"),
- completed: () => true,
- },
- {
- id: "find-friends",
- title: _t("onboarding|find_friends"),
- description: _t("onboarding|find_friends_description"),
- completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
- relevant: [UseCase.PersonalMessaging, UseCase.Skip],
- action: {
- label: _t("onboarding|find_friends_action"),
- onClick: onClickStartDm,
- },
- },
- {
- id: "find-coworkers",
- title: _t("onboarding|find_coworkers"),
- description: _t("onboarding|get_stuff_done"),
- completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
- relevant: [UseCase.WorkMessaging],
- action: {
- label: _t("onboarding|find_people"),
- onClick: onClickStartDm,
- },
- },
- {
- id: "find-community-members",
- title: _t("onboarding|find_community_members"),
- description: _t("onboarding|get_stuff_done"),
- completed: (ctx: UserOnboardingContext) => ctx.hasDmRooms,
- relevant: [UseCase.CommunityMessaging],
- action: {
- label: _t("onboarding|find_people"),
- onClick: onClickStartDm,
- },
- },
- {
- id: "download-apps",
- title: () =>
- _t("onboarding|download_app", {
- brand: SdkConfig.get("brand"),
- }),
- description: () =>
- _t("onboarding|download_app_description", {
- brand: SdkConfig.get("brand"),
- }),
- completed: (ctx: UserOnboardingContext) => ctx.hasDevices,
- action: {
- label: _t("onboarding|download_app_action"),
- onClick: (ev: ButtonEvent) => {
- PosthogTrackers.trackInteraction("WebUserOnboardingTaskDownloadApps", ev);
- Modal.createDialog(AppDownloadDialog, {}, "mx_AppDownloadDialog_wrapper", false, true);
- },
- },
- disabled(): boolean {
- return !showAppDownloadDialogPrompt();
- },
- },
- {
- id: "setup-profile",
- title: _t("onboarding|set_up_profile"),
- description: _t("onboarding|set_up_profile_description"),
- completed: (ctx: UserOnboardingContext) => ctx.hasAvatar,
- action: {
- label: _t("onboarding|set_up_profile_action"),
- onClick: (ev: ButtonEvent) => {
- PosthogTrackers.trackInteraction("WebUserOnboardingTaskSetupProfile", ev);
- defaultDispatcher.dispatch({
- action: Action.ViewUserSettings,
- initialTabId: UserTab.Account,
- });
- },
- },
- },
- {
- id: "permission-notifications",
- title: _t("onboarding|enable_notifications"),
- description: _t("onboarding|enable_notifications_description"),
- completed: (ctx: UserOnboardingContext) => !ctx.showNotificationsPrompt,
- action: {
- label: _t("onboarding|enable_notifications_action"),
- onClick: (ev: ButtonEvent) => {
- PosthogTrackers.trackInteraction("WebUserOnboardingTaskEnableNotifications", ev);
- defaultDispatcher.dispatch({
- action: Action.ViewUserSettings,
- initialTabId: UserTab.Notifications,
- });
- Notifier.setPromptHidden(true);
- },
- hideOnComplete: !Notifier.isPossible(),
- },
- },
-];
-
-export function useUserOnboardingTasks(context: UserOnboardingContext): UserOnboardingTaskWithResolvedCompletion[] {
- const useCase = useSettingValue("FTUE.useCaseSelection") ?? UseCase.Skip;
-
- return useMemo(() => {
- return tasks
- .filter((task) => {
- if (task.disabled?.()) return false;
- return !task.relevant || task.relevant.includes(useCase);
- })
- .map((task) => ({
- ...task,
- completed: task.completed(context),
- }));
- }, [context, useCase]);
-}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 42cf08ae703..9bd3c68436b 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -451,7 +451,6 @@
"one": "and one other...",
"other": "and %(count)s others..."
},
- "android": "Android",
"appearance": "Appearance",
"application": "Application",
"are_you_sure": "Are you sure?",
@@ -491,7 +490,6 @@
"identity_server": "Identity server",
"image": "Image",
"integration_manager": "Integration manager",
- "ios": "iOS",
"joined": "Joined",
"labs": "Labs",
"legal": "Legal",
@@ -585,8 +583,7 @@
"video": "Video",
"video_room": "Video room",
"view_message": "View message",
- "warning": "Warning",
- "welcome": "Welcome"
+ "warning": "Warning"
},
"composer": {
"autocomplete": {
@@ -1628,61 +1625,15 @@
"m.key.verification.request": "%(name)s is requesting verification"
},
"onboarding": {
- "apple_trademarks": "App Store® and the Apple logo® are trademarks of Apple Inc.",
- "community_messaging_action": "Find your people",
- "community_messaging_description": "Keep ownership and control of community discussion.\nScale to support millions, with powerful moderation and interoperability.",
- "community_messaging_title": "Community ownership",
- "complete_these": "Complete these to get the most out of %(brand)s",
"create_room": "Create a Group Chat",
- "download_app": "Download %(brand)s",
- "download_app_action": "Download apps",
- "download_app_description": "Don’t miss a thing by taking %(brand)s with you",
- "download_app_store": "Download on the App Store",
- "download_brand": "Download %(brand)s",
- "download_brand_desktop": "Download %(brand)s Desktop",
- "download_f_droid": "Get it on F-Droid",
- "download_google_play": "Get it on Google Play",
- "enable_notifications": "Turn on desktop notifications",
- "enable_notifications_action": "Open settings",
- "enable_notifications_description": "Don’t miss a reply or important message",
"explore_rooms": "Explore Public Rooms",
- "find_community_members": "Find and invite your community members",
- "find_coworkers": "Find and invite your co-workers",
- "find_friends": "Find and invite your friends",
- "find_friends_action": "Find friends",
- "find_friends_description": "It’s what you’re here for, so lets get to it",
- "find_people": "Find people",
- "free_e2ee_messaging_unlimited_voip": "With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",
- "get_stuff_done": "Get stuff done by finding your teammates",
- "google_trademarks": "Google Play and the Google Play logo are trademarks of Google LLC.",
"has_avatar_label": "Great, that'll help people know it's you",
"intro_byline": "Own your conversations.",
"intro_welcome": "Welcome to %(appName)s",
"no_avatar_label": "Add a photo so people know it's you.",
- "only_n_steps_to_go": {
- "one": "Only %(count)s step to go",
- "other": "Only %(count)s steps to go"
- },
- "personal_messaging_action": "Start your first chat",
- "personal_messaging_title": "Secure messaging for friends and family",
- "qr_or_app_links": "%(qrCode)s or %(appLinks)s",
"send_dm": "Send a Direct Message",
- "set_up_profile": "Set up your profile",
- "set_up_profile_action": "Your profile",
- "set_up_profile_description": "Make sure people know it’s really you",
- "use_case_community_messaging": "Online community members",
- "use_case_heading1": "You're in",
- "use_case_heading2": "Who will you chat to the most?",
- "use_case_heading3": "We'll help you get connected.",
- "use_case_personal_messaging": "Friends and family",
- "use_case_work_messaging": "Coworkers and teams",
"welcome_detail": "Now, let's help you get started",
- "welcome_to_brand": "Welcome to %(brand)s",
- "welcome_user": "Welcome %(name)s",
- "work_messaging_action": "Find your co-workers",
- "work_messaging_title": "Secure messaging for work",
- "you_did_it": "You did it!",
- "you_made_it": "You made it!"
+ "welcome_user": "Welcome %(name)s"
},
"pill": {
"permalink_other_room": "Message in %(room)s",
@@ -2686,7 +2637,6 @@
"room_directory_heading": "Room directory",
"room_list_heading": "Room list",
"show_avatars_pills": "Show avatars in user, room and event mentions",
- "show_checklist_shortcuts": "Show shortcut to welcome checklist above the room list",
"show_polls_button": "Show polls button",
"surround_text": "Surround selected text when typing special characters",
"time_heading": "Displaying time",
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index 9c4bb76f9f9..48a271a9a96 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -38,7 +38,6 @@ import { WatchManager } from "./WatchManager";
import { CustomTheme } from "../theme";
import AnalyticsController from "./controllers/AnalyticsController";
import FallbackIceServerController from "./controllers/FallbackIceServerController";
-import { UseCase } from "./enums/UseCase.tsx";
import { IRightPanelForRoomStored } from "../stores/right-panel/RightPanelStoreIPanelState.ts";
import { ILayoutSettings } from "../stores/widgets/WidgetLayoutStore.ts";
import { ReleaseAnnouncementData } from "../stores/ReleaseAnnouncementStore.ts";
@@ -280,7 +279,6 @@ export interface Settings {
"analyticsOptIn": IBaseSetting;
"pseudonymousAnalyticsOptIn": IBaseSetting;
"deviceClientInformationOptIn": IBaseSetting;
- "FTUE.useCaseSelection": IBaseSetting;
"Registration.mobileRegistrationHelper": IBaseSetting;
"autocompleteDelay": IBaseSetting;
"readMarkerInViewThresholdMs": IBaseSetting;
@@ -308,7 +306,6 @@ export interface Settings {
deny?: string[];
}>;
"breadcrumbs": IBaseSetting;
- "FTUE.userOnboardingButton": IBaseSetting;
"showHiddenEventsInTimeline": IBaseSetting;
"lowBandwidth": IBaseSetting;
"fallbackICEServerAllowed": IBaseSetting;
@@ -992,10 +989,6 @@ export const SETTINGS: Settings = {
displayName: _td("settings|security|record_session_details"),
default: false,
},
- "FTUE.useCaseSelection": {
- supportedLevels: LEVELS_ACCOUNT_SETTINGS,
- default: null,
- },
"Registration.mobileRegistrationHelper": {
supportedLevels: [SettingLevel.CONFIG],
default: false,
@@ -1086,11 +1079,6 @@ export const SETTINGS: Settings = {
displayName: _td("settings|show_breadcrumbs"),
default: true,
},
- "FTUE.userOnboardingButton": {
- supportedLevels: LEVELS_ACCOUNT_SETTINGS,
- displayName: _td("settings|preferences|show_checklist_shortcuts"),
- default: true,
- },
"showHiddenEventsInTimeline": {
displayName: _td("devtools|show_hidden_events"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
diff --git a/src/settings/enums/UseCase.tsx b/src/settings/enums/UseCase.tsx
deleted file mode 100644
index 036e0a51cd2..00000000000
--- a/src/settings/enums/UseCase.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-export enum UseCase {
- PersonalMessaging = "PersonalMessaging",
- WorkMessaging = "WorkMessaging",
- CommunityMessaging = "CommunityMessaging",
- Skip = "Skip",
-}
diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx
index 751a670fc0b..a29834d51f7 100644
--- a/test/unit-tests/components/structures/MatrixChat-test.tsx
+++ b/test/unit-tests/components/structures/MatrixChat-test.tsx
@@ -1114,19 +1114,6 @@ describe("", () => {
// set up keys screen is rendered
expect(screen.getByText("Setting up keys")).toBeInTheDocument();
});
-
- it("should go to use case selection if user just registered", async () => {
- loginClient.doesServerSupportUnstableFeature.mockResolvedValue(true);
- MatrixClientPeg.setJustRegisteredUserId(userId);
-
- await getComponentAndLogin();
-
- bootstrapDeferred.resolve();
-
- await expect(
- screen.findByRole("heading", { name: "You're in", level: 1 }),
- ).resolves.toBeInTheDocument();
- });
});
});
diff --git a/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx b/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx
deleted file mode 100644
index ed329cfcdb8..00000000000
--- a/test/unit-tests/components/views/dialogs/AppDownloadDialog-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2023 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { render, screen } from "jest-matrix-react";
-
-import { AppDownloadDialog } from "../../../../../src/components/views/dialogs/AppDownloadDialog";
-import SdkConfig, { ConfigOptions } from "../../../../../src/SdkConfig";
-
-describe("AppDownloadDialog", () => {
- afterEach(() => {
- SdkConfig.reset();
- });
-
- it("should render with desktop, ios, android, fdroid buttons by default", () => {
- const { asFragment } = render();
- expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).toBeInTheDocument();
- expect(asFragment()).toMatchSnapshot();
- });
-
- it("should allow disabling fdroid build", () => {
- SdkConfig.add({
- mobile_builds: {
- fdroid: null,
- },
- } as ConfigOptions);
- const { asFragment } = render();
- expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).not.toBeInTheDocument();
- expect(asFragment()).toMatchSnapshot();
- });
-
- it("should allow disabling desktop build", () => {
- SdkConfig.add({
- desktop_builds: {
- available: false,
- },
- } as ConfigOptions);
- const { asFragment } = render();
- expect(screen.queryByRole("button", { name: "Download Element Desktop" })).not.toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Download on the App Store" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on Google Play" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).toBeInTheDocument();
- expect(asFragment()).toMatchSnapshot();
- });
-
- it("should allow disabling mobile builds", () => {
- SdkConfig.add({
- mobile_builds: {
- ios: null,
- android: null,
- fdroid: null,
- },
- } as ConfigOptions);
- const { asFragment } = render();
- expect(screen.queryByRole("button", { name: "Download Element Desktop" })).toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Download on the App Store" })).not.toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on Google Play" })).not.toBeInTheDocument();
- expect(screen.queryByRole("button", { name: "Get it on F-Droid" })).not.toBeInTheDocument();
- expect(asFragment()).toMatchSnapshot();
- });
-});
diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap
deleted file mode 100644
index 6d4e827c474..00000000000
--- a/test/unit-tests/components/views/dialogs/__snapshots__/AppDownloadDialog-test.tsx.snap
+++ /dev/null
@@ -1,540 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AppDownloadDialog should allow disabling desktop build 1`] = `
-
-
-
-
-
-
-
-
- Android
-
-
-
- or
-
-
-
-
-
-
- App Store® and the Apple logo® are trademarks of Apple Inc.
-
-
- Google Play and the Google Play logo are trademarks of Google LLC.
-
-
-
-
-
-
-`;
-
-exports[`AppDownloadDialog should allow disabling fdroid build 1`] = `
-
-
-
-
-
-
-
-
-
- Android
-
-
-
- or
-
-
-
-
-
-
- App Store® and the Apple logo® are trademarks of Apple Inc.
-
-
- Google Play and the Google Play logo are trademarks of Google LLC.
-
-
-
-
-
-
-`;
-
-exports[`AppDownloadDialog should allow disabling mobile builds 1`] = `
-
-
-
-
-
-
-
-
- App Store® and the Apple logo® are trademarks of Apple Inc.
-
-
- Google Play and the Google Play logo are trademarks of Google LLC.
-
-
-
-
-
-
-`;
-
-exports[`AppDownloadDialog should render with desktop, ios, android, fdroid buttons by default 1`] = `
-
-
-
-
-
-
-
-
-
- Android
-
-
-
- or
-
-
-
-
-
-
- App Store® and the Apple logo® are trademarks of Apple Inc.
-
-
- Google Play and the Google Play logo are trademarks of Google LLC.
-
-
-
-
-
-
-`;
diff --git a/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx b/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx
deleted file mode 100644
index f5a693cda33..00000000000
--- a/test/unit-tests/components/views/user-onboarding/UserOnboardingList-test.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import { getUserOnboardingCounters } from "../../../../../src/components/views/user-onboarding/UserOnboardingList";
-
-const tasks = [
- {
- id: "1",
- title: "Lorem ipsum",
- description: "Lorem ipsum dolor amet.",
- completed: true,
- },
- {
- id: "2",
- title: "Lorem ipsum",
- description: "Lorem ipsum dolor amet.",
- completed: false,
- },
-];
-
-describe("getUserOnboardingCounters()", () => {
- it.each([
- {
- tasks: [],
- expectation: {
- completed: 0,
- waiting: 0,
- total: 0,
- },
- },
- {
- tasks: tasks,
- expectation: {
- completed: 1,
- waiting: 1,
- total: 2,
- },
- },
- ])("should calculate counters correctly", ({ tasks, expectation }) => {
- const result = getUserOnboardingCounters(tasks);
- expect(result).toStrictEqual(expectation);
- });
-});
diff --git a/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx b/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx
deleted file mode 100644
index 03eefcfde50..00000000000
--- a/test/unit-tests/components/views/user-onboarding/UserOnboardingPage-test.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { act, render, RenderResult } from "jest-matrix-react";
-
-import { filterConsole, withClientContextRenderOptions, stubClient } from "../../../../test-utils";
-import { UserOnboardingPage } from "../../../../../src/components/views/user-onboarding/UserOnboardingPage";
-import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
-import SdkConfig from "../../../../../src/SdkConfig";
-
-jest.mock("../../../../../src/components/structures/EmbeddedPage", () => ({
- __esModule: true,
- default: ({ url }: { url: string }) => {url}
,
-}));
-
-jest.mock("../../../../../src/components/structures/HomePage", () => ({
- __esModule: true,
- default: () => home page
,
-}));
-
-describe("UserOnboardingPage", () => {
- const renderComponent = async (): Promise => {
- const renderResult = render(, withClientContextRenderOptions(MatrixClientPeg.safeGet()));
- await act(async () => {
- jest.runAllTimers();
- });
- return renderResult;
- };
-
- filterConsole(
- // unrelated for this test
- "could not update user onboarding context",
- );
-
- beforeEach(() => {
- stubClient();
- jest.useFakeTimers();
- });
-
- afterEach(() => {
- jest.useRealTimers();
- jest.restoreAllMocks();
- });
-
- describe("when the user registered before the cutoff date", () => {
- beforeEach(() => {
- jest.spyOn(MatrixClientPeg, "userRegisteredAfter").mockReturnValue(false);
- });
-
- it("should render the home page", async () => {
- expect((await renderComponent()).queryByText("home page")).toBeInTheDocument();
- });
- });
-
- describe("when the user registered after the cutoff date", () => {
- beforeEach(() => {
- jest.spyOn(MatrixClientPeg, "userRegisteredAfter").mockReturnValue(true);
- });
-
- describe("and there is an explicit home page configured", () => {
- beforeEach(() => {
- jest.spyOn(SdkConfig, "get").mockReturnValue({
- embedded_pages: {
- home_url: "https://example.com/home",
- },
- });
- });
-
- it("should render the configured page", async () => {
- expect((await renderComponent()).queryByText("https://example.com/home")).toBeInTheDocument();
- });
- });
-
- describe("and there is no home page configured", () => {
- it("should render the onboarding", async () => {
- expect((await renderComponent()).queryByTestId("user-onboarding-list")).toBeInTheDocument();
- });
- });
- });
-});
diff --git a/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx b/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
deleted file mode 100644
index c20a75e910b..00000000000
--- a/test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2024 New Vector Ltd.
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
-Please see LICENSE files in the repository root for full details.
-*/
-
-import React from "react";
-import { renderHook, waitFor } from "jest-matrix-react";
-
-import { useUserOnboardingTasks } from "../../../src/hooks/useUserOnboardingTasks";
-import { useUserOnboardingContext } from "../../../src/hooks/useUserOnboardingContext";
-import { stubClient } from "../../test-utils";
-import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
-import DMRoomMap from "../../../src/utils/DMRoomMap";
-import PlatformPeg from "../../../src/PlatformPeg";
-
-describe("useUserOnboardingTasks", () => {
- it.each([
- {
- context: {
- hasAvatar: false,
- hasDevices: false,
- hasDmRooms: false,
- showNotificationsPrompt: false,
- },
- },
- {
- context: {
- hasAvatar: true,
- hasDevices: false,
- hasDmRooms: false,
- showNotificationsPrompt: true,
- },
- },
- ])("sequence should stay static", async ({ context }) => {
- const { result } = renderHook(() => useUserOnboardingTasks(context));
-
- expect(result.current).toHaveLength(5);
- expect(result.current[0].id).toBe("create-account");
- expect(result.current[1].id).toBe("find-friends");
- expect(result.current[2].id).toBe("download-apps");
- expect(result.current[3].id).toBe("setup-profile");
- expect(result.current[4].id).toBe("permission-notifications");
- });
-
- it("should mark desktop notifications task completed on click", async () => {
- jest.spyOn(PlatformPeg, "get").mockReturnValue({
- supportsNotifications: jest.fn().mockReturnValue(true),
- maySendNotifications: jest.fn().mockReturnValue(false),
- } as any);
-
- const cli = stubClient();
- cli.pushRules = {
- global: {
- override: [
- {
- rule_id: ".m.rule.master",
- enabled: false,
- actions: [],
- default: true,
- },
- ],
- },
- };
- DMRoomMap.makeShared(cli);
- const context = renderHook(() => useUserOnboardingContext(), {
- wrapper: (props) => {
- return {props.children};
- },
- });
- const { result, rerender } = renderHook(() => useUserOnboardingTasks(context.result.current));
- expect(result.current[4].id).toBe("permission-notifications");
- expect(result.current[4].completed).toBe(false);
- result.current[4].action!.onClick!({ type: "click" } as any);
- await waitFor(() => {
- rerender();
- expect(result.current[4].completed).toBe(true);
- });
- });
-});