From e502fafad2d2eace7eb7bebed987d48624c70a50 Mon Sep 17 00:00:00 2001
From: David Baker <dbkr@users.noreply.github.com>
Date: Tue, 1 Mar 2022 11:49:23 +0000
Subject: [PATCH 1/3] Fix right panel soft crashes due to missing room prop
 (#7923) (#7927)

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
---
 res/css/structures/_GroupView.scss            |  1 +
 src/components/structures/MatrixChat.tsx      |  2 +-
 src/components/structures/RightPanel.tsx      | 29 ++++++++++++-------
 src/components/structures/ThreadView.tsx      |  2 +-
 src/stores/right-panel/RightPanelStore.ts     | 14 ++++-----
 .../right-panel/RightPanelStorePhases.ts      | 20 -------------
 6 files changed, 29 insertions(+), 39 deletions(-)

diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss
index 8d05135a9a..9cbf632cdd 100644
--- a/res/css/structures/_GroupView.scss
+++ b/res/css/structures/_GroupView.scss
@@ -18,6 +18,7 @@ limitations under the License.
     display: flex;
     flex-direction: column;
     overflow: hidden;
+    flex-grow: 1;
 }
 
 .mx_GroupView_error {
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 59d9b97ea5..4960f59c08 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -975,7 +975,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
             this.viewWelcome();
             return;
         }
-        if (!this.state.currentGroupId && !this.state.currentRoomId) {
+        if (!this.state.currentGroupId && !this.state.currentRoomId && !this.state.currentUserId) {
             this.viewHome();
         }
     }
diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx
index 0779a9a52b..a1e06101da 100644
--- a/src/components/structures/RightPanel.tsx
+++ b/src/components/structures/RightPanel.tsx
@@ -94,10 +94,23 @@ export default class RightPanel extends React.Component<IProps, IState> {
     }
 
     public static getDerivedStateFromProps(props: IProps): Partial<IState> {
-        const currentCard = RightPanelStore.instance.currentCardForRoom(props.room.roomId);
+        let currentCard: IRightPanelCard;
+        if (props.room) {
+            currentCard = RightPanelStore.instance.currentCardForRoom(props.room.roomId);
+        }
+        if (props.groupId) {
+            currentCard = RightPanelStore.instance.currentGroup;
+        }
+
+        if (currentCard?.phase && !RightPanelStore.instance.isPhaseValid(currentCard.phase, !!props.room)) {
+            // XXX: We can probably get rid of this workaround once GroupView is dead, it's unmounting happens weirdly
+            // late causing the app to soft-crash due to lack of a room object being passed to a RightPanel
+            return null; // skip this update, we're about to be unmounted and don't have the appropriate props
+        }
+
         return {
-            cardState: currentCard.state,
-            phase: currentCard.phase,
+            cardState: currentCard?.state,
+            phase: currentCard?.phase,
         };
     }
 
