From d5acfc6cf453915deed0bf6ac6bca2b5920d73f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Wed, 23 Jun 2021 17:27:53 +0200
Subject: [PATCH 01/11] Convert EntityTile to TS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 .../rooms/{EntityTile.js => EntityTile.tsx}   | 94 ++++++++++---------
 1 file changed, 49 insertions(+), 45 deletions(-)
 rename src/components/views/rooms/{EntityTile.js => EntityTile.tsx} (75%)

diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.tsx
similarity index 75%
rename from src/components/views/rooms/EntityTile.js
rename to src/components/views/rooms/EntityTile.tsx
index a92d87643c..53c5900fbf 100644
--- a/src/components/views/rooms/EntityTile.js
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -16,14 +16,19 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-import React from 'react';
-import PropTypes from 'prop-types';
-import * as sdk from '../../../index';
+import React, { createRef } from 'react';
 import AccessibleButton from '../elements/AccessibleButton';
-import { _t } from '../../../languageHandler';
+import { _td } from '../../../languageHandler';
 import classNames from "classnames";
 import E2EIcon from './E2EIcon';
-import {replaceableComponent} from "../../../utils/replaceableComponent";
+import { replaceableComponent } from "../../../utils/replaceableComponent";
+import BaseAvatar from '../avatars/BaseAvatar';
+import PresenceLabel from "./PresenceLabel";
+
+const PowerLabel: Record<string, string> = {
+    "admin": _td("Admin"),
+    "moderator": _td("Mod"),
+}
 
 const PRESENCE_CLASS = {
     "offline": "mx_EntityTile_offline",
@@ -31,14 +36,14 @@ const PRESENCE_CLASS = {
     "unavailable": "mx_EntityTile_unavailable",
 };
 
-function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
+function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean) {
     if (showPresence === false) {
         return 'mx_EntityTile_online_beenactive';
     }
 
     // offline is split into two categories depending on whether we have
     // a last_active_ago for them.
-    if (presenceState == 'offline') {
+    if (presenceState === 'offline') {
         if (lastActiveAgo) {
             return PRESENCE_CLASS['offline'] + '_beenactive';
         } else {
@@ -51,29 +56,34 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
     }
 }
 
-@replaceableComponent("views.rooms.EntityTile")
-class EntityTile extends React.Component {
-    static propTypes = {
-        name: PropTypes.string,
-        title: PropTypes.string,
-        avatarJsx: PropTypes.any, // <BaseAvatar />
-        className: PropTypes.string,
-        presenceState: PropTypes.string,
-        presenceLastActiveAgo: PropTypes.number,
-        presenceLastTs: PropTypes.number,
-        presenceCurrentlyActive: PropTypes.bool,
-        showInviteButton: PropTypes.bool,
-        shouldComponentUpdate: PropTypes.func,
-        onClick: PropTypes.func,
-        suppressOnHover: PropTypes.bool,
-        showPresence: PropTypes.bool,
-        subtextLabel: PropTypes.string,
-        e2eStatus: PropTypes.string,
-    };
+interface IProps {
+    name?: string,
+    title?: string,
+    avatarJsx?: JSX.Element, // <BaseAvatar />
+    className?: string,
+    presenceState?: string,
+    presenceLastActiveAgo?: number,
+    presenceLastTs?: number,
+    presenceCurrentlyActive?: boolean,
+    showInviteButton?: boolean,
+    shouldComponentUpdate?(nextProps: IProps, nextState: IState): boolean,
+    onClick?(): void,
+    suppressOnHover?: boolean,
+    showPresence?: boolean,
+    subtextLabel?: string,
+    e2eStatus?: string,
+    powerStatus?: string,
+}
 
+interface IState {
+    hover: boolean;
+}
+
+@replaceableComponent("views.rooms.EntityTile")
+export default class EntityTile extends React.Component<IProps, IState> {
     static defaultProps = {
-        shouldComponentUpdate: function(nextProps, nextState) { return true; },
-        onClick: function() {},
+        shouldComponentUpdate: (nextProps: IProps, nextState: IState) => { return true; },
+        onClick: () => {},
         presenceState: "offline",
         presenceLastActiveAgo: 0,
         presenceLastTs: 0,
@@ -81,12 +91,17 @@ class EntityTile extends React.Component {
         suppressOnHover: false,
         showPresence: true,
     };
+    private container = createRef<HTMLDivElement>();
 
-    state = {
-        hover: false,
-    };
+    constructor(props: IProps) {
+        super(props);
 
-    shouldComponentUpdate(nextProps, nextState) {
+        this.state = {
+            hover: false,
+        };
+    }
+
+    shouldComponentUpdate(nextProps: IProps, nextState: IState) {
         if (this.state.hover !== nextState.hover) return true;
         return this.props.shouldComponentUpdate(nextProps, nextState);
     }
@@ -110,7 +125,6 @@ class EntityTile extends React.Component {
             const activeAgo = this.props.presenceLastActiveAgo ?
                 (Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1;
 
-            const PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
             let presenceLabel = null;
             if (this.props.showPresence) {
                 presenceLabel = <PresenceLabel activeAgo={activeAgo}
@@ -155,10 +169,7 @@ class EntityTile extends React.Component {
         let powerLabel;
         const powerStatus = this.props.powerStatus;
         if (powerStatus) {
-            const powerText = {
-                [EntityTile.POWER_STATUS_MODERATOR]: _t("Mod"),
-                [EntityTile.POWER_STATUS_ADMIN]: _t("Admin"),
-            }[powerStatus];
+            const powerText = PowerLabel[powerStatus];
             powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
         }
 
@@ -168,14 +179,12 @@ class EntityTile extends React.Component {
             e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
         }
 
-        const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
-
         const av = this.props.avatarJsx ||
             <BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />;
 
         // The wrapping div is required to make the magic mouse listener work, for some reason.
         return (
-            <div ref={(c) => this.container = c} >
+            <div ref={this.container} >
                 <AccessibleButton
                     className={classNames(mainClassNames)}
                     title={this.props.title}
@@ -193,8 +202,3 @@ class EntityTile extends React.Component {
         );
     }
 }
-
-EntityTile.POWER_STATUS_MODERATOR = "moderator";
-EntityTile.POWER_STATUS_ADMIN = "admin";
-
-export default EntityTile;

From 87d27593de06f92f9dc39cbe818dc71f25778cbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Wed, 23 Jun 2021 17:28:02 +0200
Subject: [PATCH 02/11] Convert MemberTile to TS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 .../rooms/{MemberTile.js => MemberTile.tsx}   | 68 +++++++++++--------
 1 file changed, 40 insertions(+), 28 deletions(-)
 rename src/components/views/rooms/{MemberTile.js => MemberTile.tsx} (79%)

diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.tsx
similarity index 79%
rename from src/components/views/rooms/MemberTile.js
rename to src/components/views/rooms/MemberTile.tsx
index f8df7ed78f..e0ee0e5daf 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.tsx
@@ -17,20 +17,32 @@ limitations under the License.
 
 import SettingsStore from "../../../settings/SettingsStore";
 import React from 'react';
-import PropTypes from 'prop-types';
 import * as sdk from "../../../index";
 import dis from "../../../dispatcher/dispatcher";
 import { _t } from '../../../languageHandler';
 import { MatrixClientPeg } from "../../../MatrixClientPeg";
 import {Action} from "../../../dispatcher/actions";
-import {replaceableComponent} from "../../../utils/replaceableComponent";
+import { replaceableComponent } from "../../../utils/replaceableComponent";
+import { RoomMember } from "matrix-js-sdk/src/models/room-member";
+import { MatrixEvent } from "matrix-js-sdk/src/models/event";
+import { EventType } from "matrix-js-sdk/src/@types/event";
+import { DeviceInfo } from "matrix-js-sdk/src/crypto";
+
+interface IProps {
+    member: RoomMember,
+    showPresence?: boolean,
+}
+
+interface IState {
+    statusMessage: string,
+    isRoomEncrypted: boolean,
+    e2eStatus: string,
+}
 
 @replaceableComponent("views.rooms.MemberTile")
-export default class MemberTile extends React.Component {
-    static propTypes = {
-        member: PropTypes.any.isRequired, // RoomMember
-        showPresence: PropTypes.bool,
-    };
+export default class MemberTile extends React.Component<IProps, IState> {
+    private userLastModifiedTime: number;
+    private memberLastModifiedTime: number;
 
     static defaultProps = {
         showPresence: true,
@@ -52,7 +64,7 @@ export default class MemberTile extends React.Component {
         if (SettingsStore.getValue("feature_custom_status")) {
             const { user } = this.props.member;
             if (user) {
-                user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
+                user.on("User._unstable_statusMessage", this.onStatusMessageCommitted);
             }
         }
 
@@ -80,7 +92,7 @@ export default class MemberTile extends React.Component {
         if (user) {
             user.removeListener(
                 "User._unstable_statusMessage",
-                this._onStatusMessageCommitted,
+                this.onStatusMessageCommitted,
             );
         }
 
@@ -91,8 +103,8 @@ export default class MemberTile extends React.Component {
         }
     }
 
-    onRoomStateEvents = ev => {
-        if (ev.getType() !== "m.room.encryption") return;
+    private onRoomStateEvents = (ev: MatrixEvent): void => {
+        if (ev.getType() !== EventType.RoomEncryption) return;
         const { roomId } = this.props.member;
         if (ev.getRoomId() !== roomId) return;
 
@@ -105,17 +117,17 @@ export default class MemberTile extends React.Component {
         this.updateE2EStatus();
     };
 
-    onUserTrustStatusChanged = (userId, trustStatus) => {
+    private onUserTrustStatusChanged = (userId: string, trustStatus: string): void => {
         if (userId !== this.props.member.userId) return;
         this.updateE2EStatus();
     };
 
-    onDeviceVerificationChanged = (userId, deviceId, deviceInfo) => {
+    private onDeviceVerificationChanged = (userId: string, deviceId: string, deviceInfo: DeviceInfo): void => {
         if (userId !== this.props.member.userId) return;
         this.updateE2EStatus();
     };
 
-    async updateE2EStatus() {
+    private async updateE2EStatus(): Promise<void> {
         const cli = MatrixClientPeg.get();
         const { userId } = this.props.member;
         const isMe = userId === cli.getUserId();
@@ -143,32 +155,32 @@ export default class MemberTile extends React.Component {
         });
     }
 
-    getStatusMessage() {
+    private getStatusMessage(): string {
         const { user } = this.props.member;
         if (!user) {
             return "";
         }
-        return user._unstable_statusMessage;
+        return user.unstable_statusMessage;
     }
 
-    _onStatusMessageCommitted = () => {
+    private onStatusMessageCommitted = (): void => {
         // The `User` object has observed a status message change.
         this.setState({
             statusMessage: this.getStatusMessage(),
         });
     };
 
-    shouldComponentUpdate(nextProps, nextState) {
+    shouldComponentUpdate(nextProps: IProps, nextState: IState): boolean {
         if (
-            this.member_last_modified_time === undefined ||
-            this.member_last_modified_time < nextProps.member.getLastModifiedTime()
+            this.memberLastModifiedTime === undefined ||
+            this.memberLastModifiedTime < nextProps.member.getLastModifiedTime()
         ) {
             return true;
         }
         if (
             nextProps.member.user &&
-            (this.user_last_modified_time === undefined ||
-            this.user_last_modified_time < nextProps.member.user.getLastModifiedTime())
+            (this.userLastModifiedTime === undefined ||
+            this.userLastModifiedTime < nextProps.member.user.getLastModifiedTime())
         ) {
             return true;
         }
@@ -181,18 +193,18 @@ export default class MemberTile extends React.Component {
         return false;
     }
 
-    onClick = e => {
+    private onClick = (e: MouseEvent): void => {
         dis.dispatch({
             action: Action.ViewUser,
             member: this.props.member,
         });
     };
 
-    _getDisplayName() {
+    private getDisplayName(): string {
         return this.props.member.name;
     }
 
-    getPowerLabel() {
+    private getPowerLabel(): string {
         return _t("%(userName)s (power %(powerLevelNumber)s)", {
             userName: this.props.member.userId,
             powerLevelNumber: this.props.member.powerLevel,
@@ -204,7 +216,7 @@ export default class MemberTile extends React.Component {
         const EntityTile = sdk.getComponent('rooms.EntityTile');
 
         const member = this.props.member;
-        const name = this._getDisplayName();
+        const name = this.getDisplayName();
         const presenceState = member.user ? member.user.presence : null;
 
         let statusMessage = null;
@@ -217,9 +229,9 @@ export default class MemberTile extends React.Component {
         );
 
         if (member.user) {
-            this.user_last_modified_time = member.user.getLastModifiedTime();
+            this.userLastModifiedTime = member.user.getLastModifiedTime();
         }
-        this.member_last_modified_time = member.getLastModifiedTime();
+        this.memberLastModifiedTime = member.getLastModifiedTime();
 
         const powerStatusMap = new Map([
             [100, EntityTile.POWER_STATUS_ADMIN],

From e25940cbdd18630c58e6b4d58f577d85f30fd97b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Wed, 23 Jun 2021 19:18:36 +0200
Subject: [PATCH 03/11] Convert PresenceLabel to TS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 .../{PresenceLabel.js => PresenceLabel.tsx}   | 49 +++++++++----------
 1 file changed, 23 insertions(+), 26 deletions(-)
 rename src/components/views/rooms/{PresenceLabel.js => PresenceLabel.tsx} (69%)

diff --git a/src/components/views/rooms/PresenceLabel.js b/src/components/views/rooms/PresenceLabel.tsx
similarity index 69%
rename from src/components/views/rooms/PresenceLabel.js
rename to src/components/views/rooms/PresenceLabel.tsx
index ca21afe63d..513fecfd43 100644
--- a/src/components/views/rooms/PresenceLabel.js
+++ b/src/components/views/rooms/PresenceLabel.tsx
@@ -15,26 +15,23 @@ limitations under the License.
 */
 
 import React from 'react';
-import PropTypes from 'prop-types';
 
 import { _t } from '../../../languageHandler';
 import {replaceableComponent} from "../../../utils/replaceableComponent";
 
+interface IProps {
+    // number of milliseconds ago this user was last active.
+    // zero = unknown
+    activeAgo?: number,
+    // if true, activeAgo is an approximation and "Now" should
+    // be shown instead
+    currentlyActive?: boolean,
+    // offline, online, etc
+    presenceState?: string,
+}
+
 @replaceableComponent("views.rooms.PresenceLabel")
-export default class PresenceLabel extends React.Component {
-    static propTypes = {
-        // number of milliseconds ago this user was last active.
-        // zero = unknown
-        activeAgo: PropTypes.number,
-
-        // if true, activeAgo is an approximation and "Now" should
-        // be shown instead
-        currentlyActive: PropTypes.bool,
-
-        // offline, online, etc
-        presenceState: PropTypes.string,
-    };
-
+export default class PresenceLabel extends React.Component<IProps> {
     static defaultProps = {
         activeAgo: -1,
         presenceState: null,
@@ -42,29 +39,29 @@ export default class PresenceLabel extends React.Component {
 
     // Return duration as a string using appropriate time units
     // XXX: This would be better handled using a culture-aware library, but we don't use one yet.
-    getDuration(time) {
+    private getDuration(time: number): string {
         if (!time) return;
-        const t = parseInt(time / 1000);
+        const t = time / 1000;
         const s = t % 60;
-        const m = parseInt(t / 60) % 60;
-        const h = parseInt(t / (60 * 60)) % 24;
-        const d = parseInt(t / (60 * 60 * 24));
+        const m = t / 60 % 60;
+        const h = t / (60 * 60) % 24;
+        const d = t / (60 * 60 * 24);
         if (t < 60) {
             if (t < 0) {
-                return _t("%(duration)ss", {duration: 0});
+                return _t("%(duration)ss", { duration: 0 });
             }
-            return _t("%(duration)ss", {duration: s});
+            return _t("%(duration)ss", { duration: s });
         }
         if (t < 60 * 60) {
-            return _t("%(duration)sm", {duration: m});
+            return _t("%(duration)sm", { duration: m });
         }
         if (t < 24 * 60 * 60) {
-            return _t("%(duration)sh", {duration: h});
+            return _t("%(duration)sh", { duration: h });
         }
-        return _t("%(duration)sd", {duration: d});
+        return _t("%(duration)sd", { duration: d });
     }
 
-    getPrettyPresence(presence, activeAgo, currentlyActive) {
+    private getPrettyPresence(presence: string, activeAgo: number, currentlyActive: boolean): string {
         if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
             const duration = this.getDuration(activeAgo);
             if (presence === "online") return _t("Online for %(duration)s", { duration: duration });

From 298e505381e96e30535bd1ce28b66b1e523be094 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 14:29:24 +0200
Subject: [PATCH 04/11] Iterate EntityTile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/EntityTile.tsx | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
index 53c5900fbf..106449b391 100644
--- a/src/components/views/rooms/EntityTile.tsx
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-import React, { createRef } from 'react';
+import React from 'react';
 import AccessibleButton from '../elements/AccessibleButton';
 import { _td } from '../../../languageHandler';
 import classNames from "classnames";
@@ -25,7 +25,12 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
 import BaseAvatar from '../avatars/BaseAvatar';
 import PresenceLabel from "./PresenceLabel";
 
-const PowerLabel: Record<string, string> = {
+enum PowerStatus {
+    Admin = "admin",
+    Moderator = "moderator",
+}
+
+const PowerLabel: Record<PowerStatus, string> = {
     "admin": _td("Admin"),
     "moderator": _td("Mod"),
 }
@@ -36,7 +41,7 @@ const PRESENCE_CLASS = {
     "unavailable": "mx_EntityTile_unavailable",
 };
 
-function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean) {
+function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean): string {
     if (showPresence === false) {
         return 'mx_EntityTile_online_beenactive';
     }
@@ -66,13 +71,12 @@ interface IProps {
     presenceLastTs?: number,
     presenceCurrentlyActive?: boolean,
     showInviteButton?: boolean,
-    shouldComponentUpdate?(nextProps: IProps, nextState: IState): boolean,
     onClick?(): void,
     suppressOnHover?: boolean,
     showPresence?: boolean,
     subtextLabel?: string,
     e2eStatus?: string,
-    powerStatus?: string,
+    powerStatus?: PowerStatus,
 }
 
 interface IState {
@@ -82,7 +86,6 @@ interface IState {
 @replaceableComponent("views.rooms.EntityTile")
 export default class EntityTile extends React.Component<IProps, IState> {
     static defaultProps = {
-        shouldComponentUpdate: (nextProps: IProps, nextState: IState) => { return true; },
         onClick: () => {},
         presenceState: "offline",
         presenceLastActiveAgo: 0,
@@ -91,7 +94,6 @@ export default class EntityTile extends React.Component<IProps, IState> {
         suppressOnHover: false,
         showPresence: true,
     };
-    private container = createRef<HTMLDivElement>();
 
     constructor(props: IProps) {
         super(props);
@@ -103,7 +105,6 @@ export default class EntityTile extends React.Component<IProps, IState> {
 
     shouldComponentUpdate(nextProps: IProps, nextState: IState) {
         if (this.state.hover !== nextState.hover) return true;
-        return this.props.shouldComponentUpdate(nextProps, nextState);
     }
 
     render() {
@@ -184,7 +185,7 @@ export default class EntityTile extends React.Component<IProps, IState> {
 
         // The wrapping div is required to make the magic mouse listener work, for some reason.
         return (
-            <div ref={this.container} >
+            <div>
                 <AccessibleButton
                     className={classNames(mainClassNames)}
                     title={this.props.title}

From 1b64cd0c88bb1092f11e680460c4f983c9d7d0b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 14:36:22 +0200
Subject: [PATCH 05/11] Iterate PresenceLabel
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/PresenceLabel.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/components/views/rooms/PresenceLabel.tsx b/src/components/views/rooms/PresenceLabel.tsx
index 513fecfd43..abedb394b5 100644
--- a/src/components/views/rooms/PresenceLabel.tsx
+++ b/src/components/views/rooms/PresenceLabel.tsx
@@ -17,17 +17,17 @@ limitations under the License.
 import React from 'react';
 
 import { _t } from '../../../languageHandler';
-import {replaceableComponent} from "../../../utils/replaceableComponent";
+import { replaceableComponent } from "../../../utils/replaceableComponent";
 
 interface IProps {
     // number of milliseconds ago this user was last active.
     // zero = unknown
-    activeAgo?: number,
+    activeAgo?: number;
     // if true, activeAgo is an approximation and "Now" should
     // be shown instead
-    currentlyActive?: boolean,
+    currentlyActive?: boolean;
     // offline, online, etc
-    presenceState?: string,
+    presenceState?: string;
 }
 
 @replaceableComponent("views.rooms.PresenceLabel")

From 5b21cff24098b62fa45e7c46964ec8841d02a3fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 14:38:21 +0200
Subject: [PATCH 06/11] Iterate MemberTile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/MemberTile.tsx | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx
index e0ee0e5daf..390cbdbf9f 100644
--- a/src/components/views/rooms/MemberTile.tsx
+++ b/src/components/views/rooms/MemberTile.tsx
@@ -29,14 +29,14 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
 import { DeviceInfo } from "matrix-js-sdk/src/crypto";
 
 interface IProps {
-    member: RoomMember,
-    showPresence?: boolean,
+    member: RoomMember;
+    showPresence?: boolean;
 }
 
 interface IState {
-    statusMessage: string,
-    isRoomEncrypted: boolean,
-    e2eStatus: string,
+    statusMessage: string;
+    isRoomEncrypted: boolean;
+    e2eStatus: string;
 }
 
 @replaceableComponent("views.rooms.MemberTile")

From 8fb788ae5679c44b46d70cf9887be01fe50f07ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 14:39:51 +0200
Subject: [PATCH 07/11] Iterate EntityTile once more
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/EntityTile.tsx | 30 +++++++++++------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
index 106449b391..de37d6caf0 100644
--- a/src/components/views/rooms/EntityTile.tsx
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -62,21 +62,21 @@ function presenceClassForMember(presenceState: string, lastActiveAgo: number, sh
 }
 
 interface IProps {
-    name?: string,
-    title?: string,
-    avatarJsx?: JSX.Element, // <BaseAvatar />
-    className?: string,
-    presenceState?: string,
-    presenceLastActiveAgo?: number,
-    presenceLastTs?: number,
-    presenceCurrentlyActive?: boolean,
-    showInviteButton?: boolean,
-    onClick?(): void,
-    suppressOnHover?: boolean,
-    showPresence?: boolean,
-    subtextLabel?: string,
-    e2eStatus?: string,
-    powerStatus?: PowerStatus,
+    name?: string;
+    title?: string;
+    avatarJsx?: JSX.Element; // <BaseAvatar />
+    className?: string;
+    presenceState?: string;
+    presenceLastActiveAgo?: number;
+    presenceLastTs?: number;
+    presenceCurrentlyActive?: boolean;
+    showInviteButton?: boolean;
+    onClick?(): void;
+    suppressOnHover?: boolean;
+    showPresence?: boolean;
+    subtextLabel?: string;
+    e2eStatus?: string;
+    powerStatus?: PowerStatus;
 }
 
 interface IState {

From f08b92309f95f018fcc7cd972a3ca16577df5196 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 16:35:33 +0200
Subject: [PATCH 08/11] Iterate EntityTile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/EntityTile.tsx | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
index de37d6caf0..fedb0b2964 100644
--- a/src/components/views/rooms/EntityTile.tsx
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -31,8 +31,8 @@ enum PowerStatus {
 }
 
 const PowerLabel: Record<PowerStatus, string> = {
-    "admin": _td("Admin"),
-    "moderator": _td("Mod"),
+    [PowerStatus.Admin]: _td("Admin"),
+    [PowerStatus.Moderator]: _td("Mod"),
 }
 
 const PRESENCE_CLASS = {
@@ -84,7 +84,7 @@ interface IState {
 }
 
 @replaceableComponent("views.rooms.EntityTile")
-export default class EntityTile extends React.Component<IProps, IState> {
+export default class EntityTile extends React.PureComponent<IProps, IState> {
     static defaultProps = {
         onClick: () => {},
         presenceState: "offline",
@@ -103,10 +103,6 @@ export default class EntityTile extends React.Component<IProps, IState> {
         };
     }
 
-    shouldComponentUpdate(nextProps: IProps, nextState: IState) {
-        if (this.state.hover !== nextState.hover) return true;
-    }
-
     render() {
         const mainClassNames = {
             "mx_EntityTile": true,

From c0a1127cb70a0bac98e13126927dd6d5f8450758 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 16:43:11 +0200
Subject: [PATCH 09/11] Fix PowerStatus
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/EntityTile.tsx | 2 +-
 src/components/views/rooms/MemberTile.tsx | 9 ++++-----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
index fedb0b2964..2032856500 100644
--- a/src/components/views/rooms/EntityTile.tsx
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -25,7 +25,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
 import BaseAvatar from '../avatars/BaseAvatar';
 import PresenceLabel from "./PresenceLabel";
 
-enum PowerStatus {
+export enum PowerStatus {
     Admin = "admin",
     Moderator = "moderator",
 }
diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx
index 390cbdbf9f..c6077fb47f 100644
--- a/src/components/views/rooms/MemberTile.tsx
+++ b/src/components/views/rooms/MemberTile.tsx
@@ -27,6 +27,8 @@ import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 import { EventType } from "matrix-js-sdk/src/@types/event";
 import { DeviceInfo } from "matrix-js-sdk/src/crypto";
+import EntityTile, { PowerStatus } from "./EntityTile";
+import MemberAvatar from "./../avatars/MemberAvatar";
 
 interface IProps {
     member: RoomMember;
@@ -212,9 +214,6 @@ export default class MemberTile extends React.Component<IProps, IState> {
     }
 
     render() {
-        const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
-        const EntityTile = sdk.getComponent('rooms.EntityTile');
-
         const member = this.props.member;
         const name = this.getDisplayName();
         const presenceState = member.user ? member.user.presence : null;
@@ -234,8 +233,8 @@ export default class MemberTile extends React.Component<IProps, IState> {
         this.memberLastModifiedTime = member.getLastModifiedTime();
 
         const powerStatusMap = new Map([
-            [100, EntityTile.POWER_STATUS_ADMIN],
-            [50, EntityTile.POWER_STATUS_MODERATOR],
+            [100, PowerStatus.Admin],
+            [50, PowerStatus.Moderator],
         ]);
 
         // Find the nearest power level with a badge

From b065f6d1a4b591fce8da33183810598825b088f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 16:48:36 +0200
Subject: [PATCH 10/11] Remove sdk...
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/MemberTile.tsx | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx
index c6077fb47f..a97ce6995b 100644
--- a/src/components/views/rooms/MemberTile.tsx
+++ b/src/components/views/rooms/MemberTile.tsx
@@ -17,7 +17,6 @@ limitations under the License.
 
 import SettingsStore from "../../../settings/SettingsStore";
 import React from 'react';
-import * as sdk from "../../../index";
 import dis from "../../../dispatcher/dispatcher";
 import { _t } from '../../../languageHandler';
 import { MatrixClientPeg } from "../../../MatrixClientPeg";

From dc2f71bee67b3e65f73b335e4d1d5cb0d15a1534 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=A0imon=20Brandner?= <simon.bra.ag@gmail.com>
Date: Thu, 24 Jun 2021 16:55:44 +0200
Subject: [PATCH 11/11] Even more fixes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
---
 src/components/views/rooms/MemberTile.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx
index a97ce6995b..2f9927a756 100644
--- a/src/components/views/rooms/MemberTile.tsx
+++ b/src/components/views/rooms/MemberTile.tsx
@@ -25,7 +25,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
 import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 import { MatrixEvent } from "matrix-js-sdk/src/models/event";
 import { EventType } from "matrix-js-sdk/src/@types/event";
-import { DeviceInfo } from "matrix-js-sdk/src/crypto";
+import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
 import EntityTile, { PowerStatus } from "./EntityTile";
 import MemberAvatar from "./../avatars/MemberAvatar";
 
@@ -194,7 +194,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
         return false;
     }
 
-    private onClick = (e: MouseEvent): void => {
+    private onClick = (): void => {
         dis.dispatch({
             action: Action.ViewUser,
             member: this.props.member,