From 92a58c8f3bfdc8fe4dbed4eb0bde54147e6dc21c Mon Sep 17 00:00:00 2001
From: Antoine Clausse
Date: Tue, 2 Apr 2024 16:06:16 +0200
Subject: [PATCH] [web] Paywall CTA split-test (#17555)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Fix `{splitTest.requiredCohortSize && (...)}` can display `0`
* Get `paywall-cta` assignment in ProjectController.js
* CTA change: "Get Dropbox Sync"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578763286026
* CTA change: "Get GitHub Sync"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578763286736
* CTA change: "Get Git integration"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578763286283
* CTA change: "Add more collaborators"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578763884855
* CTA change: "Get track changes"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764030761
* Update wording and position: "Already subscribed? Try refreshing the page."
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764366969
* Casing update: "Upgrade to track changes"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764209961
* CTA changes: "Get Mendeley integration" + "Get Zotero integration"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764547424
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764547269
* CTA change: "Get full project history"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764762005
* Casing update: "full project history"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764762280
* CTA change: "Get more compile time" in timeout-upgrade-prompt-new.tsx
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764762563
* CTA change: "Get more compile time" in compile-timeout-warning.tsx
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764762726
* CTA change: "Get advanced reference search"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764969087
* Update casing and wording: "advanced reference search"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764969412
* CTA change: "Get Symbol Palette"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578765128906
* Update title: "Subscribe to find the symbols you need faster"
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578765289664
* Revert use of `satisfies`: it doesn't work with our version of prettier (https://github.com/prettier/prettier/issues/13516)
* CTA change: "Get more compile time" in compile-timeout-changing-soon.tsx
⚠️ not in miro
* Rename `paywallCtaAssignment`, remove useless export and comment
Addressing Fahru's review
* Add alternative texts in `/registration/try-premium` page
* CTA change: "Get more compile time" in timeout-upgrade-prompt.jsx
https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578764762563
* CTA change: "Get GitHub Sync" in import-project-from-github-modal-content.tsx
Not in Miro, but related to: https://miro.com/app/board/uXjVMFLu5J8=/?openComment=3458764578763286736
* CTA change: "Get more compile time" in compile-time-warning.tsx
Not in Miro, but related to others
* Fix compile-time-warning style (spacings, overflows out of window)
* `npm run format:fix`
GitOrigin-RevId: 0d8d1808b5901c2761d35494c49713d26721bcfd
---
.../src/Features/Project/ProjectController.js | 3 +++
.../Features/Project/ProjectListController.js | 9 +++++++++
.../web/frontend/extracted-translations.json | 14 ++++++++++++-
.../change-list/owner-paywall-prompt.tsx | 12 +++++++++--
.../components/compile-time-warning.tsx | 6 +++++-
.../compile-timeout-changing-soon.tsx | 8 +++++++-
.../components/compile-timeout-warning.tsx | 8 +++++++-
.../components/timeout-upgrade-prompt-new.tsx | 9 ++++++++-
.../components/timeout-upgrade-prompt.jsx | 10 +++++++++-
.../components/project-list-root.tsx | 5 ++++-
.../components/add-collaborators-upgrade.tsx | 7 ++++++-
.../upgrade-track-changes-modal.tsx | 12 +++++++++--
.../web/frontend/stylesheets/app/editor.less | 8 ++++----
services/web/locales/en.json | 20 +++++++++++++++++--
14 files changed, 113 insertions(+), 18 deletions(-)
diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js
index dc2e054d71..966e02d586 100644
--- a/services/web/app/src/Features/Project/ProjectController.js
+++ b/services/web/app/src/Features/Project/ProjectController.js
@@ -616,6 +616,9 @@ const ProjectController = {
compileLogEventsAssignment(cb) {
SplitTestHandler.getAssignment(req, res, 'compile-log-events', cb)
},
+ paywallCtaAssignment(cb) {
+ SplitTestHandler.getAssignment(req, res, 'paywall-cta', cb)
+ },
projectTags(cb) {
if (!userId) {
return cb(null, [])
diff --git a/services/web/app/src/Features/Project/ProjectListController.js b/services/web/app/src/Features/Project/ProjectListController.js
index e6235b17aa..c78ce87532 100644
--- a/services/web/app/src/Features/Project/ProjectListController.js
+++ b/services/web/app/src/Features/Project/ProjectListController.js
@@ -400,6 +400,15 @@ async function projectListPage(req, res, next) {
)
}
+ try {
+ await SplitTestHandler.promises.getAssignment(req, res, 'paywall-cta')
+ } catch (error) {
+ logger.error(
+ { err: error },
+ 'failed to get "paywall-cta" split test assignment'
+ )
+ }
+
res.render('project/list-react', {
title: 'your_projects',
usersBestSubscription,
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index aa46191d9b..fa1e6f6b79 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -41,6 +41,7 @@
"add_company_details": "",
"add_email_to_claim_features": "",
"add_files": "",
+ "add_more_collaborators": "",
"add_more_managers": "",
"add_more_members": "",
"add_new_email": "",
@@ -65,6 +66,7 @@
"all_premium_features_including": "",
"all_projects": "",
"all_projects_will_be_transferred_immediately": "",
+ "already_subscribed_try_refreshing_the_page": "",
"also": "",
"an_email_has_already_been_sent_to": "",
"an_error_occurred_when_verifying_the_coupon_code": "",
@@ -409,7 +411,6 @@
"find_out_more_about_institution_login": "",
"find_out_more_about_the_file_outline": "",
"find_out_more_nt": "",
- "find_the_symbols_you_need_with_premium": "",
"first_name": "",
"first_x_days_free_after_that_y_per_month": "",
"first_x_days_free_after_that_y_per_year": "",
@@ -439,9 +440,17 @@
"generic_if_problem_continues_contact_us": "",
"generic_linked_file_compile_error": "",
"generic_something_went_wrong": "",
+ "get_advanced_reference_search": "",
"get_collaborative_benefits": "",
"get_discounted_plan": "",
+ "get_dropbox_sync": "",
+ "get_full_project_history": "",
+ "get_git_integration": "",
+ "get_github_sync": "",
+ "get_more_compile_time": "",
"get_most_subscription_by_checking_features": "",
+ "get_symbol_palette": "",
+ "get_track_changes": "",
"git": "",
"git_authentication_token": "",
"git_authentication_token_create_modal_info_1": "",
@@ -741,6 +750,7 @@
"maximum_files_uploaded_together": "",
"maybe_later": "",
"members_management": "",
+ "mendeley_cta": "",
"mendeley_groups_loading_error": "",
"mendeley_groups_relink": "",
"mendeley_integration": "",
@@ -1247,6 +1257,7 @@
"subject_to_additional_vat": "",
"submit_title": "",
"subscribe": "",
+ "subscribe_to_find_the_symbols_you_need_faster": "",
"subscription_admins_cannot_be_deleted": "",
"subscription_canceled": "",
"subscription_canceled_and_terminate_on_x": "",
@@ -1594,6 +1605,7 @@
"youve_unlinked_all_users": "",
"zoom_in": "",
"zoom_out": "",
+ "zotero_cta": "",
"zotero_groups_loading_error": "",
"zotero_groups_relink": "",
"zotero_integration": "",
diff --git a/services/web/frontend/js/features/history/components/change-list/owner-paywall-prompt.tsx b/services/web/frontend/js/features/history/components/change-list/owner-paywall-prompt.tsx
index c057cea145..3248d98eb8 100644
--- a/services/web/frontend/js/features/history/components/change-list/owner-paywall-prompt.tsx
+++ b/services/web/frontend/js/features/history/components/change-list/owner-paywall-prompt.tsx
@@ -4,6 +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'
function FeatureItem({ text }: { text: string }) {
return (
@@ -17,6 +18,9 @@ export function OwnerPaywallPrompt() {
const { t } = useTranslation()
const [clickedFreeTrialButton, setClickedFreeTrialButton] = useState(false)
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
useEffect(() => {
eventTracking.send('subscription-funnel', 'editor-click-feature', 'history')
paywallPrompt('history')
@@ -32,7 +36,7 @@ export function OwnerPaywallPrompt() {
{t('currently_seeing_only_24_hrs_history')}
- {t('upgrade_to_get_feature', { feature: 'full Project History' })}
+ {t('upgrade_to_get_feature', { feature: 'full project history' })}
@@ -50,7 +54,11 @@ export function OwnerPaywallPrompt() {
source="history"
buttonProps={{ bsStyle: 'default', className: 'btn-premium' }}
handleClick={handleFreeTrialClick}
- />
+ >
+ {hasNewPaywallCta
+ ? t('get_full_project_history')
+ : t('start_free_trial')}
+
{clickedFreeTrialButton ? (
{t('refresh_page_after_starting_free_trial')}
diff --git a/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx b/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx
index c28acdf3d9..4f3ea2a23b 100644
--- a/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx
+++ b/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx
@@ -5,6 +5,7 @@ import * as eventTracking from '../../../infrastructure/event-tracking'
import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
import { useDetachCompileContext } from '../../../shared/context/detach-compile-context'
import usePersistedState from '../../../shared/hooks/use-persisted-state'
+import { useSplitTestContext } from '@/shared/context/split-test-context'
const TWENTY_FOUR_DAYS = 24 * 60 * 60 * 24 * 1000
@@ -24,6 +25,9 @@ function CompileTimeWarning() {
isProjectOwner,
} = useDetachCompileContext()
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
useEffect(() => {
if (deliveryLatencies && deliveryLatencies.compileTimeServerE2E) {
// compile-timeout-20s test
@@ -101,7 +105,7 @@ function CompileTimeWarning() {
handleClick={handleUpgradeClick}
source="compile-time-warning"
>
- {t('upgrade')}
+ {hasNewPaywallCta ? t('get_more_compile_time') : t('upgrade')}
diff --git a/services/web/frontend/js/features/pdf-preview/components/compile-timeout-changing-soon.tsx b/services/web/frontend/js/features/pdf-preview/components/compile-timeout-changing-soon.tsx
index 5f6cd56498..9ca3135991 100644
--- a/services/web/frontend/js/features/pdf-preview/components/compile-timeout-changing-soon.tsx
+++ b/services/web/frontend/js/features/pdf-preview/components/compile-timeout-changing-soon.tsx
@@ -3,6 +3,7 @@ import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
import { Trans, useTranslation } from 'react-i18next'
import * as eventTracking from '@/infrastructure/event-tracking'
import { FC } from 'react'
+import { useSplitTestContext } from '@/shared/context/split-test-context'
const sendInfoClickEvent = () => {
eventTracking.sendMB('paywall-info-click', {
@@ -17,6 +18,9 @@ export const CompileTimeoutChangingSoon: FC<{
}> = ({ isProjectOwner = false, handleDismissChangingSoon }) => {
const { t } = useTranslation()
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
const compileTimeoutChangesBlogLink = (
/* eslint-disable-next-line jsx-a11y/anchor-has-content */
- {t('start_free_trial_without_exclamation')}
+ {hasNewPaywallCta
+ ? t('get_more_compile_time')
+ : t('start_free_trial_without_exclamation')}
}
ariaLive="polite"
diff --git a/services/web/frontend/js/features/pdf-preview/components/compile-timeout-warning.tsx b/services/web/frontend/js/features/pdf-preview/components/compile-timeout-warning.tsx
index f593e06ea9..3ab2a235e5 100644
--- a/services/web/frontend/js/features/pdf-preview/components/compile-timeout-warning.tsx
+++ b/services/web/frontend/js/features/pdf-preview/components/compile-timeout-warning.tsx
@@ -2,6 +2,7 @@ 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'
export const CompileTimeoutWarning: FC<{
handleDismissWarning: () => void
@@ -9,6 +10,9 @@ export const CompileTimeoutWarning: FC<{
}> = ({ handleDismissWarning, showNewCompileTimeoutUI }) => {
const { t } = useTranslation()
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
return (
- {t('start_free_trial_without_exclamation')}
+ {hasNewPaywallCta
+ ? t('get_more_compile_time')
+ : t('start_free_trial_without_exclamation')}
}
ariaLive="polite"
diff --git a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx
index a6d15d42f5..ec1962924e 100644
--- a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx
+++ b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx
@@ -6,6 +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'
function TimeoutUpgradePromptNew() {
const {
@@ -58,6 +59,10 @@ const CompileTimeout = memo(function CompileTimeout({
isProjectOwner,
}: CompileTimeoutProps) {
const { t } = useTranslation()
+
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
return (
- {t('start_a_free_trial')}
+ {hasNewPaywallCta
+ ? t('get_more_compile_time')
+ : t('start_a_free_trial')}
)}
diff --git a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.jsx b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.jsx
index a73b20cbf9..30343a6792 100644
--- a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.jsx
+++ b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.jsx
@@ -4,12 +4,16 @@ import StartFreeTrialButton from '../../../shared/components/start-free-trial-bu
import { memo } from 'react'
import PdfLogEntry from './pdf-log-entry'
import UpgradeBenefits from '../../../shared/components/upgrade-benefits'
+import { useSplitTestContext } from '@/shared/context/split-test-context'
function TimeoutUpgradePrompt() {
const { t } = useTranslation()
const { hasPremiumCompile, isProjectOwner } = useEditorContext()
+ const { splitTestVariants } = useSplitTestContext()
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
+
if (!window.ExposedSettings.enableSubscriptions || hasPremiumCompile) {
return null
}
@@ -36,7 +40,11 @@ function TimeoutUpgradePrompt() {
bsStyle: 'success',
className: 'row-spaced-small',
}}
- />
+ >
+ {hasNewPaywallCta
+ ? t('get_more_compile_time')
+ : t('start_free_trial')}
+
)}
>
diff --git a/services/web/frontend/js/features/project-list/components/project-list-root.tsx b/services/web/frontend/js/features/project-list/components/project-list-root.tsx
index 7c261e1473..c886b1939e 100644
--- a/services/web/frontend/js/features/project-list/components/project-list-root.tsx
+++ b/services/web/frontend/js/features/project-list/components/project-list-root.tsx
@@ -25,6 +25,7 @@ import LoadMore from './load-more'
import { useEffect } from 'react'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import { GenericErrorBoundaryFallback } from '../../../shared/components/generic-error-boundary-fallback'
+import { SplitTestProvider } from '@/shared/context/split-test-context'
function ProjectListRoot() {
const { isReady } = useWaitForI18n()
@@ -40,7 +41,9 @@ export function ProjectListRootInner() {
return (
-
+
+
+
)
diff --git a/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.tsx b/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.tsx
index 89258e7732..b59950fd0e 100644
--- a/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.tsx
+++ b/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.tsx
@@ -18,6 +18,7 @@ export default function AddCollaboratorsUpgrade() {
const { splitTestVariants } = useSplitTestContext()
const variant = splitTestVariants['project-share-modal-paywall']
+ const hasNewPaywallCta = splitTestVariants['paywall-cta'] === 'enabled'
return (
@@ -33,7 +34,11 @@ export default function AddCollaboratorsUpgrade() {
buttonProps={{ bsStyle: 'success' }}
handleClick={() => setStartedFreeTrial(true)}
source="project-sharing"
- />
+ >
+ {hasNewPaywallCta
+ ? t('add_more_collaborators')
+ : t('start_free_trial')}
+
) : (
) : (