diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index 4cff508dfb..e9a05880f6 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -20,7 +20,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "../../MatrixClientPeg"; import Modal from "../../Modal"; import { _t } from "../../languageHandler"; import ErrorDialog from "../views/dialogs/ErrorDialog"; @@ -30,6 +29,7 @@ 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 MatrixClientContext from "../../contexts/MatrixClientContext"; interface IProps { userId: string; @@ -42,6 +42,9 @@ interface IState { } export default class UserView extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + public constructor(props: IProps) { super(props); this.state = { @@ -65,11 +68,10 @@ export default class UserView extends React.Component { } private async loadProfileInfo(): Promise { - const cli = MatrixClientPeg.get(); this.setState({ loading: true }); let profileInfo: Awaited>; try { - profileInfo = await cli.getProfileInfo(this.props.userId); + profileInfo = await this.context.getProfileInfo(this.props.userId); } catch (err) { Modal.createDialog(ErrorDialog, { title: _t("Could not load user profile"), diff --git a/src/components/views/messages/EditHistoryMessage.tsx b/src/components/views/messages/EditHistoryMessage.tsx index 0b1d830fdf..6c06321e69 100644 --- a/src/components/views/messages/EditHistoryMessage.tsx +++ b/src/components/views/messages/EditHistoryMessage.tsx @@ -25,13 +25,13 @@ import { formatTime } from "../../../DateUtils"; import { pillifyLinks, unmountPills } from "../../../utils/pillify"; import { tooltipifyLinks, unmountTooltips } from "../../../utils/tooltipify"; import { _t } from "../../../languageHandler"; -import { MatrixClientPeg } from "../../../MatrixClientPeg"; import Modal from "../../../Modal"; import RedactedBody from "./RedactedBody"; import AccessibleButton from "../elements/AccessibleButton"; import ConfirmAndWaitRedactDialog from "../dialogs/ConfirmAndWaitRedactDialog"; import ViewSource from "../../structures/ViewSource"; import SettingsStore from "../../../settings/SettingsStore"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; function getReplacedContent(event: MatrixEvent): IContent { const originalContent = event.getOriginalContent(); @@ -52,14 +52,18 @@ interface IState { } export default class EditHistoryMessage extends React.PureComponent { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + private content = createRef(); private pills: Element[] = []; private tooltips: Element[] = []; - public constructor(props: IProps) { + public constructor(props: IProps, context: React.ContextType) { super(props); + this.context = context; - const cli = MatrixClientPeg.get(); + const cli = this.context; const userId = cli.getSafeUserId(); const event = this.props.mxEvent; const room = cli.getRoom(event.getRoomId()); @@ -74,7 +78,7 @@ export default class EditHistoryMessage extends React.PureComponent => { const event = this.props.mxEvent; - const cli = MatrixClientPeg.get(); + const cli = this.context; Modal.createDialog( ConfirmAndWaitRedactDialog, @@ -102,7 +106,7 @@ export default class EditHistoryMessage extends React.PureComponent = (props: IProps) => { + const cli = useMatrixClientContext(); const { verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted } = props; const [request, setRequest] = useState(verificationRequest); // state to show a spinner immediately after clicking "start verification", @@ -106,7 +107,6 @@ const EncryptionPanel: React.FC = (props: IProps) => { const onStartVerification = useCallback(async (): Promise => { setRequesting(true); - const cli = MatrixClientPeg.get(); let verificationRequest_: VerificationRequest; try { const roomId = await ensureDMExists(cli, member.userId); @@ -135,14 +135,12 @@ const EncryptionPanel: React.FC = (props: IProps) => { }); } if (!RightPanelStore.instance.isOpen) RightPanelStore.instance.togglePanel(null); - }, [member]); + }, [cli, member]); const requested: boolean = (!request && isRequesting) || (!!request && (phase === PHASE_REQUESTED || phase === PHASE_UNSENT || phase === undefined)); - const isSelfVerification = request - ? request.isSelfVerification - : member.userId === MatrixClientPeg.get().getUserId(); + const isSelfVerification = request ? request.isSelfVerification : member.userId === cli.getUserId(); if (!request || requested) { const initiatedByMe = (!request && isRequesting) || (!!request && request.initiatedByMe); diff --git a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx index 04b75cb4cc..fc04d53470 100644 --- a/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/BridgeSettingsTab.tsx @@ -17,12 +17,13 @@ limitations under the License. import React, { ReactNode } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import BridgeTile from "../../BridgeTile"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; +import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; const BRIDGE_EVENT_TYPES = [ "uk.half-shot.bridge", @@ -36,14 +37,16 @@ interface IProps { } export default class BridgeSettingsTab extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + private renderBridgeCard(event: MatrixEvent, room: Room | null): ReactNode { const content = event.getContent(); if (!room || !content?.channel || !content.protocol) return null; return ; } - public static getBridgeStateEvents(roomId: string): MatrixEvent[] { - const client = MatrixClientPeg.get(); + public static getBridgeStateEvents(client: MatrixClient, roomId: string): MatrixEvent[] { const roomState = client.getRoom(roomId)?.currentState; if (!roomState) return []; @@ -53,7 +56,7 @@ export default class BridgeSettingsTab extends React.Component { public render(): React.ReactNode { // This settings tab will only be invoked if the following function returns more // than 0 events, so no validation is needed at this stage. - const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.props.room.roomId); + const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.context, this.props.room.roomId); const room = this.props.room; let content: JSX.Element; diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx index 627971eaf3..1ba3a2f17c 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.tsx @@ -18,7 +18,6 @@ import React, { createRef } from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../../../languageHandler"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton"; import Notifier from "../../../../../Notifier"; import SettingsStore from "../../../../../settings/SettingsStore"; @@ -116,7 +115,7 @@ export default class NotificationsSettingsTab extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + private onUnbanClick = (): void => { - MatrixClientPeg.get() - .unban(this.props.member.roomId, this.props.member.userId) - .catch((err) => { - logger.error("Failed to unban: " + err); - Modal.createDialog(ErrorDialog, { - title: _t("Error"), - description: _t("Failed to unban"), - }); + this.context.unban(this.props.member.roomId, this.props.member.userId).catch((err) => { + logger.error("Failed to unban: " + err); + Modal.createDialog(ErrorDialog, { + title: _t("Error"), + description: _t("Failed to unban"), }); + }); }; public render(): React.ReactNode { @@ -136,12 +137,15 @@ interface IProps { } export default class RolesRoomSettingsTab extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + public componentDidMount(): void { - MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); + this.context.on(RoomStateEvent.Update, this.onRoomStateUpdate); } public componentWillUnmount(): void { - const client = MatrixClientPeg.get(); + const client = this.context; if (client) { client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate); } @@ -173,7 +177,7 @@ export default class RolesRoomSettingsTab extends React.Component { } private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => { - const client = MatrixClientPeg.get(); + const client = this.context; const room = this.props.room; const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); let plContent = plEvent?.getContent() ?? {}; @@ -215,7 +219,7 @@ export default class RolesRoomSettingsTab extends React.Component { }; private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => { - const client = MatrixClientPeg.get(); + const client = this.context; const room = this.props.room; const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); let plContent = plEvent?.getContent() ?? {}; @@ -241,7 +245,7 @@ export default class RolesRoomSettingsTab extends React.Component { }; public render(): React.ReactNode { - const client = MatrixClientPeg.get(); + const client = this.context; const room = this.props.room; const isSpaceRoom = room.isSpaceRoom(); diff --git a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx index 94f89be331..71c0d21184 100644 --- a/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/VoipRoomSettingsTab.tsx @@ -21,7 +21,6 @@ import { RoomState } from "matrix-js-sdk/src/models/room-state"; import { Room } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../../../languageHandler"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import SettingsSubsection from "../../shared/SettingsSubsection"; import SettingsTab from "../SettingsTab"; @@ -38,14 +37,17 @@ const ElementCallSwitch: React.FC = ({ room }) => { const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]); const [content, events, maySend] = useRoomState( room, - useCallback((state: RoomState) => { - const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent(); - return [ - content ?? {}, - content?.["events"] ?? {}, - state?.maySendStateEvent(EventType.RoomPowerLevels, MatrixClientPeg.get().getSafeUserId()), - ]; - }, []), + useCallback( + (state: RoomState) => { + const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent(); + return [ + content ?? {}, + content?.["events"] ?? {}, + state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()), + ]; + }, + [room.client], + ), ); const [elementCallEnabled, setElementCallEnabled] = useState(() => { @@ -69,12 +71,12 @@ const ElementCallSwitch: React.FC = ({ room }) => { events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel; } - MatrixClientPeg.get().sendStateEvent(room.roomId, EventType.RoomPowerLevels, { + room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, { events: events, ...content, }); }, - [room.roomId, content, events, isPublic], + [room.client, room.roomId, content, events, isPublic], ); const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand; diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 135c0c4a65..29ad966a40 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -19,7 +19,6 @@ import React, { ChangeEvent, ReactNode } from "react"; import { _t } from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import SettingsStore from "../../../../../settings/SettingsStore"; import SettingsFlag from "../../../elements/SettingsFlag"; import Field from "../../../elements/Field"; @@ -34,6 +33,7 @@ import ImageSizePanel from "../../ImageSizePanel"; import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; +import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; interface IProps {} @@ -49,6 +49,9 @@ interface IState { } export default class AppearanceUserSettingsTab extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); private unmounted = false; @@ -66,7 +69,7 @@ export default class AppearanceUserSettingsTab extends React.Component { // Fetch the current user profile for the message preview - const client = MatrixClientPeg.get(); + const client = this.context; const userId = client.getUserId()!; const profileInfo = await client.getProfileInfo(userId); if (this.unmounted) return; diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx index 13a44fcaa6..c6c3bb9287 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx @@ -33,7 +33,6 @@ import SpellCheckSettings from "../../SpellCheckSettings"; import AccessibleButton from "../../../elements/AccessibleButton"; import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog"; import PlatformPeg from "../../../../../PlatformPeg"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import Modal from "../../../../../Modal"; import dis from "../../../../../dispatcher/dispatcher"; import { Service, ServicePolicyPair, startTermsFlow } from "../../../../../Terms"; @@ -102,14 +101,15 @@ export default class GeneralUserSettingsTab extends React.Component) { super(props); + this.context = context; this.state = { language: languageHandler.getCurrentLanguage(), spellCheckEnabled: false, spellCheckLanguages: [], - haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), + haveIdServer: Boolean(this.context.getIdentityServerUrl()), idServerHasUnsignedTerms: false, requiredPolicyInfo: { // This object is passed along to a component for handling @@ -151,7 +151,7 @@ export default class GeneralUserSettingsTab extends React.Component { if (payload.action === "id_server_changed") { - this.setState({ haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()) }); + this.setState({ haveIdServer: Boolean(this.context.getIdentityServerUrl()) }); this.getThreepidState(); } }; @@ -165,7 +165,7 @@ export default class GeneralUserSettingsTab extends React.Component { - const cli = MatrixClientPeg.get(); + const cli = this.context; const serverSupportsSeparateAddAndBind = await cli.doesServerSupportSeparateAddAndBind(); @@ -184,7 +184,7 @@ export default class GeneralUserSettingsTab extends React.Component { - const cli = MatrixClientPeg.get(); + const cli = this.context; // Check to see if terms need accepting this.checkTerms(); @@ -195,7 +195,7 @@ export default class GeneralUserSettingsTab extends React.Component { // By starting the terms flow we get the logic for checking which terms the user has signed // for free. So we might as well use that for our own purposes. - const idServerUrl = MatrixClientPeg.get().getIdentityServerUrl(); + const idServerUrl = this.context.getIdentityServerUrl(); if (!this.state.haveIdServer || !idServerUrl) { this.setState({ idServerHasUnsignedTerms: false }); return; diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 34da828863..7f690ce53e 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -19,7 +19,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import AccessibleButton from "../../../elements/AccessibleButton"; import { _t, getCurrentLanguage } from "../../../../../languageHandler"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import SdkConfig from "../../../../../SdkConfig"; import createRoom from "../../../../../createRoom"; import Modal from "../../../../../Modal"; @@ -77,7 +76,7 @@ export default class HelpUserSettingsTab extends React.Component private getVersionInfo(): { appVersion: string; olmVersion: string } { const brand = SdkConfig.get().brand; const appVersion = this.state.appVersion || "unknown"; - const olmVersionTuple = MatrixClientPeg.get().olmVersion; + const olmVersionTuple = this.context.olmVersion; const olmVersion = olmVersionTuple ? `${olmVersionTuple[0]}.${olmVersionTuple[1]}.${olmVersionTuple[2]}` : ""; @@ -94,12 +93,10 @@ export default class HelpUserSettingsTab extends React.Component // Dev note: please keep this log line, it's useful when troubleshooting a MatrixClient suddenly // stopping in the middle of the logs. logger.log("Clear cache & reload clicked"); - MatrixClientPeg.get().stopClient(); - MatrixClientPeg.get() - .store.deleteAllData() - .then(() => { - PlatformPeg.get()?.reload(); - }); + this.context.stopClient(); + this.context.store.deleteAllData().then(() => { + PlatformPeg.get()?.reload(); + }); }; private onBugReport = (): void => { @@ -362,19 +359,19 @@ export default class HelpUserSettingsTab extends React.Component {_t( "Homeserver is %(homeserverUrl)s", { - homeserverUrl: MatrixClientPeg.get().getHomeserverUrl(), + homeserverUrl: this.context.getHomeserverUrl(), }, { code: (sub) => {sub}, }, )} - {MatrixClientPeg.get().getIdentityServerUrl() && ( + {this.context.getIdentityServerUrl() && ( {_t( "Identity server is %(identityServerUrl)s", { - identityServerUrl: MatrixClientPeg.get().getIdentityServerUrl(), + identityServerUrl: this.context.getIdentityServerUrl(), }, { code: (sub) => {sub}, @@ -391,8 +388,8 @@ export default class HelpUserSettingsTab extends React.Component " Do not share it with anyone.", )} - MatrixClientPeg.get().getAccessToken()}> - {MatrixClientPeg.get().getAccessToken()} + this.context.getAccessToken()}> + {this.context.getAccessToken()} diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index b9ff171c4c..bf8540516a 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -23,7 +23,6 @@ import { _t } from "../../../../../languageHandler"; import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler"; import Field from "../../../elements/Field"; import AccessibleButton from "../../../elements/AccessibleButton"; -import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import SettingsFlag from "../../../elements/SettingsFlag"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; @@ -31,6 +30,7 @@ import { requestMediaPermissions } from "../../../../../utils/media/requestMedia import SettingsTab from "../SettingsTab"; import { SettingsSection } from "../../shared/SettingsSection"; import SettingsSubsection from "../../shared/SettingsSubsection"; +import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; interface IState { mediaDevices: IMediaDevices | null; @@ -58,6 +58,9 @@ const mapDeviceKindToHandlerValue = (deviceKind: MediaDeviceKindEnum): string | }; export default class VoiceUserSettingsTab extends React.Component<{}, IState> { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + public constructor(props: {}) { super(props); @@ -114,11 +117,11 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { }; private changeWebRtcMethod = (p2p: boolean): void => { - MatrixClientPeg.get().setForceTURN(!p2p); + this.context.setForceTURN(!p2p); }; private changeFallbackICEServerAllowed = (allow: boolean): void => { - MatrixClientPeg.get().setFallbackICEServerAllowed(allow); + this.context.setFallbackICEServerAllowed(allow); }; private renderDeviceOptions(devices: Array, category: MediaDeviceKindEnum): Array { diff --git a/src/hooks/useIsInitialSyncComplete.ts b/src/hooks/useIsInitialSyncComplete.ts index 33174fa182..3f78e13e72 100644 --- a/src/hooks/useIsInitialSyncComplete.ts +++ b/src/hooks/useIsInitialSyncComplete.ts @@ -16,10 +16,10 @@ limitations under the License. import { ClientEvent } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "../MatrixClientPeg"; import { useEventEmitterState } from "./useEventEmitter"; +import { useMatrixClientContext } from "../contexts/MatrixClientContext"; export function useInitialSyncComplete(): boolean { - const cli = MatrixClientPeg.get(); + const cli = useMatrixClientContext(); return useEventEmitterState(cli, ClientEvent.Sync, () => cli.isInitialSyncComplete()); } diff --git a/src/hooks/useUserOnboardingContext.ts b/src/hooks/useUserOnboardingContext.ts index a3ea8ed319..1d622173f6 100644 --- a/src/hooks/useUserOnboardingContext.ts +++ b/src/hooks/useUserOnboardingContext.ts @@ -18,9 +18,9 @@ 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 { MatrixClientPeg } from "../MatrixClientPeg"; import { Notifier } from "../Notifier"; import DMRoomMap from "../utils/DMRoomMap"; +import { useMatrixClientContext } from "../contexts/MatrixClientContext"; export interface UserOnboardingContext { hasAvatar: boolean; @@ -47,7 +47,7 @@ function useRefOf(value: (...values: T) => R): (...values: T function useUserOnboardingContextValue(defaultValue: T, callback: (cli: MatrixClient) => Promise): T { const [value, setValue] = useState(defaultValue); - const cli = MatrixClientPeg.get(); + const cli = useMatrixClientContext(); const handler = useRefOf(callback); diff --git a/src/voice-broadcast/components/VoiceBroadcastBody.tsx b/src/voice-broadcast/components/VoiceBroadcastBody.tsx index 9b6ca990e0..5433154bdf 100644 --- a/src/voice-broadcast/components/VoiceBroadcastBody.tsx +++ b/src/voice-broadcast/components/VoiceBroadcastBody.tsx @@ -25,13 +25,13 @@ import { VoiceBroadcastInfoState, } from ".."; import { IBodyProps } from "../../components/views/messages/IBodyProps"; -import { MatrixClientPeg } from "../../MatrixClientPeg"; import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper"; import { SDKContext } from "../../contexts/SDKContext"; +import { useMatrixClientContext } from "../../contexts/MatrixClientContext"; export const VoiceBroadcastBody: React.FC = ({ mxEvent }) => { const sdkContext = useContext(SDKContext); - const client = MatrixClientPeg.get(); + const client = useMatrixClientContext(); const [infoState, setInfoState] = useState(mxEvent.getContent()?.state || VoiceBroadcastInfoState.Stopped); useEffect(() => { diff --git a/test/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx b/test/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx index bf41be073a..35a54e9761 100644 --- a/test/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx +++ b/test/components/views/settings/tabs/room/BridgeSettingsTab-test.tsx @@ -19,7 +19,7 @@ import { render } from "@testing-library/react"; import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import BridgeSettingsTab from "../../../../../../src/components/views/settings/tabs/room/BridgeSettingsTab"; -import { getMockClientWithEventEmitter } from "../../../../../test-utils"; +import { getMockClientWithEventEmitter, withClientContextRenderOptions } from "../../../../../test-utils"; describe("", () => { const userId = "@alice:server.org"; @@ -28,7 +28,8 @@ describe("", () => { }); const roomId = "!room:server.org"; - const getComponent = (room: Room) => render(); + const getComponent = (room: Room) => + render(, withClientContextRenderOptions(client)); it("renders when room is not bridging messages to any platform", () => { const room = new Room(roomId, client, userId); diff --git a/test/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx b/test/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx index 9ee9df774c..c9c82ab547 100644 --- a/test/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx +++ b/test/components/views/settings/tabs/room/RolesRoomSettingsTab-test.tsx @@ -24,7 +24,7 @@ import { mocked } from "jest-mock"; import { RoomMember } from "matrix-js-sdk/src/matrix"; import RolesRoomSettingsTab from "../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab"; -import { mkStubRoom, stubClient } from "../../../../../test-utils"; +import { mkStubRoom, withClientContextRenderOptions, stubClient } from "../../../../../test-utils"; import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg"; import { VoiceBroadcastInfoEventType } from "../../../../../../src/voice-broadcast"; import SettingsStore from "../../../../../../src/settings/SettingsStore"; @@ -37,7 +37,7 @@ describe("RolesRoomSettingsTab", () => { let room: Room; const renderTab = (propRoom: Room = room): RenderResult => { - return render(); + return render(, withClientContextRenderOptions(cli)); }; const getVoiceBroadcastsSelect = (): HTMLElement => { diff --git a/test/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx b/test/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx index 310279ef01..0596652cf6 100644 --- a/test/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx +++ b/test/components/views/settings/tabs/user/AppearanceUserSettingsTab-test.tsx @@ -16,9 +16,10 @@ limitations under the License. import { render } from "@testing-library/react"; import React from "react"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import AppearanceUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/AppearanceUserSettingsTab"; -import { stubClient } from "../../../../../test-utils"; +import { withClientContextRenderOptions, stubClient } from "../../../../../test-utils"; // Fake random strings to give a predictable snapshot jest.mock("matrix-js-sdk/src/randomstring", () => ({ @@ -26,12 +27,14 @@ jest.mock("matrix-js-sdk/src/randomstring", () => ({ })); describe("AppearanceUserSettingsTab", () => { + let client: MatrixClient; + beforeEach(() => { - stubClient(); + client = stubClient(); }); it("should render", () => { - const { asFragment } = render(); + const { asFragment } = render(, withClientContextRenderOptions(client)); expect(asFragment()).toMatchSnapshot(); }); }); diff --git a/test/components/views/user-onboarding/UserOnboardingPage-test.tsx b/test/components/views/user-onboarding/UserOnboardingPage-test.tsx index af94db6461..1bb24ed346 100644 --- a/test/components/views/user-onboarding/UserOnboardingPage-test.tsx +++ b/test/components/views/user-onboarding/UserOnboardingPage-test.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import { act, render, RenderResult } from "@testing-library/react"; -import { filterConsole, stubClient } from "../../../test-utils"; +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"; @@ -34,7 +34,7 @@ jest.mock("../../../../src/components/structures/HomePage", () => ({ describe("UserOnboardingPage", () => { const renderComponent = async (): Promise => { - const renderResult = render(); + const renderResult = render(, withClientContextRenderOptions(MatrixClientPeg.safeGet())); await act(async () => { jest.runAllTimers(); }); diff --git a/test/test-utils/wrappers.tsx b/test/test-utils/wrappers.tsx index cc9b6f3570..c138f13335 100644 --- a/test/test-utils/wrappers.tsx +++ b/test/test-utils/wrappers.tsx @@ -16,6 +16,7 @@ limitations under the License. import React, { ComponentType, Ref } from "react"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; +import { RenderOptions } from "@testing-library/react"; import { MatrixClientPeg as peg } from "../../src/MatrixClientPeg"; import MatrixClientContext from "../../src/contexts/MatrixClientContext"; @@ -57,3 +58,15 @@ export function wrapInSdkContext( } }; } + +/** + * Test helper to generate React testing library render options for wrapping with a MatrixClientContext.Provider + * @param client the MatrixClient instance to expose via the provider + */ +export function withClientContextRenderOptions(client: MatrixClient): RenderOptions { + return { + wrapper: ({ children }) => ( + {children} + ), + }; +} diff --git a/test/voice-broadcast/components/VoiceBroadcastBody-test.tsx b/test/voice-broadcast/components/VoiceBroadcastBody-test.tsx index 571d8a661e..70e5378894 100644 --- a/test/voice-broadcast/components/VoiceBroadcastBody-test.tsx +++ b/test/voice-broadcast/components/VoiceBroadcastBody-test.tsx @@ -28,7 +28,7 @@ import { VoiceBroadcastPlayback, VoiceBroadcastRecordingsStore, } from "../../../src/voice-broadcast"; -import { stubClient, wrapInSdkContext } from "../../test-utils"; +import { withClientContextRenderOptions, stubClient, wrapInSdkContext } from "../../test-utils"; import { mkVoiceBroadcastInfoStateEvent } from "../utils/test-utils"; import { MediaEventHelper } from "../../../src/utils/MediaEventHelper"; import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks"; @@ -66,6 +66,7 @@ describe("VoiceBroadcastBody", () => { onMessageAllowed={() => {}} permalinkCreator={new RoomPermalinkCreator(room)} />, + withClientContextRenderOptions(client), ); testRecording = SdkContextClass.instance.voiceBroadcastRecordingsStore.getByInfoEvent(infoEvent, client); };