@@ -118,11 +131,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
     };
 
     private onRightPanelStoreUpdate = () => {
-        const currentCard = RightPanelStore.instance.currentCardForRoom(this.props.room.roomId);
-        this.setState({
-            cardState: currentCard.state,
-            phase: currentCard.phase,
-        });
+        this.setState({ ...RightPanel.getDerivedStateFromProps(this.props) as IState });
     };
 
     private onClose = () => {
@@ -139,7 +148,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
             });
         } else if (
             this.state.phase === RightPanelPhases.EncryptionPanel &&
-            this.state.cardState.verificationRequest && this.state.cardState.verificationRequest.pending
+            this.state.cardState.verificationRequest?.pending
         ) {
             // When the user clicks close on the encryption panel cancel the pending request first if any
             this.state.cardState.verificationRequest.cancel();
@@ -154,7 +163,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
 
     public render(): JSX.Element {
         let card = <div />;
-        const roomId = this.props.room ? this.props.room.roomId : undefined;
+        const roomId = this.props.room?.roomId;
         const phase = this.props.overwriteCard?.phase ?? this.state.phase;
         const cardState = this.props.overwriteCard?.state ?? this.state.cardState;
         switch (phase) {
diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx
index c26c64428c..a2a5336307 100644
--- a/src/components/structures/ThreadView.tsx
+++ b/src/components/structures/ThreadView.tsx
@@ -94,7 +94,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
 
     public componentWillUnmount(): void {
         this.teardownThread();
-        dis.unregister(this.dispatcherRef);
+        if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
         const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
         room.removeListener(ThreadEvent.New, this.onNewThread);
         SettingsStore.unwatchSetting(this.layoutWatcherRef);
diff --git a/src/stores/right-panel/RightPanelStore.ts b/src/stores/right-panel/RightPanelStore.ts
index 71754d2bc6..0681bf11b8 100644
--- a/src/stores/right-panel/RightPanelStore.ts
+++ b/src/stores/right-panel/RightPanelStore.ts
@@ -155,7 +155,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
         const cardState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
 
         // Checks for wrong SetRightPanelPhase requests
-        if (!this.isPhaseActionValid(targetPhase)) return;
+        if (!this.isPhaseValid(targetPhase)) return;
 
         if ((targetPhase === this.currentCardForRoom(rId)?.phase && !!cardState)) {
             // Update state: set right panel with a new state but keep the phase (dont know it this is ever needed...)
@@ -194,16 +194,16 @@ export default class RightPanelStore extends ReadyWatchingStore {
         const pState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
 
         // Checks for wrong SetRightPanelPhase requests
-        if (!this.isPhaseActionValid(targetPhase)) return;
+        if (!this.isPhaseValid(targetPhase)) return;
 
-        let roomCache = this.byRoom[rId];
+        const roomCache = this.byRoom[rId];
         if (!!roomCache) {
             // append new phase
             roomCache.history.push({ state: pState, phase: targetPhase });
             roomCache.isOpen = allowClose ? roomCache.isOpen : true;
         } else {
             // setup room panel cache with the new card
-            roomCache = {
+            this.byRoom[rId] = {
                 history: [{ phase: targetPhase, state: pState ?? {} }],
                 // if there was no right panel store object the the panel was closed -> keep it closed, except if allowClose==false
                 isOpen: !allowClose,
@@ -344,18 +344,18 @@ export default class RightPanelStore extends ReadyWatchingStore {
         return null;
     }
 
-    private isPhaseActionValid(targetPhase) {
+    public isPhaseValid(targetPhase: RightPanelPhases, isViewingRoom = this.isViewingRoom): boolean {
         if (!RightPanelPhases[targetPhase]) {
             logger.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`);
             return false;
         }
-        if (GROUP_PHASES.includes(targetPhase) && this.isViewingRoom) {
+        if (GROUP_PHASES.includes(targetPhase) && isViewingRoom) {
             logger.warn(
                 `Tried to switch right panel to a group phase: ${targetPhase}, ` +
                 `but we are currently not viewing a group`,
             );
             return false;
-        } else if (!GROUP_PHASES.includes(targetPhase) && !this.isViewingRoom) {
+        } else if (!GROUP_PHASES.includes(targetPhase) && !isViewingRoom) {
             logger.warn(
                 `Tried to switch right panel to a room phase: ${targetPhase}, ` +
                 `but we are currently not viewing a room`,
diff --git a/src/stores/right-panel/RightPanelStorePhases.ts b/src/stores/right-panel/RightPanelStorePhases.ts
index 10e7b64918..59d5a2f73a 100644
--- a/src/stores/right-panel/RightPanelStorePhases.ts
+++ b/src/stores/right-panel/RightPanelStorePhases.ts
@@ -56,23 +56,3 @@ export function backLabelForPhase(phase: RightPanelPhases) {
     }
     return null;
 }
-
-// These are the phases that are safe to persist (the ones that don't require additional
-// arguments).
-export const RIGHT_PANEL_PHASES_NO_ARGS = [
-    RightPanelPhases.RoomSummary,
-    RightPanelPhases.NotificationPanel,
-    RightPanelPhases.PinnedMessages,
-    RightPanelPhases.FilePanel,
-    RightPanelPhases.RoomMemberList,
-    RightPanelPhases.GroupMemberList,
-    RightPanelPhases.GroupRoomList,
-    RightPanelPhases.Timeline,
-];
-
-// Subset of phases visible in the Space View
-export const RIGHT_PANEL_SPACE_PHASES = [
-    RightPanelPhases.SpaceMemberList,
-    RightPanelPhases.Space3pidMemberInfo,
-    RightPanelPhases.SpaceMemberInfo,
-];

From 33b334cdf746547c6f454f70d6113a7c4aad72cc Mon Sep 17 00:00:00 2001
From: RiotRobot <releases@riot.im>
Date: Tue, 1 Mar 2022 11:52:58 +0000
Subject: [PATCH 2/3] Prepare changelog for v3.41.1

---
 CHANGELOG.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31226d2834..0aa6b18fc2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+Changes in [3.41.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.41.1) (2022-03-01)
+=====================================================================================================
+
+## 🐛 Bug Fixes
+ * Fix some crashes in the right panel
+
 Changes in [3.41.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.41.0) (2022-02-28)
 =====================================================================================================
 

From 915d8385d4a793bc55ceda678b3e626c6e2686a8 Mon Sep 17 00:00:00 2001
From: RiotRobot <releases@riot.im>
Date: Tue, 1 Mar 2022 11:52:59 +0000
Subject: [PATCH 3/3] v3.41.1

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index bf1b0ce903..c375ebbdd6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "matrix-react-sdk",
-  "version": "3.41.0",
+  "version": "3.41.1",
   "description": "SDK for matrix.org using React",
   "author": "matrix.org",
   "repository": {