mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 11:51:36 +02:00
Show banner for message rejection
This commit is contained in:
parent
07dd1ab2f7
commit
3045068f25
@ -98,6 +98,17 @@ export class RoomStatusBarViewModel
|
||||
adminContactHref: resourceLimitError.data.admin_contact,
|
||||
};
|
||||
}
|
||||
|
||||
// Check if any of the unsent messages are because the server rejected them.
|
||||
const serverRejectedEvent = unsentMessages.find((event) => event.error?.errcode === "M_FORBIDDEN");
|
||||
const errorMessage = serverRejectedEvent?.error?.error;
|
||||
if (errorMessage) {
|
||||
return {
|
||||
state: RoomStatusBarState.MessageRejected,
|
||||
errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise, we know there are unsent messages but the error is not special.
|
||||
return {
|
||||
state: RoomStatusBarState.UnsentMessages,
|
||||
@ -151,6 +162,8 @@ export class RoomStatusBarViewModel
|
||||
|
||||
private readonly client: MatrixClient;
|
||||
|
||||
private isMessageRejectedByServer: boolean = false;
|
||||
|
||||
public constructor(props: Props) {
|
||||
const client = MatrixClientPeg.safeGet();
|
||||
super(props, RoomStatusBarViewModel.computeSnapshot(props.room, client, false, false));
|
||||
@ -164,21 +177,40 @@ export class RoomStatusBarViewModel
|
||||
};
|
||||
|
||||
private readonly onRoomLocalEchoUpdated = (): void => {
|
||||
this.setSnapshot();
|
||||
const newSnapshot = RoomStatusBarViewModel.computeSnapshot(
|
||||
this.props.room,
|
||||
this.client,
|
||||
this.isResending,
|
||||
this.hasClickedTermsAndConditions,
|
||||
);
|
||||
this.setSnapshot(newSnapshot);
|
||||
if (newSnapshot.state === RoomStatusBarState.MessageRejected) {
|
||||
// When a message is rejected, there's not much to do except
|
||||
// cancel the message. So why bother waiting until the user
|
||||
// clicks the button?
|
||||
this.isMessageRejectedByServer = true;
|
||||
setTimeout(() => {
|
||||
Resend.cancelUnsentEvents(this.props.room);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
private isResending = false;
|
||||
private hasClickedTermsAndConditions = false;
|
||||
|
||||
private setSnapshot(): void {
|
||||
this.snapshot.set(
|
||||
private setSnapshot(newSnapshot?: RoomStatusBarViewSnapshot): void {
|
||||
if (this.isMessageRejectedByServer) {
|
||||
return;
|
||||
}
|
||||
const snapshot =
|
||||
newSnapshot ??
|
||||
RoomStatusBarViewModel.computeSnapshot(
|
||||
this.props.room,
|
||||
this.client,
|
||||
this.isResending,
|
||||
this.hasClickedTermsAndConditions,
|
||||
),
|
||||
);
|
||||
);
|
||||
this.snapshot.set(snapshot);
|
||||
// Reset `hasClickedTermsAndConditions` once the state has cleared.
|
||||
if (this.hasClickedTermsAndConditions && !this.snapshot.current.state) {
|
||||
this.hasClickedTermsAndConditions = false;
|
||||
@ -220,4 +252,9 @@ export class RoomStatusBarViewModel
|
||||
roomId: this.props.room.roomId,
|
||||
});
|
||||
};
|
||||
|
||||
public onDismissClick = (): void => {
|
||||
this.isMessageRejectedByServer = false;
|
||||
this.setSnapshot();
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
import React, { useCallback, useId, type JSX } from "react";
|
||||
import { RestartIcon, DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { RestartIcon, DeleteIcon, CloseIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { Button, InlineSpinner, Text } from "@vector-im/compound-web";
|
||||
|
||||
import styles from "./RoomStatusBarView.module.css";
|
||||
@ -33,6 +33,8 @@ export interface RoomStatusBarViewActions {
|
||||
* Called when the user clicks on the 'Review Terms and Conditions' button.
|
||||
*/
|
||||
onTermsAndConditionsClicked?: () => void;
|
||||
|
||||
onDismissClick?: () => void;
|
||||
}
|
||||
|
||||
export const RoomStatusBarState = {
|
||||
@ -60,6 +62,10 @@ export const RoomStatusBarState = {
|
||||
* There was an error creating a room. The user may retry creation.
|
||||
*/
|
||||
LocalRoomFailed: "LocalRoomFailed",
|
||||
/**
|
||||
* The homeserver rejected this message for some reason.
|
||||
*/
|
||||
MessageRejected: "MessageRejected",
|
||||
} as const;
|
||||
|
||||
export interface RoomStatusBarNotVisible {
|
||||
@ -85,6 +91,12 @@ export interface RoomStatusBarUnsentMessagesState {
|
||||
state: "UnsentMessages";
|
||||
isResending: boolean;
|
||||
}
|
||||
|
||||
export interface RoomStatusBarMessageRejectedState {
|
||||
state: "MessageRejected";
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export interface RoomStatusBarLocalRoomError {
|
||||
state: "LocalRoomFailed";
|
||||
}
|
||||
@ -95,7 +107,8 @@ export type RoomStatusBarViewSnapshot =
|
||||
| RoomStatusBarResourceLimitedState
|
||||
| RoomStatusBarUnsentMessagesState
|
||||
| RoomStatusBarLocalRoomError
|
||||
| RoomStatusBarNotVisible;
|
||||
| RoomStatusBarNotVisible
|
||||
| RoomStatusBarMessageRejectedState;
|
||||
|
||||
/**
|
||||
* The view model for RoomStatusBarView.
|
||||
@ -130,6 +143,14 @@ export function RoomStatusBarView({ vm }: Readonly<RoomStatusBarViewProps>): JSX
|
||||
[vm],
|
||||
);
|
||||
|
||||
const dismissClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
vm.onDismissClick?.();
|
||||
},
|
||||
[vm],
|
||||
);
|
||||
|
||||
const resendClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
|
||||
(ev) => {
|
||||
ev.preventDefault();
|
||||
@ -302,6 +323,36 @@ export function RoomStatusBarView({ vm }: Readonly<RoomStatusBarViewProps>): JSX
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
case RoomStatusBarState.MessageRejected:
|
||||
return (
|
||||
<Banner
|
||||
role="status"
|
||||
type="critical"
|
||||
actions={
|
||||
<>
|
||||
{vm.onDismissClick && (
|
||||
<Button
|
||||
size="sm"
|
||||
kind="primary"
|
||||
Icon={CloseIcon}
|
||||
onClick={dismissClick}
|
||||
className={styles.primaryAction}
|
||||
>
|
||||
Dismiss
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
aria-labelledby={bannerTitleId}
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<Text className={styles.title} id={bannerTitleId} weight="medium">
|
||||
Message Rejected
|
||||
</Text>
|
||||
<Text className={styles.description}>{snapshot.errorMessage}</Text>
|
||||
</div>
|
||||
</Banner>
|
||||
);
|
||||
default:
|
||||
// We should never get into this state.
|
||||
return null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user