diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 9ebfa17c82..241e5d580b 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -1180,12 +1180,8 @@ export default class MatrixChat extends React.PureComponent { button: _t("Leave"), onFinished: (shouldLeave) => { if (shouldLeave) { - const d = leaveRoomBehaviour(roomId); + leaveRoomBehaviour(roomId); - // FIXME: controller shouldn't be loading a view :( - const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); - - d.finally(() => modal.close()); dis.dispatch({ action: "after_leave_room", room_id: roomId, diff --git a/src/utils/membership.ts b/src/utils/membership.ts index 1a120e08b3..2b31737dde 100644 --- a/src/utils/membership.ts +++ b/src/utils/membership.ts @@ -16,14 +16,16 @@ limitations under the License. import { Room } from "matrix-js-sdk/src/models/room"; import { sleep } from "matrix-js-sdk/src/utils"; +import { EventStatus } from "matrix-js-sdk/src/models/event"; import { MatrixClientPeg } from "../MatrixClientPeg"; import { _t } from "../languageHandler"; -import Modal from "../Modal"; +import Modal, { IHandle } from "../Modal"; import ErrorDialog from "../components/views/dialogs/ErrorDialog"; import React from "react"; import dis from "../dispatcher/dispatcher"; import RoomViewStore from "../stores/RoomViewStore"; +import Spinner from "../components/views/elements/Spinner"; /** * Approximation of a membership status for a given room. @@ -85,7 +87,12 @@ export function isJoinedOrNearlyJoined(membership: string): boolean { return effective === EffectiveMembership.Join || effective === EffectiveMembership.Invite; } -export async function leaveRoomBehaviour(roomId: string, retry = true) { +export async function leaveRoomBehaviour(roomId: string, retry = true, spinner = true) { + let spinnerModal: IHandle; + if (spinner) { + spinnerModal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); + } + const cli = MatrixClientPeg.get(); let leavingAllVersions = true; const history = cli.getRoomUpgradeHistory(roomId); @@ -98,6 +105,26 @@ export async function leaveRoomBehaviour(roomId: string, retry = true) { } } + const room = cli.getRoom(roomId); + // await any queued messages being sent so that they do not fail + await Promise.all(room.getPendingEvents().filter(ev => { + return [EventStatus.QUEUED, EventStatus.ENCRYPTING, EventStatus.SENDING].includes(ev.status); + }).map(ev => new Promise((resolve, reject) => { + const handler = () => { + if (ev.status === EventStatus.NOT_SENT) { + spinnerModal?.close(); + reject(ev.error); + } + + if (!ev.status || ev.status === EventStatus.SENT) { + ev.off("Event.status", handler); + resolve(); + } + }; + + ev.on("Event.status", handler); + }))); + let results: { [roomId: string]: Error & { errcode?: string, message: string, data?: Record } } = {}; if (!leavingAllVersions) { try { @@ -118,10 +145,12 @@ export async function leaveRoomBehaviour(roomId: string, retry = true) { const limitExceededError = Object.values(results).find(e => e?.errcode === "M_LIMIT_EXCEEDED"); if (limitExceededError) { await sleep(limitExceededError.data.retry_after_ms ?? 100); - return leaveRoomBehaviour(roomId, false); + return leaveRoomBehaviour(roomId, false, false); } } + spinnerModal?.close(); + const errors = Object.entries(results).filter(r => !!r[1]); if (errors.length > 0) { const messages = [];