diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index 84340d8219..1a361e7b55 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -28,6 +28,7 @@ import SettingsStore from "../settings/SettingsStore";
import {ActiveRoomObserver} from "../ActiveRoomObserver";
import {Notifier} from "../Notifier";
import type {Renderer} from "react-dom";
+import RightPanelStore from "../stores/RightPanelStore";
declare global {
interface Window {
@@ -49,6 +50,7 @@ declare global {
singletonModalManager: ModalManager;
mxSettingsStore: SettingsStore;
mxNotifier: typeof Notifier;
+ mxRightPanelStore: RightPanelStore;
}
interface Document {
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index 24fee80c2a..11416b29fb 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -21,6 +21,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
+import {Room} from "matrix-js-sdk/src/models/room";
+
import * as sdk from '../../index';
import dis from '../../dispatcher/dispatcher';
import RateLimitedFunc from '../../ratelimitedfunc';
@@ -34,7 +36,7 @@ import {Action} from "../../dispatcher/actions";
export default class RightPanel extends React.Component {
static get propTypes() {
return {
- roomId: PropTypes.string, // if showing panels for a given room, this is set
+ room: PropTypes.instanceOf(Room), // if showing panels for a given room, this is set
groupId: PropTypes.string, // if showing panels for a given group, this is set
user: PropTypes.object, // used if we know the user ahead of opening the panel
};
@@ -161,13 +163,13 @@ export default class RightPanel extends React.Component {
}
onRoomStateMember(ev, state, member) {
- if (member.roomId !== this.props.roomId) {
+ if (member.roomId !== this.props.room.roomId) {
return;
}
// redraw the badge on the membership list
- if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.roomId) {
+ if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) {
this._delayedUpdate();
- } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.roomId &&
+ } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId &&
member.userId === this.state.member.userId) {
// refresh the member info (e.g. new power level)
this._delayedUpdate();
@@ -226,8 +228,8 @@ export default class RightPanel extends React.Component {
switch (this.state.phase) {
case RightPanelPhases.RoomMemberList:
- if (this.props.roomId) {
- panel = ;
+ if (this.props.room.roomId) {
+ panel = ;
}
break;
case RightPanelPhases.GroupMemberList:
@@ -242,8 +244,8 @@ export default class RightPanel extends React.Component {
case RightPanelPhases.EncryptionPanel:
panel = ;
break;
case RightPanelPhases.Room3pidMemberInfo:
- panel = ;
+ panel = ;
break;
case RightPanelPhases.GroupMemberInfo:
panel = ;
break;
case RightPanelPhases.FilePanel:
- panel = ;
+ panel = ;
break;
}
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index e1a075f770..ed2e5645e9 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -2062,7 +2062,7 @@ export default class RoomView extends React.Component {
const showRightPanel = !forceHideRightPanel && this.state.room && this.state.showRightPanel;
const rightPanel = showRightPanel
- ?
+ ?
: null;
const timelineClasses = classNames("mx_RoomView_timeline", {
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js
index ef21b5d787..4e3e00f221 100644
--- a/src/components/structures/ScrollPanel.js
+++ b/src/components/structures/ScrollPanel.js
@@ -94,7 +94,7 @@ export default class ScrollPanel extends React.Component {
/* startAtBottom: if set to true, the view is assumed to start
* scrolled to the bottom.
- * XXX: It's likley this is unecessary and can be derived from
+ * XXX: It's likely this is unnecessary and can be derived from
* stickyBottom, but I'm adding an extra parameter to ensure
* behaviour stays the same for other uses of ScrollPanel.
* If so, let's remove this parameter down the line.
@@ -138,6 +138,7 @@ export default class ScrollPanel extends React.Component {
/* style: styles to add to the top-level div
*/
style: PropTypes.object,
+
/* resizeNotifier: ResizeNotifier to know when middle column has changed size
*/
resizeNotifier: PropTypes.object,
diff --git a/src/components/views/avatars/MemberAvatar.tsx b/src/components/views/avatars/MemberAvatar.tsx
index 1d23d85b0f..8fd51d3715 100644
--- a/src/components/views/avatars/MemberAvatar.tsx
+++ b/src/components/views/avatars/MemberAvatar.tsx
@@ -16,23 +16,24 @@ limitations under the License.
*/
import React from 'react';
+import {RoomMember} from "matrix-js-sdk/src/models/room-member";
+
import dis from "../../../dispatcher/dispatcher";
import {Action} from "../../../dispatcher/actions";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import BaseAvatar from "./BaseAvatar";
interface IProps {
- // TODO: replace with correct type
- member: any;
- fallbackUserId: string;
+ member: RoomMember;
+ fallbackUserId?: string;
width: number;
height: number;
- resizeMethod: string;
+ resizeMethod?: string;
// The onClick to give the avatar
- onClick: React.MouseEventHandler;
+ onClick?: React.MouseEventHandler;
// Whether the onClick of the avatar should be overriden to dispatch `Action.ViewUser`
- viewUserOnClick: boolean;
- title: string;
+ viewUserOnClick?: boolean;
+ title?: string;
}
interface IState {
diff --git a/src/components/views/right_panel/GroupHeaderButtons.tsx b/src/components/views/right_panel/GroupHeaderButtons.tsx
index 44237e401f..dd4a82e645 100644
--- a/src/components/views/right_panel/GroupHeaderButtons.tsx
+++ b/src/components/views/right_panel/GroupHeaderButtons.tsx
@@ -41,13 +41,9 @@ interface IProps {}
export default class GroupHeaderButtons extends HeaderButtons {
constructor(props: IProps) {
super(props, HeaderKind.Group);
- this.onMembersClicked = this.onMembersClicked.bind(this);
- this.onRoomsClicked = this.onRoomsClicked.bind(this);
}
protected onAction(payload: ActionPayload) {
- super.onAction(payload);
-
if (payload.action === Action.ViewUser) {
if ((payload as ViewUserPayload).member) {
this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member});
@@ -70,7 +66,7 @@ export default class GroupHeaderButtons extends HeaderButtons {
}
}
- private onMembersClicked() {
+ private onMembersClicked = () => {
if (this.state.phase === RightPanelPhases.GroupMemberInfo) {
// send the active phase to trigger a toggle
this.setPhase(RightPanelPhases.GroupMemberInfo);
@@ -78,12 +74,12 @@ export default class GroupHeaderButtons extends HeaderButtons {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupMemberList);
}
- }
+ };
- private onRoomsClicked() {
+ private onRoomsClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupRoomList);
- }
+ };
renderButtons() {
return [
diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx
index bbb783ccb9..e922959bbb 100644
--- a/src/components/views/right_panel/HeaderButtons.tsx
+++ b/src/components/views/right_panel/HeaderButtons.tsx
@@ -65,9 +65,7 @@ export default abstract class HeaderButtons extends React.Component) {
dis.dispatch({
diff --git a/src/components/views/right_panel/RoomHeaderButtons.tsx b/src/components/views/right_panel/RoomHeaderButtons.tsx
index 7ac547f499..7d732b8ae3 100644
--- a/src/components/views/right_panel/RoomHeaderButtons.tsx
+++ b/src/components/views/right_panel/RoomHeaderButtons.tsx
@@ -36,13 +36,9 @@ const MEMBER_PHASES = [
export default class RoomHeaderButtons extends HeaderButtons {
constructor(props) {
super(props, HeaderKind.Room);
- this.onMembersClicked = this.onMembersClicked.bind(this);
- this.onFilesClicked = this.onFilesClicked.bind(this);
- this.onNotificationsClicked = this.onNotificationsClicked.bind(this);
}
protected onAction(payload: ActionPayload) {
- super.onAction(payload);
if (payload.action === Action.ViewUser) {
if (payload.member) {
this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member});
@@ -58,7 +54,7 @@ export default class RoomHeaderButtons extends HeaderButtons {
}
}
- private onMembersClicked() {
+ private onMembersClicked = () => {
if (this.state.phase === RightPanelPhases.RoomMemberInfo) {
// send the active phase to trigger a toggle
// XXX: we should pass refireParams here but then it won't collapse as we desire it to
@@ -67,17 +63,17 @@ export default class RoomHeaderButtons extends HeaderButtons {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.RoomMemberList);
}
- }
+ };
- private onFilesClicked() {
+ private onFilesClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.FilePanel);
- }
+ };
- private onNotificationsClicked() {
+ private onNotificationsClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.NotificationPanel);
- }
+ };
public renderButtons() {
return [
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index 71ee86a1ea..518bb133ce 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -45,6 +45,7 @@ import EncryptionPanel from "./EncryptionPanel";
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
import { verifyUser, legacyVerifyUser, verifyDevice } from '../../../verification';
import {Action} from "../../../dispatcher/actions";
+import {useIsEncrypted} from "../../../hooks/useIsEncrypted";
const _disambiguateDevices = (devices) => {
const names = Object.create(null);
@@ -124,18 +125,6 @@ async function openDMForUser(matrixClient, userId) {
createRoom(createRoomOptions);
}
-function useIsEncrypted(cli, room) {
- const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
-
- const update = useCallback((event) => {
- if (event.getType() === "m.room.encryption") {
- setIsEncrypted(cli.isRoomEncrypted(room.roomId));
- }
- }, [cli, room]);
- useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
- return isEncrypted;
-}
-
function useHasCrossSigningKeys(cli, member, canVerify, setUpdating) {
return useAsyncMemo(async () => {
if (!canVerify) {
@@ -1485,7 +1474,7 @@ const UserInfoHeader = ({onClose, member, e2eStatus}) => {
const UserInfo = ({user, groupId, roomId, onClose, phase=RightPanelPhases.RoomMemberInfo, ...props}) => {
const cli = useContext(MatrixClientContext);
- // Load room if we are given a room id and memoize it
+ // Load room if we are given a room id and memoize it - this can be undefined for User Info/Group Member Info
const room = useMemo(() => roomId ? cli.getRoom(roomId) : null, [cli, roomId]);
// fetch latest room member if we have a room, so we don't show historical information, falling back to user
const member = useMemo(() => room ? (room.getMember(user.userId) || user) : user, [room, user]);
diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts
new file mode 100644
index 0000000000..79f3e539cd
--- /dev/null
+++ b/src/hooks/useIsEncrypted.ts
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import {useCallback, useState} from "react";
+import {MatrixClient} from "matrix-js-sdk/src/client";
+import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import {useEventEmitter} from "./useEventEmitter";
+
+// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined
+export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
+ const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
+
+ const update = useCallback((event: MatrixEvent) => {
+ if (room && event.getType() === "m.room.encryption") {
+ setIsEncrypted(cli.isRoomEncrypted(room.roomId));
+ }
+ }, [cli, room]);
+ useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
+
+ return isEncrypted;
+}
diff --git a/src/stores/RightPanelStore.ts b/src/stores/RightPanelStore.ts
index c1799978ad..34445d007b 100644
--- a/src/stores/RightPanelStore.ts
+++ b/src/stores/RightPanelStore.ts
@@ -223,3 +223,5 @@ export default class RightPanelStore extends Store {
return RightPanelStore.instance;
}
}
+
+window.mxRightPanelStore = RightPanelStore.getSharedInstance();