fix(self-hosting): use instance contacts and live product name (#3333)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-09 01:39:35 +02:00
1 parent 454fefdb92
commit a5c1362f4a
308 files changed
+16533 -13512

No files matched your search

@@ -5,7 +5,6 @@ import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {
PAYMENT_PROVIDER_NAME,
PIX_PAYMENT_METHOD,
PRODUCT_NAME,
SUPPORT_EMAIL,
UPI_PAYMENT_METHOD,
} from '@app/features/app/config/I18nDisplayConstants';
@@ -154,6 +153,11 @@ const PLAN_UNAVAILABLE_TOAST_DESCRIPTOR = msg({
message: "This plan isn't available. Contact support.",
comment: 'Error modal body shown when the selected Plutonium plan has no price ID configured.',
});
const PLAN_UNAVAILABLE_SELF_HOSTED_TOAST_DESCRIPTOR = msg({
message: "This plan isn't available. Contact the administrators of this instance.",
comment:
'Error modal body shown on a self-hosted instance when the selected Plutonium plan has no price ID configured.',
});
const COMPLETE_PAYMENT_MODAL_TITLE_DESCRIPTOR = msg({
message: 'Complete payment',
comment: 'Modal title for the mobile checkout confirmation when opening the payment provider in a browser.',
@@ -438,7 +442,11 @@ export const useCheckoutActions = (
if (!priceId) {
logger.error('Price ID not available for plan', {plan});
showCheckoutPlanErrorModal(
i18n._(PLAN_UNAVAILABLE_TOAST_DESCRIPTOR),
i18n._(
RuntimeConfig.isSelfHosted()
? PLAN_UNAVAILABLE_SELF_HOSTED_TOAST_DESCRIPTOR
: PLAN_UNAVAILABLE_TOAST_DESCRIPTOR,
),
'app.plutonium.use-checkout-actions.plan-unavailable.generic-error-modal',
);
return;
@@ -459,7 +467,7 @@ export const useCheckoutActions = (
title={i18n._(COMPLETE_PAYMENT_MODAL_TITLE_DESCRIPTOR)}
description={i18n._(COMPLETE_PAYMENT_MODAL_BODY_DESCRIPTOR, {
paymentProviderName: PAYMENT_PROVIDER_NAME,
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})}
primaryText={i18n._(OKAY_DESCRIPTOR)}
primaryVariant="primary"
@@ -9,7 +9,7 @@ import {GuildNavbar} from '@app/features/app/components/layout/GuildNavbar';
import {Nagbar} from '@app/features/app/components/layout/Nagbar';
import {NagbarButton} from '@app/features/app/components/layout/NagbarButton';
import {GuildSidebarSkeleton} from '@app/features/app/components/skeleton/GuildSidebarSkeleton';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import Accounts from '@app/features/auth/state/Accounts';
import {MatureContentChannelGate} from '@app/features/channel/components/MatureContentChannelGate';
import Channels from '@app/features/channel/state/Channels';
@@ -160,7 +160,7 @@ const InvitesDisabledNagbar = observer(({isMobile, guildId}: {isMobile: boolean;
{isRaidDetected
? i18n._(INVITES_DISABLED_RAID_MESSAGE_DESCRIPTOR, {
communityName: guild.name,
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})
: i18n._(INVITES_DISABLED_MESSAGE_DESCRIPTOR, {communityName: guild.name})}
</p>
@@ -278,7 +278,7 @@ const StaffOnlyGuildNagbar = observer(({isMobile, guildId}: {isMobile: boolean;
<p className={styles.nagbarText} data-flx="app.guild-layout.staff-only-guild-nagbar.nagbar-text">
{i18n._(STAFF_ONLY_GUILD_MESSAGE_DESCRIPTOR, {
communityName: guild.name,
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})}
</p>
<div
@@ -4,7 +4,7 @@ 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 Config from '@app/features/app/config/Config';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import NagbarController from '@app/features/ui/state/Nagbar';
import {msg} from '@lingui/core/macro';
import {useLingui} from '@lingui/react/macro';
@@ -31,7 +31,7 @@ export function BuildEnvironmentNagbar({isMobile}: {isMobile: boolean}) {
onDismiss={NagbarController.dismissBuildEnvironmentNagbar}
message={i18n._(BUILD_ENVIRONMENT_MESSAGE_DESCRIPTOR, {
releaseChannel: Config.PUBLIC_RELEASE_CHANNEL,
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
})}
data-flx="app.app-layout.nagbars.build-environment-nagbar.nagbar-content"
/>
@@ -4,7 +4,8 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {DESKTOP_DOWNLOAD_URL, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {DESKTOP_DOWNLOAD_URL} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {openExternalUrl} from '@app/features/ui/utils/NativeUtils';
import {msg} from '@lingui/core/macro';
import {useLingui} from '@lingui/react/macro';
@@ -39,7 +40,7 @@ export const CorruptedInstallationNagbar = observer(({isMobile}: {isMobile: bool
onClick={handleDownload}
data-flx="app.app-layout.nagbars.corrupted-installation-nagbar.nagbar-button.download"
>
{i18n._(DOWNLOAD_PRODUCT_DESCRIPTOR, {productName: PRODUCT_NAME})}
{i18n._(DOWNLOAD_PRODUCT_DESCRIPTOR, {productName: RuntimeConfig.productName})}
</NagbarButton>
}
data-flx="app.app-layout.nagbars.corrupted-installation-nagbar.nagbar-content"
@@ -5,7 +5,8 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {DESKTOP_DOWNLOAD_URL, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {DESKTOP_DOWNLOAD_URL} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {DOWNLOAD_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import * as NagbarCommands from '@app/features/ui/commands/NagbarCommands';
import {openExternalUrl} from '@app/features/ui/utils/NativeUtils';
@@ -38,7 +39,7 @@ export const DesktopDownloadNagbar = observer(({isMobile}: {isMobile: boolean})
<NagbarContent
isMobile={isMobile}
onDismiss={handleDismiss}
message={i18n._(DESKTOP_APP_DOWNLOAD_MESSAGE_DESCRIPTOR, {productName: PRODUCT_NAME})}
message={i18n._(DESKTOP_APP_DOWNLOAD_MESSAGE_DESCRIPTOR, {productName: RuntimeConfig.productName})}
actions={
<>
<span
@@ -6,7 +6,7 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {ENABLE_NOTIFICATIONS_DESCRIPTOR, OKAY_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {usePushSubscriptions} from '@app/features/notification/hooks/usePushSubscriptions';
import * as NotificationUtils from '@app/features/notification/utils/NotificationUtils';
@@ -142,7 +142,7 @@ export const DesktopNotificationNagbar = observer(({isMobile}: {isMobile: boolea
onDismiss={handleDismiss}
message={
isPwaMobile
? i18n._(ENABLE_PUSH_NOTIFICATIONS_MESSAGE_DESCRIPTOR, {productName: PRODUCT_NAME})
? i18n._(ENABLE_PUSH_NOTIFICATIONS_MESSAGE_DESCRIPTOR, {productName: RuntimeConfig.productName})
: i18n._(ENABLE_DESKTOP_NOTIFICATIONS_MESSAGE_DESCRIPTOR)
}
actions={
@@ -5,7 +5,6 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {
installDomainMovedApp,
openDomainMovedBrowserMigration,
@@ -16,6 +15,7 @@ import {
type DomainMovedStepsPlatform,
showDomainMovedStepsModal,
} from '@app/features/app/domain_migration/DomainMovedStepsModal';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import * as RouterUtils from '@app/features/navigation/utils/RouterUtils';
import {isIOSMobileOrTabletUserAgent} from '@app/features/platform/notifications/NotificationAlertOptions';
import {msg} from '@lingui/core/macro';
@@ -112,7 +112,7 @@ export const DomainMovedNagbar = observer(({isMobile}: {isMobile: boolean}) => {
RouterUtils.transitionTo(`${Routes.LOGIN}?handoff=1`);
}, []);
const tone = NAGBAR_TONES[NagbarToneKind.BRAND];
const values = {productName: PRODUCT_NAME, host: DomainMovedNotice.targetHost};
const values = {productName: RuntimeConfig.productName, host: DomainMovedNotice.targetHost};
const linkDeviceButton = (
<NagbarButton
isMobile={isMobile}
@@ -4,7 +4,6 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {PRODUCT_HQ_COMMUNITY_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import Authentication from '@app/features/auth/state/Authentication';
import Guilds from '@app/features/guild/state/Guilds';
@@ -79,6 +78,7 @@ export const GuildMembershipCtaNagbar = observer(({isMobile}: {isMobile: boolean
const handleDismiss = () => {
NagbarState.guildMembershipCtaDismissed = true;
};
const communityName = `${RuntimeConfig.productName} HQ`;
return (
<Nagbar
isMobile={isMobile}
@@ -92,7 +92,7 @@ export const GuildMembershipCtaNagbar = observer(({isMobile}: {isMobile: boolean
isMobile={isMobile}
onDismiss={handleDismiss}
message={i18n._(JOIN_PRODUCT_COMMUNITY_MESSAGE_DESCRIPTOR, {
communityName: PRODUCT_HQ_COMMUNITY_NAME,
communityName,
})}
actions={
<NagbarButton
@@ -102,7 +102,7 @@ export const GuildMembershipCtaNagbar = observer(({isMobile}: {isMobile: boolean
disabled={isSubmitting}
data-flx="app.app-layout.nagbars.guild-membership-cta-nagbar.nagbar-button.join-guild"
>
{i18n._(JOIN_PRODUCT_COMMUNITY_BUTTON_DESCRIPTOR, {communityName: PRODUCT_HQ_COMMUNITY_NAME})}
{i18n._(JOIN_PRODUCT_COMMUNITY_BUTTON_DESCRIPTOR, {communityName})}
</NagbarButton>
}
data-flx="app.app-layout.nagbars.guild-membership-cta-nagbar.nagbar-content"
@@ -5,7 +5,7 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {ENABLE_TWO_FACTOR_AUTH_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
import {modal} from '@app/features/ui/commands/ModalCommands';
@@ -51,7 +51,7 @@ export const VisionaryMfaNagbar = observer(({isMobile}: {isMobile: boolean}) =>
<NagbarContent
isMobile={isMobile}
onDismiss={handleDismiss}
message={i18n._(VISIONARY_MFA_MESSAGE_DESCRIPTOR, {productName: PRODUCT_NAME})}
message={i18n._(VISIONARY_MFA_MESSAGE_DESCRIPTOR, {productName: RuntimeConfig.productName})}
actions={
<NagbarButton
isMobile={isMobile}
@@ -4,7 +4,7 @@ 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 {NAGBAR_TONES, NagbarToneKind} from '@app/features/app/components/layout/NagbarTones';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import Authentication from '@app/features/auth/state/Authentication';
import type {Channel} from '@app/features/channel/models/Channel';
import Channels from '@app/features/channel/state/Channels';
@@ -51,7 +51,7 @@ function getRestoreNagbarMessage(channel: Channel, i18n: I18n): string | null {
if (!CallState.hasActiveCall(channel.id)) return null;
const directCallName = getVoiceSessionRestoreChannelDisplayName(channel, '');
return i18n._(DIRECT_CALL_VOICE_SESSION_RESTORE_MESSAGE_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
directCallName,
});
}
@@ -61,7 +61,7 @@ function getRestoreNagbarMessage(channel: Channel, i18n: I18n): string | null {
const communityName = guild?.name.trim() ?? '';
if (!channelName || !communityName) return null;
return i18n._(COMMUNITY_VOICE_SESSION_RESTORE_MESSAGE_DESCRIPTOR, {
productName: PRODUCT_NAME,
productName: RuntimeConfig.productName,
channelName,
communityName,
});
@@ -3,10 +3,11 @@
import Accessibility from '@app/features/accessibility/state/Accessibility';
import guildStyles from '@app/features/app/components/layout/GuildsLayout.module.css';
import styles from '@app/features/app/components/layout/sidebar_nav/DownloadButton.module.css';
import {DESKTOP_DOWNLOAD_URL, PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {DESKTOP_DOWNLOAD_URL} from '@app/features/app/config/I18nDisplayConstants';
import {useContextMenuHoverState} from '@app/features/app/hooks/useContextMenuHoverState';
import {useHover} from '@app/features/app/hooks/useHover';
import {useMergeRefs} from '@app/features/app/hooks/useMergeRefs';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import HiddenGuildListButtons from '@app/features/guild/state/HiddenGuildListButtons';
import {openExternalUrlWithWarning} from '@app/features/messaging/utils/ExternalLinkUtils';
import {MenuGroup} from '@app/features/ui/action_menu/MenuGroup';
@@ -73,7 +74,7 @@ export const DownloadButton = observer(() => {
<Tooltip
position="right"
size="large"
text={() => i18n._(DOWNLOAD_DESCRIPTOR, {productName: PRODUCT_NAME})}
text={() => i18n._(DOWNLOAD_DESCRIPTOR, {productName: RuntimeConfig.productName})}
data-flx="app.sidebar-nav.download-button.tooltip"
>
<FocusRing
@@ -84,7 +85,7 @@ export const DownloadButton = observer(() => {
>
<button
type="button"
aria-label={i18n._(DOWNLOAD_DESCRIPTOR, {productName: PRODUCT_NAME})}
aria-label={i18n._(DOWNLOAD_DESCRIPTOR, {productName: RuntimeConfig.productName})}
data-guild-list-focus-item="true"
onClick={handleDownload}
onContextMenu={handleContextMenu}
@@ -36,11 +36,12 @@ export const HelpButton = observer(() => {
const itemRef = useRef<HTMLElement | null>(null);
const contextMenuOpen = useContextMenuHoverState(itemRef);
const mergedButtonRef = useMergeRefs([hoverRef, buttonRef, itemRef]);
if (HiddenGuildListButtons.helpButtonHidden) {
const helpUrl = Routes.help();
if (HiddenGuildListButtons.helpButtonHidden || !helpUrl) {
return null;
}
const handleHelp = () => {
openExternalUrlWithWarning(Routes.help());
openExternalUrlWithWarning(helpUrl);
};
const handleContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
@@ -12,7 +12,7 @@
-webkit-user-select: none;
}
.footnote:hover {
.footnote[href]:hover {
text-decoration: underline;
}
@@ -28,7 +28,7 @@
-webkit-user-select: none;
}
.inlineFootnote:hover {
.inlineFootnote[href]:hover {
color: var(--text-tertiary) !important;
text-decoration: underline;
}
@@ -46,10 +46,22 @@ export const ExpiryFootnote: FC<ExpiryFootnoteProps> = ({expiresAt, isExpired, l
return null;
}
}
const footnoteClassName = clsx(inline ? styles.inlineFootnote : styles.footnote, className);
if (!helpUrl) {
return (
<span
className={footnoteClassName}
data-message-copy-hidden="true"
data-flx="app.expiry-footnote.inline-footnote.text"
>
{resolved}
</span>
);
}
return (
<FocusRing data-flx="app.expiry-footnote.focus-ring">
<a
className={clsx(inline ? styles.inlineFootnote : styles.footnote, className)}
className={footnoteClassName}
href={helpUrl}
onContextMenu={handleContextMenu}
target="_blank"
@@ -25,7 +25,7 @@ export const ExpiryFootnoteContextMenu: FC = () => {
AccessibilityCommands.update({showAttachmentExpiryIndicator: false});
}, []);
const handleOpenHelpCenter = useCallback(() => {
void openExternalUrl(helpUrl);
if (helpUrl) void openExternalUrl(helpUrl);
}, [helpUrl]);
return (
<MenuGroup data-flx="app.expiry-footnote-context-menu.menu-group">
@@ -6,9 +6,6 @@ import {formatAssetUploadExtensions, formatKnownAnimatedAssetExtensions} from '@
import {THE_OTHER_PLATFORM} from '@fluxer/constants/src/ExternalPlatformConstants';
export {PRODUCT_NAME};
export const PRODUCT_API_NAME = `${PRODUCT_NAME} API`;
export const PRODUCT_HQ_COMMUNITY_NAME = `${PRODUCT_NAME} HQ`;
export const CANARY_RELEASE_CHANNEL_NAME = `${PRODUCT_NAME} Canary`;
export const DESKTOP_ENTRY_NAME = 'Fluxer';
export const CANARY_DESKTOP_ENTRY_NAME = 'Fluxer Canary';
export const VOICE_PROVIDER_NAME = 'LiveKit';
@@ -19,10 +16,8 @@ export const GOOGLE_PLAY_NAME = 'Google Play';
export const PIX_PAYMENT_METHOD = 'Pix';
export const UPI_PAYMENT_METHOD = 'UPI';
export const BLIK_PAYMENT_METHOD = 'BLIK';
export const SUPPORT_EMAIL = 'support@fluxer.app';
export const SUPPORT_EMAIL = 'support@fluxer.com';
export const SUPPORT_EMAIL_MAILTO = `mailto:${SUPPORT_EMAIL}`;
export const I18N_EMAIL = '[email protected]';
export const I18N_EMAIL_MAILTO = `mailto:${I18N_EMAIL}`;
export const I18N_WEBLATE_DOMAIN = 'weblate.fluxer.tools';
export const I18N_WEBLATE_URL = `https://${I18N_WEBLATE_DOMAIN}`;
export const EXAMPLE_DOMAIN = 'example.com';
@@ -30,9 +25,9 @@ export const EXAMPLE_URL = `https://${EXAMPLE_DOMAIN}`;
export const EXAMPLE_CALLBACK_URL = `${EXAMPLE_URL}/callback`;
export const EXAMPLE_EMAIL = '[email protected]';
export const EXAMPLE_PERSONAL_EMAIL = '[email protected]';
export const EXAMPLE_USERNAME_TAG = 'Username#0000';
export const EXAMPLE_REPORT_EMAIL = '[email protected]';
export const EXAMPLE_REPORT_USER_TAG = 'username#1234';
export const EXAMPLE_REPORT_USERNAME = 'username';
export const EXAMPLE_INVITE_CODE = 'abcDEF12';
export const EXAMPLE_VERIFICATION_CODE = 'ABCD-1234';
export const EXAMPLE_FLUXER_TAG = 'Marty_McFly';
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import * as Modal from '@app/features/app/components/dialogs/Modal';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import styles from '@app/features/app/domain_migration/DomainMovedStepsModal.module.css';
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
import {CLOSE_DESCRIPTOR, COPY_LINK_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
import {Button} from '@app/features/ui/button/Button';
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
@@ -81,7 +81,7 @@ interface DomainMovedStepsModalProps {
function DomainMovedStepsModal({target, platform}: DomainMovedStepsModalProps) {
const {i18n} = useLingui();
const host = new URL(target).host;
const values = {host, productName: PRODUCT_NAME};
const values = {host, productName: RuntimeConfig.productName};
const [first, second, third] = PLATFORM_STEPS[platform];
const handleCopy = useCallback(() => {
void TextCopyCommands.copy(i18n, `${target}/`);
@@ -183,7 +183,9 @@ export function registerDefaultKeybindHandlers(host: HandlerHost, i18n: I18n): v
}
host.register('misc_help', ({type}) => {
if (type !== 'press') return;
openExternalUrlWithWarning(Routes.help());
const helpUrl = Routes.help();
if (!helpUrl) return;
openExternalUrlWithWarning(helpUrl);
});
host.register('misc_search', ({type}) => {
if (type !== 'press') return;
@@ -210,7 +210,7 @@ describe('runtimeSnapshotFromDiscovery', () => {
document.app_public = {
...BOOTSTRAP_APP_PUBLIC,
branding: {...BOOTSTRAP_APP_PUBLIC.branding, icon_url: 'https://cdn.d.test/icon.png?v=3'},
legal: {terms_url: 'https://d.test/legal?doc=terms', privacy_url: null},
legal: {terms_url: 'https://d.test/legal?doc=terms', privacy_url: null, guidelines_url: null},
};
const snapshot = runtimeSnapshotFromDiscovery(parseInstanceDiscoveryDocument(document));
expect(snapshot.appPublic.branding.icon_url).toBe('https://cdn.d.test/icon.png?v=3');
@@ -815,6 +815,10 @@ class RuntimeConfig {
return this.appPublic.branding.product_name;
}
get premiumProductFullName(): string {
return `${this.productName} ${this.premiumProductName}`;
}
get iconUrl(): string | null {
return this.appPublic.branding.icon_url;
}
@@ -847,6 +851,10 @@ class RuntimeConfig {
return this.appPublic.legal.privacy_url;
}
get guidelinesUrl(): string | null {
return this.appPublic.legal.guidelines_url;
}
get collectDateOfBirthOnRegistration(): boolean {
return this.appPublic.registration.collect_date_of_birth;
}
@@ -422,6 +422,10 @@ function readAppPublic(value: unknown): InstanceAppPublic {
legal: {
terms_url: readNullableAbsoluteHttpUrl(legal, 'terms_url', 'appPublic.legal.terms_url'),
privacy_url: readNullableAbsoluteHttpUrl(legal, 'privacy_url', 'appPublic.legal.privacy_url'),
guidelines_url:
legal['guidelines_url'] === undefined
? null
: readNullableAbsoluteHttpUrl(legal, 'guidelines_url', 'appPublic.legal.guidelines_url'),
},
registration: {
collect_date_of_birth: readBoolean(