diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index c76cd7cee7..c01214f3f4 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -107,7 +107,9 @@ interface IState { errcode: string; }; }; + usageLimitDismissed: boolean; usageLimitEventContent?: IUsageLimit; + usageLimitEventTs?: number; useCompactLayout: boolean; } @@ -151,6 +153,7 @@ class LoggedInView extends React.Component { syncErrorData: undefined, // use compact timeline view useCompactLayout: SettingsStore.getValue('useCompactLayout'), + usageLimitDismissed: false, }; // stash the MatrixClient in case we log out before we are unmounted @@ -302,14 +305,27 @@ class LoggedInView extends React.Component { } }; + private onUsageLimitDismissed = () => { + this.setState({ + usageLimitDismissed: true, + }); + } + _calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; if (error) { usageLimitEventContent = syncError.error.data; } - if (usageLimitEventContent) { - showServerLimitToast(usageLimitEventContent.limit_type, usageLimitEventContent.admin_contact, error); + // usageLimitDismissed is true when the user has explicitly hidden the toast + // and it will be reset to false if a *new* usage alert comes in. + if (usageLimitEventContent && this.state.usageLimitDismissed) { + showServerLimitToast( + usageLimitEventContent.limit_type, + this.onUsageLimitDismissed, + usageLimitEventContent.admin_contact, + error, + ); } else { hideServerLimitToast(); } @@ -320,10 +336,12 @@ class LoggedInView extends React.Component { if (!serverNoticeList) return []; const events = []; + let pinnedEventTs = 0; for (const room of serverNoticeList) { const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", ""); if (!pinStateEvent || !pinStateEvent.getContent().pinned) continue; + pinnedEventTs = pinStateEvent.getTs(); const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM); for (const eventId of pinnedEventIds) { @@ -333,6 +351,11 @@ class LoggedInView extends React.Component { } } + if (pinnedEventTs && this.state.usageLimitEventTs > pinnedEventTs) { + // We've processed a newer event than this one, so ignore it. + return; + } + const usageLimitEvent = events.find((e) => { return ( e && e.getType() === 'm.room.message' && @@ -341,7 +364,12 @@ class LoggedInView extends React.Component { }); const usageLimitEventContent = usageLimitEvent && usageLimitEvent.getContent(); this._calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent); - this.setState({ usageLimitEventContent }); + this.setState({ + usageLimitEventContent, + usageLimitEventTs: pinnedEventTs, + // This is a fresh toast, we can show toasts again + usageLimitDismissed: false, + }); }; _onPaste = (ev) => { diff --git a/src/toasts/ServerLimitToast.tsx b/src/toasts/ServerLimitToast.tsx index d35140be3d..81b5492402 100644 --- a/src/toasts/ServerLimitToast.tsx +++ b/src/toasts/ServerLimitToast.tsx @@ -23,7 +23,7 @@ import {messageForResourceLimitError} from "../utils/ErrorUtils"; const TOAST_KEY = "serverlimit"; -export const showToast = (limitType: string, adminContact?: string, syncError?: boolean) => { +export const showToast = (limitType: string, onHideToast: () => void, adminContact?: string, syncError?: boolean) => { const errorText = messageForResourceLimitError(limitType, adminContact, { 'monthly_active_user': _td("Your homeserver has exceeded its user limit."), '': _td("Your homeserver has exceeded one of its resource limits."), @@ -38,7 +38,10 @@ export const showToast = (limitType: string, adminContact?: string, syncError?: props: { description: {errorText} {contactText}, acceptLabel: _t("Ok"), - onAccept: hideToast, + onAccept: () => { + hideToast() + if (onHideToast) onHideToast(); + }, }, component: GenericToast, priority: 70,