feat: remove Canary Testers guild integration (#1572)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-12 15:40:33 +02:00
1 parent a9a51f576c
commit f88b0f69b2
56 files changed
+1156 -4266

No files matched your search

@@ -6,16 +6,13 @@ import {
type NagbarState,
NagbarType,
} from '@app/features/app/components/layout/app_layout/AppLayoutTypes';
import {isCanaryTesterCtaDismissed} from '@app/features/app/components/layout/app_layout/CanaryTesterDismissal';
import {isScheduledMaintenanceNagbarDismissed} from '@app/features/app/components/layout/app_layout/ScheduledMaintenanceDismissal';
import Config from '@app/features/app/config/Config';
import Initialization from '@app/features/app/state/Initialization';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import Authentication from '@app/features/auth/state/Authentication';
import Channels from '@app/features/channel/state/Channels';
import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions';
import GatewayConnection from '@app/features/gateway/transport/GatewayConnection';
import GuildMembers from '@app/features/member/state/GuildMembers';
import * as NotificationUtils from '@app/features/notification/utils/NotificationUtils';
import NativePermission from '@app/features/permissions/system/state/NativePermission';
import StreamerMode from '@app/features/streamer_mode/state/StreamerMode';
@@ -33,12 +30,10 @@ import {
getVoiceSessionRestoreSnapshotKey,
isRestorableVoiceChannelType,
} from '@app/features/voice/utils/VoiceSessionRestoreUtils';
import {CANARY_TESTER_MIN_ACCOUNT_AGE_MS, CANARY_TESTERS_GUILD_ID} from '@fluxer/constants/src/AppConstants';
import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants';
import {PRIVACY_POLICY_LAST_UPDATED, TERMS_OF_SERVICE_LAST_UPDATED} from '@fluxer/constants/src/PolicyConstants';
import {UserPremiumTypes} from '@fluxer/constants/src/UserConstants';
import {MS_PER_DAY} from '@fluxer/date_utils/src/DateConstants';
import * as SnowflakeUtils from '@fluxer/snowflake/src/SnowflakeUtils';
import {useEffect, useMemo, useState} from 'react';
function sortNagbarsByPriority(a: NagbarState, b: NagbarState): number {
@@ -168,21 +163,6 @@ export const useNagbarConditions = (): NagbarConditions => {
if (isSelfHosted) return false;
return !nagbarState.guildMembershipCtaDismissed;
})();
void nagbarState.canaryTesterCtaDismissalVersion;
const canShowCanaryTesterCta = (() => {
if (nagbarState.forceHideCanaryTesterCta) return false;
if (nagbarState.forceCanaryTesterCta) return true;
if (!user) return false;
if (isSelfHosted) return false;
if (Config.PUBLIC_RELEASE_CHANNEL !== 'canary') return false;
if (user.bot) return false;
if (!user.email || !user.verified) return false;
if (user.requiredActions && user.requiredActions.length > 0) return false;
if (SnowflakeUtils.age(user.id) < CANARY_TESTER_MIN_ACCOUNT_AGE_MS) return false;
if (GuildMembers.getMember(CANARY_TESTERS_GUILD_ID, user.id)) return false;
if (isCanaryTesterCtaDismissed()) return false;
return true;
})();
void nagbarState.scheduledMaintenanceDismissalVersion;
const canShowScheduledMaintenance = (() => {
if (nagbarState.forceHideScheduledMaintenance) return false;
@@ -285,7 +265,6 @@ export const useNagbarConditions = (): NagbarConditions => {
canShowVisionaryMfa,
canShowVoiceSessionRestore,
needsTermsAcceptance,
canShowCanaryTesterCta,
canShowLinuxInputAccess,
canShowSoftwareEncoder,
canShowStreamerMode,
@@ -384,12 +363,6 @@ export const useActiveNagbars = (conditions: NagbarConditions): Array<NagbarStat
visible: conditions.canShowDesktopDownload,
dismissible: true,
},
{
type: NagbarType.CANARY_TESTER_CTA,
priority: 6.5,
visible: conditions.canShowCanaryTesterCta,
dismissible: true,
},
{
type: NagbarType.SOFTWARE_ENCODER,
priority: -2,
@@ -17,7 +17,6 @@ export const NagbarType = {
VISIONARY_MFA: 'visionary-mfa',
VOICE_SESSION_RESTORE: 'voice-session-restore',
TERMS_ACCEPTANCE: 'terms-acceptance',
CANARY_TESTER_CTA: 'canary-tester-cta',
LINUX_INPUT_ACCESS: 'linux-input-access',
SOFTWARE_ENCODER: 'software-encoder',
STREAMER_MODE: 'streamer-mode',
@@ -51,7 +50,6 @@ export interface NagbarConditions {
canShowVisionaryMfa: boolean;
canShowVoiceSessionRestore: boolean;
needsTermsAcceptance: boolean;
canShowCanaryTesterCta: boolean;
canShowLinuxInputAccess: boolean;
canShowSoftwareEncoder: boolean;
canShowStreamerMode: boolean;
@@ -1,17 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import AppStorage from '@app/features/platform/state/PersistentStorage';
const CANARY_TESTER_DISMISS_KEY = 'fluxer_canary_tester_cta_dismissed';
export function isCanaryTesterCtaDismissed(): boolean {
return AppStorage.getItem(CANARY_TESTER_DISMISS_KEY) === '1';
}
export function dismissCanaryTesterCtaNagbar(): void {
AppStorage.setItem(CANARY_TESTER_DISMISS_KEY, '1');
}
export function resetCanaryTesterCtaNagbar(): void {
AppStorage.removeItem(CANARY_TESTER_DISMISS_KEY);
}
@@ -2,7 +2,6 @@
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 {CanaryTesterCtaNagbar} from '@app/features/app/components/layout/app_layout/nagbars/CanaryTesterCtaNagbar';
import {CorruptedInstallationNagbar} from '@app/features/app/components/layout/app_layout/nagbars/CorruptedInstallationNagbar';
import {DesktopDownloadNagbar} from '@app/features/app/components/layout/app_layout/nagbars/DesktopDownloadNagbar';
import {DesktopNotificationNagbar} from '@app/features/app/components/layout/app_layout/nagbars/DesktopNotificationNagbar';
@@ -154,14 +153,6 @@ export const NagbarContainer: React.FC<NagbarContainerProps> = observer(({nagbar
data-flx="app.app-layout.nagbar-container.voice-session-restore-nagbar"
/>
);
case NagbarType.CANARY_TESTER_CTA:
return (
<CanaryTesterCtaNagbar
key={nagbar.type}
isMobile={mobileLayout.enabled}
data-flx="app.app-layout.nagbar-container.canary-tester-cta-nagbar"
/>
);
case NagbarType.LINUX_INPUT_ACCESS:
return (
<LinuxInputAccessNagbar
@@ -1,167 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import i18nGlobal from '@app/app/I18n';
import {GenericErrorModal} from '@app/features/app/components/alerts/GenericErrorModal';
import {dismissCanaryTesterCtaNagbar} from '@app/features/app/components/layout/app_layout/CanaryTesterDismissal';
import {Nagbar} from '@app/features/app/components/layout/Nagbar';
import {NagbarButton} from '@app/features/app/components/layout/NagbarButton';
import {NagbarContent} from '@app/features/app/components/layout/NagbarContent';
import {
CANARY_RELEASE_CHANNEL_NAME,
CANARY_TESTERS_COMMUNITY_NAME,
} from '@app/features/app/config/I18nDisplayConstants';
import * as CanaryTesterCommands from '@app/features/canary_tester/commands/CanaryTesterCommands';
import {failureCode} from '@app/features/platform/utils/ResponseInspection';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
import {modal} from '@app/features/ui/commands/ModalCommands';
import * as ToastCommands from '@app/features/ui/commands/ToastCommands';
import NagbarState from '@app/features/ui/state/Nagbar';
import {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
import {msg} from '@lingui/core/macro';
import {useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import {useState} from 'react';
const JOINED_TESTERS_COMMUNITY_DESCRIPTOR = msg({
message: 'You joined {testersCommunityName}. Thanks for testing {canaryReleaseName}!',
comment:
'Toast success shown after joining the canary testers community. {testersCommunityName} is the community name and {canaryReleaseName} is the release channel name.',
});
const VERIFY_EMAIL_TITLE_DESCRIPTOR = msg({
message: 'Verify your email first',
comment: 'Title of the error modal shown when an unverified account tries to join the canary testers community.',
});
const VERIFY_EMAIL_MESSAGE_DESCRIPTOR = msg({
message: 'You need to verify your email before you can join {testersCommunityName}.',
comment: 'Body of the error modal shown when an unverified account tries to join the canary testers community.',
});
const ACCOUNT_TOO_NEW_TITLE_DESCRIPTOR = msg({
message: 'Your account is too new',
comment: 'Title of the error modal shown when a too-new account tries to join the canary testers community.',
});
const ACCOUNT_TOO_NEW_MESSAGE_DESCRIPTOR = msg({
message: 'This account is too new to join {testersCommunityName} yet. Try again in a little while.',
comment: 'Body of the error modal shown when a too-new account tries to join the canary testers community.',
});
const SUSPICIOUS_ACTIVITY_TITLE_DESCRIPTOR = msg({
message: "We can't add you right now",
comment:
'Title of the error modal shown when a flagged account is blocked from joining the canary testers community.',
});
const SUSPICIOUS_ACTIVITY_MESSAGE_DESCRIPTOR = msg({
message:
"Your account can't join {testersCommunityName} at the moment. Contact support if you think this is a mistake.",
comment: 'Body of the error modal shown when a flagged account is blocked from joining the canary testers community.',
});
const JOIN_FAILED_TITLE_DESCRIPTOR = msg({
message: "Couldn't join {testersCommunityName}",
comment: 'Title of the generic fallback error modal shown when joining the canary testers community fails.',
});
const JOIN_FAILED_MESSAGE_DESCRIPTOR = msg({
message: 'Something went wrong. Please try again in a moment.',
comment: 'Body of the generic fallback error modal shown when joining the canary testers community fails.',
});
function showCanaryJoinErrorModal(error: unknown, testersCommunityName: string): void {
const code = failureCode(error);
let title: string;
let message: string;
switch (code) {
case APIErrorCodes.CANARY_TESTER_EMAIL_VERIFICATION_REQUIRED:
case APIErrorCodes.EMAIL_VERIFICATION_REQUIRED:
title = i18nGlobal._(VERIFY_EMAIL_TITLE_DESCRIPTOR);
message = i18nGlobal._(VERIFY_EMAIL_MESSAGE_DESCRIPTOR, {testersCommunityName});
break;
case APIErrorCodes.ACCOUNT_TOO_NEW_FOR_GUILD:
title = i18nGlobal._(ACCOUNT_TOO_NEW_TITLE_DESCRIPTOR);
message = i18nGlobal._(ACCOUNT_TOO_NEW_MESSAGE_DESCRIPTOR, {testersCommunityName});
break;
case APIErrorCodes.ACCOUNT_SUSPICIOUS_ACTIVITY:
title = i18nGlobal._(SUSPICIOUS_ACTIVITY_TITLE_DESCRIPTOR);
message = i18nGlobal._(SUSPICIOUS_ACTIVITY_MESSAGE_DESCRIPTOR, {testersCommunityName});
break;
default:
title = i18nGlobal._(JOIN_FAILED_TITLE_DESCRIPTOR, {testersCommunityName});
message = i18nGlobal._(JOIN_FAILED_MESSAGE_DESCRIPTOR);
break;
}
ModalCommands.push(
modal(() => (
<GenericErrorModal
title={title}
message={message}
data-flx="app.app-layout.nagbars.canary-tester-cta-nagbar.join.generic-error-modal"
/>
)),
);
}
const JOIN_TESTERS_COMMUNITY_DESCRIPTOR = msg({
message: 'Join {testersCommunityName}',
comment: 'CTA button label for joining the canary testers community. testersCommunityName is a community name.',
});
const CANARY_TESTER_CTA_MESSAGE_DESCRIPTOR = msg({
message:
"You're on {canaryReleaseName}. Join {testersCommunityName} to submit bug reports and feedback about upcoming builds.",
comment:
'Nagbar body inviting canary release users to join the testers community. {canaryReleaseName} is the release channel name and {testersCommunityName} is the community name.',
});
export const CanaryTesterCtaNagbar = observer(({isMobile}: {isMobile: boolean}) => {
const {i18n} = useLingui();
const canaryReleaseChannelName = CANARY_RELEASE_CHANNEL_NAME;
const canaryTestersCommunityName = CANARY_TESTERS_COMMUNITY_NAME;
const [isSubmitting, setIsSubmitting] = useState(false);
const handleDismiss = () => {
dismissCanaryTesterCtaNagbar();
NagbarState.bumpCanaryTesterCtaDismissed();
};
const handleJoin = async () => {
if (isSubmitting) return;
setIsSubmitting(true);
try {
await CanaryTesterCommands.joinCanaryTesters();
ToastCommands.createToast({
type: 'success',
children: i18n._(JOINED_TESTERS_COMMUNITY_DESCRIPTOR, {
testersCommunityName: canaryTestersCommunityName,
canaryReleaseName: canaryReleaseChannelName,
}),
});
handleDismiss();
} catch (error) {
showCanaryJoinErrorModal(error, canaryTestersCommunityName);
} finally {
setIsSubmitting(false);
}
};
return (
<Nagbar
isMobile={isMobile}
backgroundColor="#fbbf24"
textColor="#1f2937"
onDismiss={handleDismiss}
dismissible={true}
data-flx="app.app-layout.nagbars.canary-tester-cta-nagbar.nagbar"
>
<NagbarContent
isMobile={isMobile}
onDismiss={handleDismiss}
message={i18n._(CANARY_TESTER_CTA_MESSAGE_DESCRIPTOR, {
canaryReleaseName: canaryReleaseChannelName,
testersCommunityName: canaryTestersCommunityName,
})}
actions={
<NagbarButton
isMobile={isMobile}
onClick={handleJoin}
submitting={isSubmitting}
disabled={isSubmitting}
data-flx="app.app-layout.nagbars.canary-tester-cta-nagbar.nagbar-button.join"
>
{i18n._(JOIN_TESTERS_COMMUNITY_DESCRIPTOR, {testersCommunityName: canaryTestersCommunityName})}
</NagbarButton>
}
data-flx="app.app-layout.nagbars.canary-tester-cta-nagbar.nagbar-content"
/>
</Nagbar>
);
});