feat(profile): move profile timezone from staff to an experiment (#3011)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-28 12:57:26 +02:00
1 parent dd8ed6f205
commit 564c5ae164
67 files changed
+843 -554

No files matched your search

@@ -8,7 +8,6 @@ import {PREMIUM_PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstant
import {useFormSubmit} from '@app/features/app/hooks/useFormSubmit';
import {LimitResolver} from '@app/features/app/utils/LimitResolverAdapter';
import {isLimitToggleEnabled} from '@app/features/app/utils/LimitUtils';
import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions';
import type {FlatEmoji} from '@app/features/emoji/types/EmojiTypes';
import {ExpressionPickerSheet} from '@app/features/expressions/components/modals/ExpressionPickerSheet';
import Guilds from '@app/features/guild/state/Guilds';
@@ -54,6 +53,7 @@ import {ProfileTypeSelector} from '@app/features/user/components/modals/tabs/my_
import {TimezoneProfileSettings} from '@app/features/user/components/modals/tabs/my_profile_tab/TimezoneProfileSettings';
import {ProfilePreview} from '@app/features/user/components/profile/ProfilePreview';
import type {Profile} from '@app/features/user/models/Profile';
import ProfileTimezoneRollout from '@app/features/user/state/ProfileTimezoneRollout';
import Users from '@app/features/user/state/Users';
import * as NicknameUtils from '@app/features/user/utils/NicknameUtils';
import {setMeaningfulFormValue} from '@app/lib/forms/MeaningfulFormValue';
@@ -411,7 +411,7 @@ const MyProfileTabComponent = observer(function MyProfileTabComponent({
);
const showPremiumFeatures = shouldShowPremiumFeatures();
const hasPremium = useMemo(() => showPremiumFeatures && (user?.isPremium() ?? false), [showPremiumFeatures, user]);
const hasProfileTimezoneAccess = (user?.isStaff() ?? false) && DeveloperOptions.showProfileTimezoneSettings;
const hasProfileTimezoneAccess = ProfileTimezoneRollout.enabled;
const hasPerGuildProfiles = useMemo(
() =>
isLimitToggleEnabled(
+8 -13
View File
@@ -203,12 +203,10 @@ export class User {
this.bannerColor = hasKey(user, 'banner_color') ? (user.banner_color ?? null) : undefined;
this.pronouns = hasKey(user, 'pronouns') ? (user.pronouns ?? null) : undefined;
this.accentColor = hasKey(user, 'accent_color') ? (user.accent_color ?? null) : undefined;
const hasProfileTimezoneAccess = this._isStaff ?? (this.flags & PublicUserFlags.STAFF) !== 0;
this.timezone = hasProfileTimezoneAccess && hasKey(user, 'timezone') ? (user.timezone ?? null) : undefined;
this.timezonePrivacyFlags =
hasProfileTimezoneAccess && hasKey(user, 'timezone_privacy_flags')
? (user.timezone_privacy_flags ?? ProfileFieldPrivacyFlags.EVERYONE)
: undefined;
this.timezone = hasKey(user, 'timezone') ? (user.timezone ?? null) : undefined;
this.timezonePrivacyFlags = hasKey(user, 'timezone_privacy_flags')
? (user.timezone_privacy_flags ?? ProfileFieldPrivacyFlags.EVERYONE)
: undefined;
this.mfaEnabled = hasKey(user, 'mfa_enabled') ? user.mfa_enabled : undefined;
this.hasVerifiedPhone = hasKey(user, 'has_verified_phone') ? user.has_verified_phone : undefined;
this.authenticatorTypes = hasKey(user, 'authenticator_types')
@@ -420,13 +418,10 @@ export class User {
if (pronouns !== undefined) result.pronouns = pronouns;
const accentColor = pickField(this.accentColor, u, 'accent_color', opts);
if (accentColor !== undefined) result.accent_color = accentColor;
const hasProfileTimezoneAccess = isStaff ?? (result.flags & PublicUserFlags.STAFF) !== 0;
if (hasProfileTimezoneAccess) {
const timezone = pickField(this.timezone, u, 'timezone', opts);
if (timezone !== undefined) result.timezone = timezone;
const timezonePrivacyFlags = pickField(this.timezonePrivacyFlags, u, 'timezone_privacy_flags', opts);
if (timezonePrivacyFlags !== undefined) result.timezone_privacy_flags = timezonePrivacyFlags;
}
const timezone = pickField(this.timezone, u, 'timezone', opts);
if (timezone !== undefined) result.timezone = timezone;
const timezonePrivacyFlags = pickField(this.timezonePrivacyFlags, u, 'timezone_privacy_flags', opts);
if (timezonePrivacyFlags !== undefined) result.timezone_privacy_flags = timezonePrivacyFlags;
const mfaEnabled = pickField(this.mfaEnabled, u, 'mfa_enabled', opts);
if (mfaEnabled !== undefined) result.mfa_enabled = mfaEnabled;
const hasVerifiedPhone = pickField(this.hasVerifiedPhone, u, 'has_verified_phone', opts);
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import ExperimentAssignments from '@app/features/experiment/state/ExperimentAssignments';
import {Logger} from '@app/features/platform/utils/AppLogger';
import {readProfileTimezoneAssignment} from '@fluxer/schema/src/domains/experiment/ExperimentSchemas';
const logger = new Logger('ProfileTimezoneRollout');
class ProfileTimezoneRolloutSelector {
get enabled(): boolean {
try {
return readProfileTimezoneAssignment(ExperimentAssignments.response).enabled;
} catch (err) {
logger.warn('Failed to resolve profile timezone assignment:', err);
return false;
}
}
}
export const ProfileTimezoneRollout = new ProfileTimezoneRolloutSelector();
export default ProfileTimezoneRollout;
@@ -2,6 +2,7 @@
import {Profile} from '@app/features/user/models/Profile';
import type {User} from '@app/features/user/models/User';
import ProfileTimezoneRollout from '@app/features/user/state/ProfileTimezoneRollout';
import {ProfileFieldPrivacyFlags, UserPremiumTypes} from '@fluxer/constants/src/UserConstants';
import {getCurrentTimeZoneOffsetMinutes} from '@fluxer/date_utils/src/TimeZoneUtils';
@@ -96,7 +97,7 @@ export function createMockProfile(
timezone_offset:
options?.previewTimezoneOffset !== undefined
? options.previewTimezoneOffset
: user.isStaff() && (user.timezonePrivacyFlags ?? ProfileFieldPrivacyFlags.EVERYONE) !== 0
: ProfileTimezoneRollout.enabled && (user.timezonePrivacyFlags ?? ProfileFieldPrivacyFlags.EVERYONE) !== 0
? getCurrentTimeZoneOffsetMinutes(user.timezone)
: null,
premium_type: visiblePremiumData.premiumType ?? undefined,