feat(app): show paused-messaging banner across the app (#3178)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-03 19:31:43 +02:00
1 parent 973aaced96
commit bc5dcdfe21
61 files changed
+7917 -7775

No files matched your search

@@ -10,6 +10,10 @@ import {GenericErrorModal} from '@app/features/app/components/alerts/GenericErro
import {failureCode, failureMessage} from '@app/features/platform/utils/ResponseInspection';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
import {modal} from '@app/features/ui/commands/ModalCommands';
import {
ACCOUNT_LIMITED_NOTICE_DESCRIPTOR,
ACCOUNT_LIMITED_TITLE_DESCRIPTOR,
} from '@app/features/user/utils/AccountLimitUtils';
import {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
import {msg} from '@lingui/core/macro';
@@ -72,11 +76,15 @@ export function resolveDmActionErrorContent(
): {title: string; message: string} {
switch (code) {
case APIErrorCodes.NEW_CONVERSATIONS_LIMITED:
case APIErrorCodes.ACCOUNT_LIMITED:
return {
title: i18nGlobal._(GENERIC_TITLE_DESCRIPTOR),
message: apiMessage || i18nGlobal._(GENERIC_ERROR_BODY_DESCRIPTOR),
};
case APIErrorCodes.ACCOUNT_LIMITED:
return {
title: i18nGlobal._(ACCOUNT_LIMITED_TITLE_DESCRIPTOR),
message: apiMessage || i18nGlobal._(ACCOUNT_LIMITED_NOTICE_DESCRIPTOR),
};
case APIErrorCodes.CANNOT_SEND_MESSAGES_TO_USER:
return {
title: i18nGlobal._(CANNOT_MESSAGE_USER_TITLE_DESCRIPTOR),
@@ -1271,6 +1271,7 @@ const SKELETON_NAGBAR_ROW_SHAPES: Record<NagbarType, SkeletonNagbarRowShape> = {
[NagbarType.SCHEDULED_MAINTENANCE]: {tone: SkeletonNagbarTone.MAINTENANCE_SCHEDULED, hasActions: true},
[NagbarType.UNCLAIMED_ACCOUNT]: {tone: SkeletonNagbarTone.ALERT, hasActions: true},
[NagbarType.EMAIL_VERIFICATION]: {tone: SkeletonNagbarTone.ALERT, hasActions: true},
[NagbarType.ACCOUNT_LIMITED]: {tone: SkeletonNagbarTone.NEUTRAL, hasActions: false},
[NagbarType.DESKTOP_NOTIFICATION]: {tone: SkeletonNagbarTone.BRAND, hasActions: true},
[NagbarType.PREMIUM_GRACE_PERIOD]: {tone: SkeletonNagbarTone.PREMIUM, hasActions: true},
[NagbarType.PREMIUM_EXPIRED]: {tone: SkeletonNagbarTone.DANGER, hasActions: true},
@@ -307,6 +307,11 @@ export const useNagbarConditions = (): NagbarConditions => {
: nagbarState.forceEmailVerification
? true
: Boolean(RuntimeConfig.emailsEnabled && user?.isClaimed() && !user.verified),
canShowAccountLimited: nagbarState.forceHideAccountLimited
? false
: nagbarState.forceAccountLimited
? true
: user?.accountLimited === true,
canShowDesktopNotification: nagbarState.forceHideDesktopNotification
? false
: nagbarState.forceDesktopNotification
@@ -375,6 +380,12 @@ export const useActiveNagbars = (conditions: NagbarConditions): Array<NagbarStat
visible: conditions.userNeedsVerification,
dismissible: false,
},
{
type: NagbarType.ACCOUNT_LIMITED,
priority: -3.75,
visible: conditions.canShowAccountLimited,
dismissible: false,
},
{
type: NagbarType.PREMIUM_EXPIRED,
priority: 0,
@@ -9,6 +9,7 @@ export const NagbarType = {
SCHEDULED_MAINTENANCE: 'scheduled-maintenance',
UNCLAIMED_ACCOUNT: 'unclaimed-account',
EMAIL_VERIFICATION: 'email-verification',
ACCOUNT_LIMITED: 'account-limited',
DESKTOP_NOTIFICATION: 'desktop-notification',
PREMIUM_GRACE_PERIOD: 'premium-grace-period',
PREMIUM_EXPIRED: 'premium-expired',
@@ -48,6 +49,7 @@ export interface NagbarConditions {
canShowScheduledMaintenance: boolean;
userIsUnclaimed: boolean;
userNeedsVerification: boolean;
canShowAccountLimited: boolean;
canShowDesktopNotification: boolean;
canShowPremiumGracePeriod: boolean;
canShowPremiumExpired: boolean;
@@ -2,6 +2,7 @@
import {type NagbarState, NagbarType} from '@app/features/app/components/layout/app_layout/AppLayoutTypes';
import styles from '@app/features/app/components/layout/app_layout/NagbarContainer.module.css';
import {AccountLimitedNagbar} from '@app/features/app/components/layout/app_layout/nagbars/AccountLimitedNagbar';
import {BuildEnvironmentNagbar} from '@app/features/app/components/layout/app_layout/nagbars/BuildEnvironmentNagbar';
import {ConnectionNagbar} from '@app/features/app/components/layout/app_layout/nagbars/ConnectionNagbar';
import {CorruptedInstallationNagbar} from '@app/features/app/components/layout/app_layout/nagbars/CorruptedInstallationNagbar';
@@ -105,6 +106,14 @@ export const NagbarContainer: React.FC<NagbarContainerProps> = observer(({nagbar
data-flx="app.app-layout.nagbar-container.email-verification-nagbar"
/>
);
case NagbarType.ACCOUNT_LIMITED:
return (
<AccountLimitedNagbar
key={nagbar.type}
isMobile={mobileLayout.enabled}
data-flx="app.app-layout.nagbar-container.account-limited-nagbar"
/>
);
case NagbarType.DESKTOP_NOTIFICATION:
return (
<DesktopNotificationNagbar
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Nagbar} from '@app/features/app/components/layout/Nagbar';
import {NagbarContent} from '@app/features/app/components/layout/NagbarContent';
import {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {ACCOUNT_LIMITED_NOTICE_DESCRIPTOR} from '@app/features/user/utils/AccountLimitUtils';
import {useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
export const AccountLimitedNagbar = observer(({isMobile}: {isMobile: boolean}) => {
const {i18n} = useLingui();
return (
<Nagbar
isMobile={isMobile}
backgroundColor={NAGBAR_TONES[NagbarToneKind.NEUTRAL].backgroundColor}
textColor={NAGBAR_TONES[NagbarToneKind.NEUTRAL].textColor}
data-flx="app.app-layout.nagbars.account-limited-nagbar.nagbar"
>
<NagbarContent
isMobile={isMobile}
message={
<span data-flx="app.app-layout.nagbars.account-limited-nagbar.message">
{i18n._(ACCOUNT_LIMITED_NOTICE_DESCRIPTOR)}
</span>
}
data-flx="app.app-layout.nagbars.account-limited-nagbar.nagbar-content"
/>
</Nagbar>
);
});