Skip to content

Commit 3c5e113

Browse files
committed
refactor: use RoomListShared in room list panel
1 parent 3a03062 commit 3c5e113

File tree

4 files changed

+117
-88
lines changed

4 files changed

+117
-88
lines changed

src/components/structures/LeftPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
391391
return (
392392
<div className={containerClasses}>
393393
<div className="mx_LeftPanel_roomListContainer">
394-
<RoomListPanel activeSpace={this.state.activeSpace} />
394+
<RoomListPanel />
395395
</div>
396396
</div>
397397
);

src/components/views/rooms/RoomListPanel/RoomListPanel.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,10 @@ import { RoomListView } from "./RoomListView";
1515
import { Flex } from "../../../../shared-components/Flex";
1616
import { _t } from "../../../../languageHandler";
1717

18-
type RoomListPanelProps = {
19-
/**
20-
* Current active space
21-
* See {@link RoomListSearch}
22-
*/
23-
activeSpace: string;
24-
};
25-
2618
/**
2719
* The panel of the room list
2820
*/
29-
export const RoomListPanel: React.FC<RoomListPanelProps> = ({ activeSpace }) => {
21+
export const RoomListPanel: React.FC = () => {
3022
const displayRoomSearch = shouldShowComponent(UIComponent.FilterContainer);
3123

3224
return (
@@ -37,7 +29,7 @@ export const RoomListPanel: React.FC<RoomListPanelProps> = ({ activeSpace }) =>
3729
align="stretch"
3830
aria-label={_t("room_list|list_title")}
3931
>
40-
{displayRoomSearch && <RoomListSearch activeSpace={activeSpace} />}
32+
{displayRoomSearch && <RoomListSearch />}
4133
<RoomListHeaderView />
4234
<RoomListView />
4335
</Flex>

src/components/views/rooms/RoomListPanel/RoomListSearch.tsx

Lines changed: 6 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -5,87 +5,16 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
import React, { type JSX } from "react";
9-
import { Button } from "@vector-im/compound-web";
10-
import ExploreIcon from "@vector-im/compound-design-tokens/assets/web/icons/explore";
11-
import SearchIcon from "@vector-im/compound-design-tokens/assets/web/icons/search";
12-
import DialPadIcon from "@vector-im/compound-design-tokens/assets/web/icons/dial-pad";
8+
import React, { type JSX, useMemo } from "react";
139

14-
import { IS_MAC, Key } from "../../../../shared-components/Keyboard";
15-
import { _t } from "../../../../languageHandler";
16-
import { ALTERNATE_KEY_NAME } from "../../../../accessibility/KeyboardShortcuts";
17-
import { shouldShowComponent } from "../../../../customisations/helpers/UIComponents";
18-
import { UIComponent } from "../../../../settings/UIFeature";
19-
import { MetaSpace } from "../../../../stores/spaces";
20-
import { Action } from "../../../../dispatcher/actions";
21-
import PosthogTrackers from "../../../../PosthogTrackers";
22-
import defaultDispatcher from "../../../../dispatcher/dispatcher";
23-
import { Flex } from "../../../../shared-components/Flex";
24-
import { useTypedEventEmitterState } from "../../../../hooks/useEventEmitter";
25-
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../../LegacyCallHandler";
26-
27-
type RoomListSearchProps = {
28-
/**
29-
* Current active space
30-
* The explore button is only displayed in the Home meta space
31-
*/
32-
activeSpace: string;
33-
};
10+
import { RoomListSearchViewModel } from "../../../../viewmodels/room-list/RoomListSearchViewModel";
11+
import { RoomListSearch as RoomListSearchView } from "../../../../shared-components/room-list/RoomListSearch";
3412

3513
/**
3614
* A search component to be displayed at the top of the room list
3715
* The `Explore` button is displayed only in the Home meta space and when UIComponent.ExploreRooms is enabled.
3816
*/
39-
export function RoomListSearch({ activeSpace }: RoomListSearchProps): JSX.Element {
40-
const displayExploreButton = activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms);
41-
// We only display the dial button if the user is can make PSTN calls
42-
const displayDialButton = useTypedEventEmitterState(
43-
LegacyCallHandler.instance,
44-
LegacyCallHandlerEvent.ProtocolSupport,
45-
() => LegacyCallHandler.instance.getSupportsPstnProtocol(),
46-
);
47-
48-
return (
49-
<Flex className="mx_RoomListSearch" role="search" gap="var(--cpd-space-2x)" align="center">
50-
<Button
51-
className="mx_RoomListSearch_search"
52-
kind="secondary"
53-
size="sm"
54-
Icon={SearchIcon}
55-
onClick={() => defaultDispatcher.fire(Action.OpenSpotlight)}
56-
>
57-
<Flex as="span" justify="space-between">
58-
<span className="mx_RoomListSearch_search_text">{_t("action|search")}</span>
59-
<kbd>{IS_MAC ? "⌘ K" : _t(ALTERNATE_KEY_NAME[Key.CONTROL]) + " K"}</kbd>
60-
</Flex>
61-
</Button>
62-
{displayDialButton && (
63-
<Button
64-
className="mx_RoomListSearch_button"
65-
kind="secondary"
66-
size="sm"
67-
Icon={DialPadIcon}
68-
iconOnly={true}
69-
aria-label={_t("left_panel|open_dial_pad")}
70-
onClick={(ev) => {
71-
defaultDispatcher.fire(Action.OpenDialPad);
72-
}}
73-
/>
74-
)}
75-
{displayExploreButton && (
76-
<Button
77-
className="mx_RoomListSearch_button"
78-
kind="secondary"
79-
size="sm"
80-
Icon={ExploreIcon}
81-
iconOnly={true}
82-
aria-label={_t("action|explore_rooms")}
83-
onClick={(ev) => {
84-
defaultDispatcher.fire(Action.ViewRoomDirectory);
85-
PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev);
86-
}}
87-
/>
88-
)}
89-
</Flex>
90-
);
17+
export function RoomListSearch(): JSX.Element {
18+
const vm = useMemo(() => new RoomListSearchViewModel(), []);
19+
return <RoomListSearchView vm={vm} />;
9120
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
import type React from "react";
9+
import { ViewModelSubscriptions } from "../ViewModelSubscriptions";
10+
import SpaceStore from "../../stores/spaces/SpaceStore";
11+
import { MetaSpace, type SpaceKey, UPDATE_SELECTED_SPACE } from "../../stores/spaces";
12+
import {
13+
type RoomListSearchSnapshot,
14+
type RoomListSearchViewModel as RoomListSearchViewModelType,
15+
} from "../../shared-components/room-list/RoomListSearch";
16+
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
17+
import { UIComponent } from "../../settings/UIFeature";
18+
import defaultDispatcher from "../../dispatcher/dispatcher";
19+
import { Action } from "../../dispatcher/actions";
20+
import PosthogTrackers from "../../PosthogTrackers";
21+
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../LegacyCallHandler";
22+
23+
/**
24+
* ViewModel for the RoomListSearch component.
25+
*/
26+
export class RoomListSearchViewModel implements RoomListSearchViewModelType {
27+
private subs: ViewModelSubscriptions;
28+
29+
/**
30+
* The current snapshot of the RoomListSearch state.
31+
* It contains flags to determine whether to display the dial button and explore button.
32+
*/
33+
private snapshot = {
34+
displayDialButton: false,
35+
displayExploreButton: false,
36+
};
37+
38+
/**
39+
* Creates an instance of RoomListSearchViewModel.
40+
* It listens to SpaceStore and LegacyCallHandler events to update the snapshot.
41+
*/
42+
public constructor() {
43+
this.subs = new ViewModelSubscriptions(this.updateSubscription);
44+
}
45+
46+
private updateSubscription = (): void => {
47+
// Put the listener on the first time the subscription is called
48+
console.log("this.listeners.size", this.subs.listeners.size);
49+
if (this.subs.listeners.size > 0 && this.subs.listeners.size < 2) {
50+
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateDisplayExploreButton);
51+
LegacyCallHandler.instance.on(LegacyCallHandlerEvent.ProtocolSupport, this.updateSupportPstn);
52+
53+
this.updateDisplayExploreButton(SpaceStore.instance.activeSpace);
54+
this.updateSupportPstn();
55+
} else {
56+
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateDisplayExploreButton);
57+
LegacyCallHandler.instance.off(LegacyCallHandlerEvent.ProtocolSupport, this.updateSupportPstn);
58+
}
59+
};
60+
61+
/**
62+
* Update the displayExploreButton flag based on the active space.
63+
*/
64+
private updateDisplayExploreButton = (activeSpace: SpaceKey): void => {
65+
this.snapshot.displayExploreButton =
66+
activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms);
67+
this.subs.emit();
68+
};
69+
70+
/**
71+
* Update the displayDialButton flag based on whether the PTSN protocol is supported.
72+
*/
73+
private updateSupportPstn = (): void => {
74+
this.snapshot.displayDialButton = LegacyCallHandler.instance.getSupportsPstnProtocol();
75+
this.subs.emit();
76+
};
77+
78+
public subscribe = (listener: () => void): (() => void) => {
79+
console.log("subscribing to RoomListSearchViewModel");
80+
return this.subs.subscribe(listener);
81+
};
82+
83+
public getSnapshot = (): RoomListSearchSnapshot => {
84+
return this.snapshot;
85+
};
86+
87+
/**
88+
* Open the dial pad when called.
89+
*/
90+
public onDialPadClick(): void {
91+
defaultDispatcher.fire(Action.OpenDialPad);
92+
}
93+
94+
/**
95+
* Open the room directory when called.
96+
*/
97+
public onExploreClick(evt: React.MouseEvent<HTMLButtonElement>): void {
98+
defaultDispatcher.fire(Action.ViewRoomDirectory);
99+
PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", evt);
100+
}
101+
102+
/**
103+
* Open the spotlight when called.
104+
*/
105+
public onSearchClick(): void {
106+
defaultDispatcher.fire(Action.OpenSpotlight);
107+
}
108+
}

0 commit comments

Comments
 (0)