From 5b900ab6e2da2e3b582eafb44fe2c9ec1b4d8415 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 11 Dec 2025 16:43:20 +0100 Subject: [PATCH] Move room list search to shared components (#31502) * refactor: move room list search to shared components * refactor: add view model * refactor: use view and vm in room list search component * refactor: use room list id instead of class for landmark navigation * refactor: remove old room list search css * test: add screenshots test for room list search view * test: fix e2e test using class as selector... --- ...-roomlistsearchview--all-buttons-linux.png | Bin 0 -> 9090 bytes ...list-roomlistsearchview--default-linux.png | Bin 0 -> 8634 bytes ...oomlistsearchview--with-dial-pad-linux.png | Bin 0 -> 9090 bytes ...mlistsearchview--without-explore-linux.png | Bin 0 -> 7768 bytes packages/shared-components/src/index.ts | 1 + .../RoomListSearchView.module.css | 47 +++ .../RoomListSearchView.stories.tsx | 74 +++++ .../RoomListSearchView.test.tsx | 103 +++++++ .../RoomListSearchView/RoomListSearchView.tsx | 119 +++++++ .../RoomListSearchView.test.tsx.snap | 290 ++++++++++++++++++ .../src/room-list/RoomListSearchView/index.ts | 9 + .../accessibility/keyboard-navigation.spec.ts | 12 +- playwright/e2e/voip/pstn.spec.ts | 2 +- res/css/_components.pcss | 1 - .../rooms/RoomListPanel/_RoomListSearch.pcss | 45 --- src/accessibility/LandmarkNavigation.ts | 2 +- .../rooms/RoomListPanel/RoomListSearch.tsx | 73 +---- .../room-list/RoomListSearchViewModel.ts | 117 +++++++ .../accessibility/LandmarkNavigation-test.tsx | 4 +- .../RoomListPanel/RoomListSearch-test.tsx | 78 +---- .../RoomListSearch-test.tsx.snap | 207 +------------ .../room-list/RoomListSearchViewModel-test.ts | 114 +++++++ 22 files changed, 901 insertions(+), 397 deletions(-) create mode 100644 packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--all-buttons-linux.png create mode 100644 packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--default-linux.png create mode 100644 packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--with-dial-pad-linux.png create mode 100644 packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--without-explore-linux.png create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.module.css create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.stories.tsx create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.test.tsx create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.tsx create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/__snapshots__/RoomListSearchView.test.tsx.snap create mode 100644 packages/shared-components/src/room-list/RoomListSearchView/index.ts delete mode 100644 res/css/views/rooms/RoomListPanel/_RoomListSearch.pcss create mode 100644 src/viewmodels/room-list/RoomListSearchViewModel.ts create mode 100644 test/viewmodels/room-list/RoomListSearchViewModel-test.ts diff --git a/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--all-buttons-linux.png b/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--all-buttons-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..0d7f17d5114cb357db1f36e73caa77eab01ac384 GIT binary patch literal 9090 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 TL9M_QkjqJrpGkkcc>Ui1kIhw1 literal 0 HcmV?d00001 diff --git a/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--default-linux.png b/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--default-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..2f41682551ca26dcac0dc7b18f2f3753cf584283 GIT binary patch literal 8634 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 TL9M_QkjqJrpGkkcc>Ui1kIhw1 literal 0 HcmV?d00001 diff --git a/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--without-explore-linux.png b/packages/shared-components/playwright/snapshots/room-list-roomlistsearchview--without-explore-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..e3e14ccfb4e575362a87658694a90dfc8d7fbe85 GIT binary patch literal 7768 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 literal 0 HcmV?d00001 diff --git a/packages/shared-components/src/index.ts b/packages/shared-components/src/index.ts index a806971a3f..849634e9da 100644 --- a/packages/shared-components/src/index.ts +++ b/packages/shared-components/src/index.ts @@ -19,6 +19,7 @@ export * from "./pill-input/Pill"; export * from "./pill-input/PillInput"; export * from "./rich-list/RichItem"; export * from "./rich-list/RichList"; +export * from "./room-list/RoomListSearchView"; export * from "./utils/Box"; export * from "./utils/Flex"; diff --git a/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.module.css b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.module.css new file mode 100644 index 0000000000..9b7097373c --- /dev/null +++ b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.module.css @@ -0,0 +1,47 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * 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. + */ + +.view { + /* From figma, this should be aligned with the room header */ + min-height: 64px; + box-sizing: border-box; + border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-bg-subtle-primary); + padding: 0 var(--cpd-space-3x); +} + +.search { + /* The search button should take all the remaining space */ + flex: 1; + /* !important is needed to override compound button in EW */ + font: var(--cpd-font-body-md-regular) !important; + color: var(--cpd-color-text-secondary) !important; + min-width: 0; + + svg { + fill: var(--cpd-color-icon-secondary); + } +} + +.search_container { + flex: 1; + + /* Shrink and truncate the search text */ + white-space: nowrap; + overflow: hidden; + + kbd { + font-family: inherit; + } +} + +.search_text { + min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: start; +} diff --git a/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.stories.tsx b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.stories.tsx new file mode 100644 index 0000000000..66f5af461c --- /dev/null +++ b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.stories.tsx @@ -0,0 +1,74 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * 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, { type JSX } from "react"; +import { fn } from "storybook/test"; + +import type { Meta, StoryFn } from "@storybook/react-vite"; +import { + RoomListSearchView, + type RoomListSearchViewActions, + type RoomListSearchViewSnapshot, +} from "./RoomListSearchView"; +import { useMockedViewModel } from "../../useMockedViewModel"; + +type RoomListSearchProps = RoomListSearchViewSnapshot & RoomListSearchViewActions; + +const RoomListSearchViewWrapper = ({ + onSearchClick, + onDialPadClick, + onExploreClick, + ...rest +}: RoomListSearchProps): JSX.Element => { + const vm = useMockedViewModel(rest, { + onSearchClick, + onDialPadClick, + onExploreClick, + }); + return ; +}; + +export default { + title: "Room List/RoomListSearchView", + component: RoomListSearchViewWrapper, + tags: ["autodocs"], + args: { + displayExploreButton: true, + displayDialButton: false, + searchShortcut: "⌘ K", + onSearchClick: fn(), + onDialPadClick: fn(), + onExploreClick: fn(), + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/vlmt46QDdE4dgXDiyBJXqp/ER-33-Left-Panel-2025?node-id=98-1979&t=vafb4zoYMNLRuAbh-4", + }, + }, +} as Meta; + +const Template: StoryFn = (args) => ; + +export const Default = Template.bind({}); + +export const WithDialPad = Template.bind({}); +WithDialPad.args = { + displayDialButton: true, +}; + +export const WithoutExplore = Template.bind({}); +WithoutExplore.args = { + displayExploreButton: false, +}; + +export const AllButtons = Template.bind({}); +AllButtons.args = { + displayExploreButton: true, + displayDialButton: true, + searchShortcut: "⌘ K", +}; diff --git a/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.test.tsx b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.test.tsx new file mode 100644 index 0000000000..1a256d63b1 --- /dev/null +++ b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.test.tsx @@ -0,0 +1,103 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * 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 { render, screen } from "jest-matrix-react"; +import { composeStories } from "@storybook/react-vite"; +import React from "react"; +import userEvent from "@testing-library/user-event"; + +import * as stories from "./RoomListSearchView.stories"; +import { + RoomListSearchView, + type RoomListSearchViewActions, + type RoomListSearchViewSnapshot, +} from "./RoomListSearchView"; +import { MockViewModel } from "../../viewmodel/MockViewModel"; + +const { Default, WithDialPad, WithoutExplore, AllButtons } = composeStories(stories); + +describe("RoomListSearchView", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("Storybook snapshots", () => { + it("renders the default state", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders with dial pad button", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders without explore button", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders with all buttons visible", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + }); + + describe("User interactions", () => { + const onSearchClick = jest.fn(); + const onDialPadClick = jest.fn(); + const onExploreClick = jest.fn(); + + class TestViewModel extends MockViewModel implements RoomListSearchViewActions { + public onSearchClick = onSearchClick; + public onDialPadClick = onDialPadClick; + public onExploreClick = onExploreClick; + } + + it("should call onSearchClick when search button is clicked", async () => { + const user = userEvent.setup(); + const vm = new TestViewModel({ + displayExploreButton: false, + displayDialButton: false, + searchShortcut: "⌘ K", + }); + + render(); + + await user.click(screen.getByRole("button", { name: "Search ⌘ K" })); + expect(onSearchClick).toHaveBeenCalledTimes(1); + }); + + it("should call onDialPadClick when dial pad button is clicked", async () => { + const user = userEvent.setup(); + const vm = new TestViewModel({ + displayExploreButton: false, + displayDialButton: true, + searchShortcut: "⌘ K", + }); + + render(); + + await user.click(screen.getByRole("button", { name: "Open dial pad" })); + expect(onDialPadClick).toHaveBeenCalledTimes(1); + }); + + it("should call onExploreClick when explore button is clicked", async () => { + const user = userEvent.setup(); + const vm = new TestViewModel({ + displayExploreButton: true, + displayDialButton: false, + searchShortcut: "⌘ K", + }); + + render(); + + await user.click(screen.getByRole("button", { name: "Explore rooms" })); + expect(onExploreClick).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.tsx b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.tsx new file mode 100644 index 0000000000..0c652328ec --- /dev/null +++ b/packages/shared-components/src/room-list/RoomListSearchView/RoomListSearchView.tsx @@ -0,0 +1,119 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * 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, { type JSX, type MouseEventHandler } from "react"; +import { Button } from "@vector-im/compound-web"; +import ExploreIcon from "@vector-im/compound-design-tokens/assets/web/icons/explore"; +import SearchIcon from "@vector-im/compound-design-tokens/assets/web/icons/search"; +import DialPadIcon from "@vector-im/compound-design-tokens/assets/web/icons/dial-pad"; + +import styles from "./RoomListSearchView.module.css"; +import { type ViewModel } from "../../viewmodel/ViewModel"; +import { useViewModel } from "../../useViewModel"; +import { Flex } from "../../utils/Flex"; +import { useI18n } from "../../utils/i18nContext"; + +export interface RoomListSearchViewSnapshot { + /** + * Whether to display the explore button. + */ + displayExploreButton: boolean; + /** + * Whether to display the dial pad button. + */ + displayDialButton: boolean; + /** + * The keyboard shortcut text to display for the search action. + * For example: "⌘ K" on macOS or "Ctrl K" on other platforms. + */ + searchShortcut: string; +} + +export interface RoomListSearchViewActions { + /** + * Handles the click event on the search button. + */ + onSearchClick: MouseEventHandler; + /** + * Handles the click event on the dial pad button. + */ + onDialPadClick: MouseEventHandler; + /** + * Handles the click event on the explore button. + */ + onExploreClick: MouseEventHandler; +} + +/** + * The view model for the room list search component. + */ +export type RoomListSearchViewModel = ViewModel & RoomListSearchViewActions; + +interface RoomListSearchViewProps { + /** + * The view model for the room list search component. + */ + vm: RoomListSearchViewModel; +} + +/** + * A search component to be displayed at the top of the room list. + * The component provides search functionality, optional dial pad access, and optional room exploration. + * + * @example + * ```tsx + * + * ``` + */ +export function RoomListSearchView({ vm }: Readonly): JSX.Element { + const { translate: _t } = useI18n(); + const { displayExploreButton, displayDialButton, searchShortcut } = useViewModel(vm); + + return ( + + + {displayDialButton && ( + + + + +`; + +exports[`RoomListSearchView Storybook snapshots renders with all buttons visible 1`] = ` +
+ +
+`; + +exports[`RoomListSearchView Storybook snapshots renders with dial pad button 1`] = ` +
+ +
+`; + +exports[`RoomListSearchView Storybook snapshots renders without explore button 1`] = ` +
+ +
+`; diff --git a/packages/shared-components/src/room-list/RoomListSearchView/index.ts b/packages/shared-components/src/room-list/RoomListSearchView/index.ts new file mode 100644 index 0000000000..a750dca7db --- /dev/null +++ b/packages/shared-components/src/room-list/RoomListSearchView/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * 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 type { RoomListSearchViewModel, RoomListSearchViewSnapshot } from "./RoomListSearchView"; +export { RoomListSearchView } from "./RoomListSearchView"; diff --git a/playwright/e2e/accessibility/keyboard-navigation.spec.ts b/playwright/e2e/accessibility/keyboard-navigation.spec.ts index 6635a01d57..8ba6cc3a92 100644 --- a/playwright/e2e/accessibility/keyboard-navigation.spec.ts +++ b/playwright/e2e/accessibility/keyboard-navigation.spec.ts @@ -29,7 +29,7 @@ test.describe("Landmark navigation tests", () => { // Pressing Control+F6 again will focus room search await page.keyboard.press("ControlOrMeta+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); // Pressing Control+F6 again will focus the message composer await page.keyboard.press("ControlOrMeta+F6"); @@ -44,7 +44,7 @@ test.describe("Landmark navigation tests", () => { await expect(page.locator(".mx_HomePage")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); await expect(page.locator(".mx_SpaceButton_active")).toBeFocused(); @@ -75,7 +75,7 @@ test.describe("Landmark navigation tests", () => { // Pressing Control+F6 again will focus room search await page.keyboard.press("ControlOrMeta+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); // Pressing Control+F6 again will focus the room tile in the room list await page.keyboard.press("ControlOrMeta+F6"); @@ -97,7 +97,7 @@ test.describe("Landmark navigation tests", () => { await expect(page.locator(".mx_RoomListItemView_selected")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); await expect(page.locator(".mx_SpaceButton_active")).toBeFocused(); @@ -131,7 +131,7 @@ test.describe("Landmark navigation tests", () => { // Pressing Control+F6 again will focus room search await page.keyboard.press("ControlOrMeta+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); // Pressing Control+F6 again will focus the room tile in the room list await page.keyboard.press("ControlOrMeta+F6"); @@ -153,7 +153,7 @@ test.describe("Landmark navigation tests", () => { await expect(page.locator(".mx_RoomListItemView")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); - await expect(page.locator(".mx_RoomListSearch_search")).toBeFocused(); + await expect(page.locator("#room-list-search-button")).toBeFocused(); await page.keyboard.press("ControlOrMeta+Shift+F6"); await expect(page.locator(".mx_SpaceButton_active")).toBeFocused(); diff --git a/playwright/e2e/voip/pstn.spec.ts b/playwright/e2e/voip/pstn.spec.ts index 0275b88067..4241db6522 100644 --- a/playwright/e2e/voip/pstn.spec.ts +++ b/playwright/e2e/voip/pstn.spec.ts @@ -24,7 +24,7 @@ test.describe("PSTN", () => { await toasts.rejectToast("Notifications"); await toasts.assertNoToasts(); - await expect(page.locator(".mx_RoomListSearch")).toMatchScreenshot("dialpad-trigger.png"); + await expect(page.getByTestId("room-list-search")).toMatchScreenshot("dialpad-trigger.png"); await page.getByLabel("Open dial pad").click(); await expect(page.locator(".mx_Dialog")).toMatchScreenshot("dialpad.png"); }); diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 21e39a1584..fe527fdc5b 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -273,7 +273,6 @@ @import "./views/rooms/RoomListPanel/_RoomListItemView.pcss"; @import "./views/rooms/RoomListPanel/_RoomListPanel.pcss"; @import "./views/rooms/RoomListPanel/_RoomListPrimaryFilters.pcss"; -@import "./views/rooms/RoomListPanel/_RoomListSearch.pcss"; @import "./views/rooms/RoomListPanel/_RoomListSecondaryFilters.pcss"; @import "./views/rooms/RoomListPanel/_RoomListSkeleton.pcss"; @import "./views/rooms/_AppsDrawer.pcss"; diff --git a/res/css/views/rooms/RoomListPanel/_RoomListSearch.pcss b/res/css/views/rooms/RoomListPanel/_RoomListSearch.pcss deleted file mode 100644 index 472badc3ad..0000000000 --- a/res/css/views/rooms/RoomListPanel/_RoomListSearch.pcss +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2025 New Vector Ltd. - * - * 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. - */ - -.mx_RoomListSearch { - /* From figma, this should be aligned with the room header */ - flex: 0 0 64px; - box-sizing: border-box; - border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-bg-subtle-primary); - padding: 0 var(--cpd-space-3x); - - .mx_RoomListSearch_search { - /* The search button should take all the remaining space */ - flex: 1; - font: var(--cpd-font-body-md-regular); - color: var(--cpd-color-text-secondary); - min-width: 0; - - svg { - fill: var(--cpd-color-icon-secondary); - } - - span { - flex: 1; - - kbd { - font-family: inherit; - } - - /* Shrink and truncate the search text */ - white-space: nowrap; - overflow: hidden; - .mx_RoomListSearch_search_text { - min-width: 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-align: start; - } - } - } -} diff --git a/src/accessibility/LandmarkNavigation.ts b/src/accessibility/LandmarkNavigation.ts index 404e01e99c..632c7ec613 100644 --- a/src/accessibility/LandmarkNavigation.ts +++ b/src/accessibility/LandmarkNavigation.ts @@ -75,7 +75,7 @@ const landmarkToDomElementMap: Record HTMLElement | null | undef [Landmark.ROOM_SEARCH]: () => SettingsStore.getValue("feature_new_room_list") - ? document.querySelector(".mx_RoomListSearch_search") + ? document.querySelector("#room-list-search-button") : document.querySelector(".mx_RoomSearch"), [Landmark.ROOM_LIST]: () => SettingsStore.getValue("feature_new_room_list") diff --git a/src/components/views/rooms/RoomListPanel/RoomListSearch.tsx b/src/components/views/rooms/RoomListPanel/RoomListSearch.tsx index f1c3c2e66d..0354831a9e 100644 --- a/src/components/views/rooms/RoomListPanel/RoomListSearch.tsx +++ b/src/components/views/rooms/RoomListPanel/RoomListSearch.tsx @@ -5,24 +5,10 @@ * Please see LICENSE files in the repository root for full details. */ -import React, { type JSX } from "react"; -import { Button } from "@vector-im/compound-web"; -import ExploreIcon from "@vector-im/compound-design-tokens/assets/web/icons/explore"; -import SearchIcon from "@vector-im/compound-design-tokens/assets/web/icons/search"; -import DialPadIcon from "@vector-im/compound-design-tokens/assets/web/icons/dial-pad"; -import { Flex } from "@element-hq/web-shared-components"; +import React, { useEffect, type JSX } from "react"; +import { RoomListSearchView, useCreateAutoDisposedViewModel } from "@element-hq/web-shared-components"; -import { IS_MAC, Key } from "../../../../Keyboard"; -import { _t } from "../../../../languageHandler"; -import { ALTERNATE_KEY_NAME } from "../../../../accessibility/KeyboardShortcuts"; -import { shouldShowComponent } from "../../../../customisations/helpers/UIComponents"; -import { UIComponent } from "../../../../settings/UIFeature"; -import { MetaSpace } from "../../../../stores/spaces"; -import { Action } from "../../../../dispatcher/actions"; -import PosthogTrackers from "../../../../PosthogTrackers"; -import defaultDispatcher from "../../../../dispatcher/dispatcher"; -import { useTypedEventEmitterState } from "../../../../hooks/useEventEmitter"; -import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../../LegacyCallHandler"; +import { RoomListSearchViewModel } from "../../../../viewmodels/room-list/RoomListSearchViewModel"; type RoomListSearchProps = { /** @@ -37,53 +23,10 @@ type RoomListSearchProps = { * The `Explore` button is displayed only in the Home meta space and when UIComponent.ExploreRooms is enabled. */ export function RoomListSearch({ activeSpace }: RoomListSearchProps): JSX.Element { - const displayExploreButton = activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms); - // We only display the dial button if the user is can make PSTN calls - const displayDialButton = useTypedEventEmitterState( - LegacyCallHandler.instance, - LegacyCallHandlerEvent.ProtocolSupport, - () => LegacyCallHandler.instance.getSupportsPstnProtocol(), - ); + const vm = useCreateAutoDisposedViewModel(() => new RoomListSearchViewModel({ activeSpace })); + useEffect(() => { + vm.setActiveSpace(activeSpace); + }, [activeSpace, vm]); - return ( - - - {displayDialButton && ( - - - - -`; - -exports[` should display the dial button when the PTSN protocol is not supported 1`] = ` - - - -`; - -exports[` should hide the explore button when UIComponent.ExploreRooms is disabled 1`] = ` - - - -`; - -exports[` should hide the explore button when the active space is not MetaSpace.Home 1`] = ` - -