feat(premium): add the Plutonium page behind an experiment (#3097)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-01 21:45:44 +02:00
1 parent 9a074adb11
commit be69333eaf
118 files changed
+18252 -2368

No files matched your search

@@ -5,6 +5,8 @@ import {MobileSettingsView} from '@app/features/app/components/dialogs/component
import * as Modal from '@app/features/app/components/dialogs/Modal';
import {SettingsModalContainer} from '@app/features/app/components/dialogs/shared/SettingsModalLayout';
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
import * as PlutoniumPageCommands from '@app/features/premium/commands/PlutoniumPageCommands';
import PlutoniumPageRollout from '@app/features/premium/state/PlutoniumPageRollout';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
import * as UnsavedChangesCommands from '@app/features/ui/commands/UnsavedChangesCommands';
import MobileLayout from '@app/features/ui/state/MobileLayout';
@@ -106,11 +108,26 @@ export const UserSettingsModal: React.FC<UserSettingsModalProps> = observer(
mobileNav.navigateBack();
}
}, [currentTab?.type, mobileNav, unsavedChangesState.unsavedChanges]);
const plutoniumPageEnabled = PlutoniumPageRollout.enabled;
const handleTabSelect = useCallback(
(tabType: string, title: string) => {
if (plutoniumPageEnabled && tabType === 'plutonium') {
PlutoniumPageCommands.openPlutoniumPage();
return;
}
mobileNav.navigateTo(tabType as UserSettingsTabType, title);
},
[mobileNav],
[mobileNav, plutoniumPageEnabled],
);
const handleDesktopTabSelect = useCallback(
(tabType: UserSettingsTabType) => {
if (plutoniumPageEnabled && tabType === 'plutonium') {
PlutoniumPageCommands.openPlutoniumPage();
return;
}
setSelectedTab(tabType);
},
[plutoniumPageEnabled],
);
const handleClose = useCallback(() => {
const checkTabId = selectedTab;
@@ -136,6 +153,10 @@ export const UserSettingsModal: React.FC<UserSettingsModalProps> = observer(
useEffect(() => {
const unsubscribe = ComponentBus.subscribe('USER_SETTINGS_TAB_SELECT', (args?: unknown) => {
const {tab, section} = (args ?? {}) as {tab?: string; section?: string};
if (plutoniumPageEnabled && tab === 'plutonium') {
PlutoniumPageCommands.openPlutoniumPage();
return;
}
if (tab && typeof tab === 'string') {
const accountSection =
getAccountSectionForNestedTab(tab as UserSettingsTabType) ?? getAccountSectionForLegacySection(section);
@@ -156,7 +177,7 @@ export const UserSettingsModal: React.FC<UserSettingsModalProps> = observer(
}
});
return unsubscribe;
}, [isMobile, mobileNav, resolveVisibleTab, visibleSettingsTabs]);
}, [isMobile, mobileNav, plutoniumPageEnabled, resolveVisibleTab, visibleSettingsTabs]);
return (
<SettingsContentKeyProvider data-flx="user.user-settings-modal.settings-content-key-provider">
<Modal.Root size="fullscreen" onClose={handleModalClose} data-flx="user.user-settings-modal.modal-root">
@@ -183,7 +204,7 @@ export const UserSettingsModal: React.FC<UserSettingsModalProps> = observer(
groupedSettingsTabs={groupedSettingsTabs}
currentTab={currentTab}
selectedTab={selectedTab}
onTabSelect={setSelectedTab}
onTabSelect={handleDesktopTabSelect}
initialGuildId={initialGuildId}
initialSubtab={normalizedInitialSubtab}
pendingSection={pendingSection}
@@ -1,10 +1,31 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {PlutoniumContent} from '@app/features/app/components/dialogs/components/PlutoniumContent';
import * as PlutoniumPageCommands from '@app/features/premium/commands/PlutoniumPageCommands';
import {PlutoniumPageLinkCard} from '@app/features/premium/components/plutonium_page/PlutoniumPageLinkCard';
import PlutoniumPageRollout from '@app/features/premium/state/PlutoniumPageRollout';
import {observer} from 'mobx-react-lite';
import type React from 'react';
import {useEffect} from 'react';
const PlutoniumPageRedirect: React.FC = () => {
useEffect(() => {
PlutoniumPageCommands.openPlutoniumPage();
}, []);
return <PlutoniumPageLinkCard data-flx="user.plutonium-tab.plutonium-page-link-card" />;
};
const PlutoniumTab: React.FC = observer(() => {
if (PlutoniumPageRollout.enabled) {
return <PlutoniumPageRedirect data-flx="user.plutonium-tab.plutonium-page-redirect" />;
}
return <PlutoniumContent data-flx="user.plutonium-tab.plutonium-content" />;
});
export const PlutoniumInlineTab: React.FC = observer(() => {
if (PlutoniumPageRollout.enabled) {
return <PlutoniumPageLinkCard data-flx="user.plutonium-tab.inline.plutonium-page-link-card" />;
}
return <PlutoniumContent data-flx="user.plutonium-tab.plutonium-content" />;
});
@@ -5,6 +5,7 @@ import {PREMIUM_PRODUCT_FULL_NAME, PRODUCT_NAME} from '@app/features/app/config/
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {cdnUrl} from '@app/features/messaging/utils/MessagingUrlUtils';
import * as PremiumModalCommands from '@app/features/premium/commands/PremiumModalCommands';
import PlutoniumPageRollout from '@app/features/premium/state/PlutoniumPageRollout';
import {shouldShowPremiumFeatures} from '@app/features/premium/utils/PremiumUtils';
import FocusRing from '@app/features/ui/focus_ring/FocusRing';
import {Tooltip} from '@app/features/ui/tooltip/Tooltip';
@@ -93,6 +94,7 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
const selfHosted = RuntimeConfig.isSelfHosted();
const showPremium = shouldShowPremiumFeatures();
const premiumInfoUrl = RuntimeConfig.premiumInfoUrl;
const plutoniumPageEnabled = PlutoniumPageRollout.enabled;
const badges = useMemo(() => {
const result: Array<Badge> = [];
if (user.flags & PublicUserFlags.STAFF) {
@@ -124,7 +126,8 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
}
if (showPremium && profile?.premiumType && profile.premiumType !== UserPremiumTypes.NONE) {
let tooltipText = PREMIUM_PRODUCT_FULL_NAME;
let badgeUrl: string | undefined = premiumInfoUrl ?? (selfHosted ? undefined : Routes.plutonium());
let badgeUrl: string | undefined =
premiumInfoUrl ?? (selfHosted || plutoniumPageEnabled ? undefined : Routes.plutonium());
const badgeOnClick = badgeUrl ? undefined : () => PremiumModalCommands.open();
if (!selfHosted && profile.premiumType === UserPremiumTypes.LIFETIME) {
if (profile.premiumSince) {
@@ -169,6 +172,7 @@ export const UserProfileBadges: React.FC<UserProfileBadgesProps> = observer(
selfHosted,
showPremium,
premiumInfoUrl,
plutoniumPageEnabled,
user.flags,
profile?.premiumType,
profile?.premiumSince,