[web] Use React hooks to get split-test variants instead of getSplitTestVariant (getMeta) (#18133)

* Fix split-tests loading in React component: use `useSplitTestContext` instead of `getSplitTestVariant`

* Replace use of `isSplitTestEnabled` by `useSplitTestContext`

* Add SplitTestProvider to roots, and fix tests

* Create `useFeatureFlag` hook

* Use `useFeatureFlag` where applicable

GitOrigin-RevId: 9ff7bb3975d50bc4d07d74d93c482d56dc96f615
This commit is contained in:
Antoine Clausse 2024-04-30 16:58:34 +02:00 committed by Copybot
parent ebb34b40c1
commit 6a6f155029
17 changed files with 105 additions and 79 deletions

View file

@ -4,7 +4,7 @@ import { useCallback, useEffect, useState } from 'react'
import * as eventTracking from '../../../../infrastructure/event-tracking'
import StartFreeTrialButton from '../../../../shared/components/start-free-trial-button'
import { paywallPrompt } from '../../../../main/account-upgrade'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function FeatureItem({ text }: { text: string }) {
return (
@ -18,8 +18,7 @@ export function OwnerPaywallPrompt() {
const { t } = useTranslation()
const [clickedFreeTrialButton, setClickedFreeTrialButton] = useState(false)
const { splitTestVariants } = useSplitTestContext()
const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
useEffect(() => {
eventTracking.send('subscription-funnel', 'editor-click-feature', 'history')

View file

@ -6,7 +6,7 @@ import ToolbarFileInfo from './toolbar-file-info'
import ToolbarRestoreFileButton from './toolbar-restore-file-button'
import { isFileRemoved } from '../../../utils/file-diff'
import ToolbarRevertFileButton from './toolbar-revert-file-button'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
type ToolbarProps = {
diff: Nullable<Diff>
@ -14,13 +14,13 @@ type ToolbarProps = {
}
export default function Toolbar({ diff, selection }: ToolbarProps) {
const { splitTestVariants } = useSplitTestContext()
const hasRevertFiles = useFeatureFlag('revert-files')
const showRestoreFileButton =
selection.selectedFile && isFileRemoved(selection.selectedFile)
const showRevertFileButton =
splitTestVariants['revert-file'] === 'enabled' &&
hasRevertFiles &&
selection.selectedFile &&
!isFileRemoved(selection.selectedFile)

View file

@ -2,15 +2,14 @@ import Notification from '@/shared/components/notification'
import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
import { useTranslation } from 'react-i18next'
import { FC } from 'react'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
export const CompileTimeWarningUpgradePromptInner: FC<{
handleDismissWarning: () => void
}> = ({ handleDismissWarning }) => {
const { t } = useTranslation()
const { splitTestVariants } = useSplitTestContext()
const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
return (
<Notification

View file

@ -6,7 +6,7 @@ import PdfLogEntry from './pdf-log-entry'
import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
import { Button } from 'react-bootstrap'
import * as eventTracking from '../../../infrastructure/event-tracking'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function TimeoutUpgradePromptNew() {
const {
@ -49,8 +49,7 @@ const CompileTimeout = memo(function CompileTimeout({
}: CompileTimeoutProps) {
const { t } = useTranslation()
const { splitTestVariants } = useSplitTestContext()
const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
return (
<PdfLogEntry

View file

@ -5,7 +5,7 @@ import { useSSOContext, SSOSubscription } from '../context/sso-context'
import { SSOLinkingWidget } from './linking/sso-widget'
import getMeta from '../../../utils/meta'
import { useBroadcastUser } from '@/shared/hooks/user-channel/use-broadcast-user'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import NotificationWrapper from '@/features/ui/components/bootstrap-5/notification-wrapper'
function LinkingSection() {
@ -51,16 +51,12 @@ function LinkingSection() {
// currently the only thing that is in the langFeedback section is writefull,
// which is behind a split test. we should hide this section if the user is not in the split test
// todo: remove split test check, and split test context after gradual rollout is complete
const {
splitTestVariants,
}: { splitTestVariants: Record<string, string | undefined> } =
useSplitTestContext()
const hasWritefullOauthPromotion = useFeatureFlag('writefull-oauth-promotion')
// even if they arent in the split test, if they have it enabled let them toggle it off
const user = getMeta('ol-user')
const shouldLoadWritefull =
(splitTestVariants['writefull-oauth-promotion'] === 'enabled' ||
user.writefull?.enabled === true) &&
(hasWritefullOauthPromotion || user.writefull?.enabled === true) &&
!window.writefull // check if the writefull extension is installed, in which case we dont handle the integration
const haslangFeedbackLinkingWidgets =

View file

@ -5,16 +5,14 @@ import { useUserContext } from '../../../shared/context/user-context'
import { upgradePlan } from '../../../main/account-upgrade'
import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
import Icon from '../../../shared/components/icon'
import { useSplitTestContext } from '../../../shared/context/split-test-context'
import { useFeatureFlag } from '../../../shared/context/split-test-context'
export default function AddCollaboratorsUpgrade() {
const { t } = useTranslation()
const user = useUserContext()
const [startedFreeTrial, setStartedFreeTrial] = useState(false)
const { splitTestVariants } = useSplitTestContext()
const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
return (
<div className="add-collaborators-upgrade">

View file

@ -6,7 +6,7 @@ import { useProjectContext } from '../../../../shared/context/project-context'
import { useUserContext } from '../../../../shared/context/user-context'
import { startFreeTrial, upgradePlan } from '../../../../main/account-upgrade'
import { memo } from 'react'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
type UpgradeTrackChangesModalProps = {
show: boolean
@ -21,8 +21,7 @@ function UpgradeTrackChangesModal({
const project = useProjectContext()
const user = useUserContext()
const { splitTestVariants } = useSplitTestContext()
const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
return (
<AccessibleModal show={show} onHide={() => setShow(false)}>

View file

@ -14,7 +14,7 @@ import { Button, Overlay, Popover } from 'react-bootstrap'
import Close from '../../../../../shared/components/close'
import { postJSON } from '../../../../../infrastructure/fetch-json'
import { sendMB } from '../../../../../infrastructure/event-tracking'
import { useSplitTestContext } from '../../../../../shared/context/split-test-context'
import { useFeatureFlag } from '../../../../../shared/context/split-test-context'
import { User } from '../../../../../../../types/user'
import { useUserContext } from '../../../../../shared/context/user-context'
import grammarlyExtensionPresent from '../../../../../shared/utils/grammarly'
@ -30,10 +30,8 @@ export const PromotionOverlay: FC = ({ children }) => {
const { inactiveTutorials, currentPopup, setCurrentPopup } =
useEditorContext()
const {
splitTestVariants,
}: { splitTestVariants: Record<string, string | undefined> } =
useSplitTestContext()
const hasTableGeneratorPromotion = useFeatureFlag('table-generator-promotion')
const user = useUserContext() as User | undefined
@ -50,7 +48,7 @@ export const PromotionOverlay: FC = ({ children }) => {
currentPopup && currentPopup !== 'table-generator-promotion'
const showPromotion =
splitTestVariants['table-generator-promotion'] === 'enabled' &&
hasTableGeneratorPromotion &&
!popupPresent &&
!inactiveTutorials.includes('table-generator-promotion') &&
!hideBecauseNewUser

View file

@ -1,6 +1,7 @@
import { SubscriptionDashboardProvider } from '../../context/subscription-dashboard-context'
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
import SubscriptionDashboard from './subscription-dashboard'
import { SplitTestProvider } from '@/shared/context/split-test-context'
function Root() {
const { isReady } = useWaitForI18n()
@ -10,9 +11,11 @@ function Root() {
}
return (
<SubscriptionDashboardProvider>
<SubscriptionDashboard />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<SubscriptionDashboard />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
}

View file

@ -1,6 +1,7 @@
import useWaitForI18n from '../../../../shared/hooks/use-wait-for-i18n'
import { SubscriptionDashboardProvider } from '../../context/subscription-dashboard-context'
import SuccessfulSubscription from './successful-subscription'
import { SplitTestProvider } from '@/shared/context/split-test-context'
function Root() {
const { isReady } = useWaitForI18n()
@ -10,9 +11,11 @@ function Root() {
}
return (
<SubscriptionDashboardProvider>
<SuccessfulSubscription />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<SuccessfulSubscription />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
}

View file

@ -30,7 +30,7 @@ import {
import { isRecurlyLoaded } from '../util/is-recurly-loaded'
import { SubscriptionDashModalIds } from '../../../../../types/subscription/dashboard/modal-ids'
import { debugConsole } from '@/utils/debugging'
import { getSplitTestVariant } from '@/utils/splitTestUtils'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import { formatCurrencyLocalized } from '@/shared/utils/currency'
type SubscriptionDashboardContextValue = {
@ -80,11 +80,6 @@ export const SubscriptionDashboardContext = createContext<
SubscriptionDashboardContextValue | undefined
>(undefined)
const getFormatCurrencies = () =>
getSplitTestVariant('local-ccy-format-v2') === 'enabled'
? formatCurrencyLocalized
: formatCurrencyDefault
export function SubscriptionDashboardProvider({
children,
}: {
@ -150,6 +145,10 @@ export function SubscriptionDashboardProvider({
memberGroupSubscriptions?.length > 0
)
const formatCurrency = useFeatureFlag('local-ccy-format-v2')
? formatCurrencyLocalized
: formatCurrencyDefault
useEffect(() => {
if (!isRecurlyLoaded()) {
setRecurlyLoadError(true)
@ -164,7 +163,6 @@ export function SubscriptionDashboardProvider({
plansWithoutDisplayPrice &&
personalSubscription?.recurly
) {
const formatCurrency = getFormatCurrencies()
const { currency, taxRate } = personalSubscription.recurly
const fetchPlansDisplayPrices = async () => {
for (const plan of plansWithoutDisplayPrice) {
@ -192,7 +190,12 @@ export function SubscriptionDashboardProvider({
}
fetchPlansDisplayPrices().catch(debugConsole.error)
}
}, [personalSubscription, plansWithoutDisplayPrice, i18n.language])
}, [
personalSubscription,
plansWithoutDisplayPrice,
i18n.language,
formatCurrency,
])
useEffect(() => {
if (
@ -209,7 +212,6 @@ export function SubscriptionDashboardProvider({
setGroupPlanToChangeToPriceError(false)
let priceData
try {
const formatCurrency = getFormatCurrencies()
priceData = await loadGroupDisplayPriceWithTaxPromise(
groupPlanToChangeToCode,
currency,
@ -233,6 +235,7 @@ export function SubscriptionDashboardProvider({
groupPlanToChangeToSize,
personalSubscription,
groupPlanToChangeToCode,
formatCurrency,
i18n.language,
])

View file

@ -34,7 +34,7 @@ import { useUserContext } from './user-context'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
import { useSplitTestContext } from '@/shared/context/split-test-context'
import { useFeatureFlag } from '@/shared/context/split-test-context'
type PdfFile = Record<string, any>
@ -342,7 +342,7 @@ export const LocalCompileProvider: FC = ({ children }) => {
}
}, [compiling, isProjectOwner, hasShortCompileTimeout])
const { splitTestVariants } = useSplitTestContext()
const hasCompileLogsEvents = useFeatureFlag('compile-log-events')
// handle the data returned from a compile request
// note: this should _only_ run when `data` changes,
@ -401,7 +401,7 @@ export const LocalCompileProvider: FC = ({ children }) => {
)
}
if (splitTestVariants['compile-log-events'] === 'enabled') {
if (hasCompileLogsEvents) {
sendMB('compile-log-entries', {
status: data.status,
stopOnFirstError: data.options.stopOnFirstError,
@ -479,6 +479,7 @@ export const LocalCompileProvider: FC = ({ children }) => {
}, [
data,
ide,
hasCompileLogsEvents,
hasPremiumCompile,
isProjectOwner,
projectId,
@ -487,7 +488,6 @@ export const LocalCompileProvider: FC = ({ children }) => {
setLogEntries,
setLogEntryAnnotations,
setPdfFile,
splitTestVariants,
])
// switch to logs if there's an error

View file

@ -39,3 +39,8 @@ export function useSplitTestContext() {
return context
}
export function useFeatureFlag(name: string) {
const { splitTestVariants } = useSplitTestContext()
return splitTestVariants[name] === 'enabled'
}

View file

@ -17,6 +17,7 @@ import {
} from '../../fixtures/subscriptions'
import * as useLocationModule from '../../../../../../frontend/js/shared/hooks/use-location'
import { UserId } from '../../../../../../types/user'
import { SplitTestProvider } from '@/shared/context/split-test-context'
const userId = 'fff999fff999'
const memberGroupSubscriptions: MemberGroupSubscription[] = [
@ -58,9 +59,11 @@ describe('<GroupSubscriptionMemberships />', function () {
it('renders all group subscriptions not managed', function () {
render(
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.getAllByText('You are on our', {
@ -83,9 +86,11 @@ describe('<GroupSubscriptionMemberships />', function () {
})
render(
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const leaveGroupButton = screen.getByText('Leave group')
@ -130,9 +135,11 @@ describe('<GroupSubscriptionMemberships />', function () {
window.metaAttributesCache.set('ol-memberGroupSubscriptions', undefined)
render(
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<GroupSubscriptionMemberships />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.queryAllByText('You are on our', {
exact: false,

View file

@ -5,6 +5,7 @@ import ManagedInstitutions, {
} from '../../../../../../frontend/js/features/subscription/components/dashboard/managed-institutions'
import { SubscriptionDashboardProvider } from '../../../../../../frontend/js/features/subscription/context/subscription-dashboard-context'
import fetchMock from 'fetch-mock'
import { SplitTestProvider } from '@/shared/context/split-test-context'
const userId = 'fff999fff999'
const institution1 = {
@ -45,9 +46,11 @@ describe('<ManagedInstitutions />', function () {
it('renders all managed institutions', function () {
render(
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.getAllByText('You are a', {
@ -90,9 +93,11 @@ describe('<ManagedInstitutions />', function () {
})
render(
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const unsubscribeLink = screen.getByText('Unsubscribe')
@ -114,9 +119,11 @@ describe('<ManagedInstitutions />', function () {
})
render(
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const subscribeLink = screen.getByText('Subscribe')
@ -132,9 +139,11 @@ describe('<ManagedInstitutions />', function () {
window.metaAttributesCache.set('ol-managedInstitutions', undefined)
render(
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedInstitutions />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.queryAllByText('You are a', {
exact: false,

View file

@ -5,6 +5,7 @@ import fetchMock from 'fetch-mock'
import ManagedPublishers, {
Publisher,
} from '../../../../../../frontend/js/features/subscription/components/dashboard/managed-publishers'
import { SplitTestProvider } from '@/shared/context/split-test-context'
const userId = 'fff999fff999'
const publisher1 = {
@ -36,9 +37,11 @@ describe('<ManagedPublishers />', function () {
it('renders all managed publishers', function () {
render(
<SubscriptionDashboardProvider>
<ManagedPublishers />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedPublishers />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.getAllByText('You are a', {
@ -63,9 +66,11 @@ describe('<ManagedPublishers />', function () {
window.metaAttributesCache.set('ol-managedPublishers', undefined)
render(
<SubscriptionDashboardProvider>
<ManagedPublishers />
</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>
<ManagedPublishers />
</SubscriptionDashboardProvider>
</SplitTestProvider>
)
const elements = screen.queryAllByText('You are a', {
exact: false,

View file

@ -3,6 +3,7 @@ import _ from 'lodash'
import { SubscriptionDashboardProvider } from '../../../../../frontend/js/features/subscription/context/subscription-dashboard-context'
import { groupPriceByUsageTypeAndSize, plans } from '../fixtures/plans'
import fetchMock from 'fetch-mock'
import { SplitTestProvider } from '@/shared/context/split-test-context'
export function renderWithSubscriptionDashContext(
component: React.ReactElement,
@ -21,7 +22,9 @@ export function renderWithSubscriptionDashContext(
}: {
children: React.ReactNode
}) => (
<SubscriptionDashboardProvider>{children}</SubscriptionDashboardProvider>
<SplitTestProvider>
<SubscriptionDashboardProvider>{children}</SubscriptionDashboardProvider>
</SplitTestProvider>
)
window.metaAttributesCache = new Map()