mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #35478 from overleaf/oa-paywall-ctas
[web] Paywall CTAs GitOrigin-RevId: 26703fe008926db67473a43ef64addca0e23accd
This commit is contained in:
@@ -518,7 +518,7 @@ const _ProjectController = {
|
||||
user: (async () => {
|
||||
const user = await User.findById(
|
||||
userId,
|
||||
'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiFeatures'
|
||||
'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiFeatures lastTrial'
|
||||
).exec()
|
||||
// Handle case of deleted user
|
||||
if (!user) {
|
||||
@@ -627,19 +627,26 @@ const _ProjectController = {
|
||||
inEnterpriseCommons || affiliation.institution?.enterpriseCommons
|
||||
}
|
||||
|
||||
const getSplitTestAssignment = async splitTest => {
|
||||
return await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
splitTest
|
||||
)
|
||||
const allowedFreeTrial =
|
||||
subscription == null ||
|
||||
isStandaloneAiAddOnPlanCode(subscription.planCode)
|
||||
|
||||
// The test's audience: free users who've spent their trial and can't start
|
||||
// another, yet still see a misleading "free trial" CTA.
|
||||
const trialIneligible =
|
||||
!anonymous && allowedFreeTrial && Boolean(user?.lastTrial)
|
||||
|
||||
if (trialIneligible) {
|
||||
splitTests.push('paywall-cta-trial-ineligible')
|
||||
}
|
||||
const splitTestAssignments = {}
|
||||
await Promise.all(
|
||||
splitTests.map(async splitTest => {
|
||||
splitTestAssignments[splitTest] =
|
||||
await getSplitTestAssignment(splitTest)
|
||||
})
|
||||
|
||||
const splitTestAssignments = Object.fromEntries(
|
||||
await Promise.all(
|
||||
splitTests.map(async splitTest => [
|
||||
splitTest,
|
||||
await SplitTestHandler.promises.getAssignment(req, res, splitTest),
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
// PDF caching, these tests are archived but we are keeping the frontend code unchanged for now
|
||||
@@ -705,10 +712,6 @@ const _ProjectController = {
|
||||
return res.sendStatus(401)
|
||||
}
|
||||
|
||||
const allowedFreeTrial =
|
||||
subscription == null ||
|
||||
isStandaloneAiAddOnPlanCode(subscription.planCode)
|
||||
|
||||
let wsUrl = Settings.wsUrl
|
||||
let metricName = 'load-editor-ws'
|
||||
if (user.betaProgram && Settings.wsUrlBeta !== undefined) {
|
||||
|
||||
@@ -1631,6 +1631,7 @@
|
||||
"refresh": "",
|
||||
"refresh_page_after_linking_dropbox": "",
|
||||
"refresh_page_after_starting_free_trial": "",
|
||||
"refresh_page_after_subscribing": "",
|
||||
"refreshing": "",
|
||||
"refund_with_description": "",
|
||||
"regards": "",
|
||||
|
||||
+8
-2
@@ -3,10 +3,12 @@ import { useCallback, useEffect, useState } from 'react'
|
||||
import * as eventTracking from '../../../../infrastructure/event-tracking'
|
||||
import StartFreeTrialButton from '../../../../shared/components/start-free-trial-button'
|
||||
import UpgradeBenefits from '@/shared/components/upgrade-benefits'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export function OwnerPaywallPrompt() {
|
||||
const { t } = useTranslation()
|
||||
const [clickedFreeTrialButton, setClickedFreeTrialButton] = useState(false)
|
||||
const showSubscribeNow = useFeatureFlag('paywall-cta-trial-ineligible')
|
||||
|
||||
useEffect(() => {
|
||||
eventTracking.send('subscription-funnel', 'editor-click-feature', 'history')
|
||||
@@ -34,11 +36,15 @@ export function OwnerPaywallPrompt() {
|
||||
buttonProps={{ variant: 'premium' }}
|
||||
handleClick={handleFreeTrialClick}
|
||||
>
|
||||
{t('start_free_trial')}
|
||||
{showSubscribeNow ? t('subscribe_now') : t('start_free_trial')}
|
||||
</StartFreeTrialButton>
|
||||
</p>
|
||||
{clickedFreeTrialButton ? (
|
||||
<p className="small">{t('refresh_page_after_starting_free_trial')}</p>
|
||||
<p className="small">
|
||||
{showSubscribeNow
|
||||
? t('refresh_page_after_subscribing')
|
||||
: t('refresh_page_after_starting_free_trial')}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
|
||||
+3
-1
@@ -3,12 +3,14 @@ import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FC } from 'react'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export const CompileTimeWarningUpgradePromptInner: FC<{
|
||||
handleDismissWarning: () => void
|
||||
segmentation: eventTracking.Segmentation
|
||||
}> = ({ handleDismissWarning, segmentation }) => {
|
||||
const { t } = useTranslation()
|
||||
const showSubscribeNow = useFeatureFlag('paywall-cta-trial-ineligible')
|
||||
|
||||
return (
|
||||
<Notification
|
||||
@@ -21,7 +23,7 @@ export const CompileTimeWarningUpgradePromptInner: FC<{
|
||||
size: 'sm',
|
||||
}}
|
||||
>
|
||||
{t('start_free_trial')}
|
||||
{showSubscribeNow ? t('subscribe_now') : t('start_free_trial')}
|
||||
</StartFreeTrialButton>
|
||||
}
|
||||
ariaLive="polite"
|
||||
|
||||
+3
-1
@@ -18,11 +18,13 @@ import OLRow from '@/shared/components/ol/ol-row'
|
||||
import OLCol from '@/shared/components/ol/ol-col'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
function UpgradeTrackChangesModal() {
|
||||
const { t } = useTranslation()
|
||||
const { project } = useProjectContext()
|
||||
const user = useUserContext()
|
||||
const showSubscribeNow = useFeatureFlag('paywall-cta-trial-ineligible')
|
||||
const {
|
||||
upgradeTrackChangesModal: { show, location = 'unknown' },
|
||||
setUpgradeTrackChangesModal,
|
||||
@@ -94,7 +96,7 @@ function UpgradeTrackChangesModal() {
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('try_for_free')}
|
||||
{showSubscribeNow ? t('subscribe_now') : t('try_for_free')}
|
||||
</OLButton>
|
||||
) : (
|
||||
<OLButton
|
||||
|
||||
@@ -229,6 +229,7 @@
|
||||
"reconnecting": "Obnovuji připojení",
|
||||
"reconnecting_in_x_secs": "Obnovuji připojení za __seconds__ sek",
|
||||
"refresh_page_after_starting_free_trial": "Obnovte prosím stránku poté co začnete používat svou bezplatnou trial verzi.",
|
||||
"refresh_page_after_subscribing": "Obnovte prosím stránku po předplacení.",
|
||||
"regards": "S pozdravem",
|
||||
"register": "Registrovat",
|
||||
"register_to_edit_template": "Pro úpravu šablony __templateName__ se prosím přihlašte",
|
||||
|
||||
@@ -1411,6 +1411,7 @@
|
||||
"refresh": "Genindlæs",
|
||||
"refresh_page_after_linking_dropbox": "Genindlæs venligst denne side efter at have forbundet din konto til Dropbox",
|
||||
"refresh_page_after_starting_free_trial": "Genindlæs venligst denne side efter du har startet din gratis prøveperiode.",
|
||||
"refresh_page_after_subscribing": "Genindlæs venligst denne side efter du har tilmeldt dig.",
|
||||
"refreshing": "Genindlæser",
|
||||
"regards": "Venligst",
|
||||
"register": "Registrer",
|
||||
|
||||
@@ -1193,6 +1193,7 @@
|
||||
"refresh": "Aktualisieren",
|
||||
"refresh_page_after_linking_dropbox": "Bitte aktualisiere diese Seite, nachdem du dein Konto mit Dropbox verknüpft hast.",
|
||||
"refresh_page_after_starting_free_trial": "Bitte aktualisiere diese Seite, nachdem du deinen kostenlosen Test gestartet hast.",
|
||||
"refresh_page_after_subscribing": "Bitte aktualisiere diese Seite, nachdem du abonniert hast.",
|
||||
"refreshing": "Aktualisiere",
|
||||
"regards": "Viele Grüße",
|
||||
"register": "Registrieren",
|
||||
|
||||
@@ -2126,6 +2126,7 @@
|
||||
"refresh": "Refresh",
|
||||
"refresh_page_after_linking_dropbox": "Please refresh this page after linking your account to Dropbox.",
|
||||
"refresh_page_after_starting_free_trial": "Please refresh this page after starting your free trial.",
|
||||
"refresh_page_after_subscribing": "Please refresh this page after subscribing.",
|
||||
"refreshing": "Refreshing",
|
||||
"refund_with_description": "Refund: __description__",
|
||||
"regards": "Regards",
|
||||
|
||||
@@ -476,7 +476,8 @@
|
||||
"reconnecting": "Volviendo a conectar",
|
||||
"reconnecting_in_x_secs": "Volviendo a conectar en __seconds__ segundos",
|
||||
"reference_error_relink_hint": "Si el error persiste, prueba a volver a vincular la cuenta aquí:",
|
||||
"refresh_page_after_starting_free_trial": "Por favor actualiza esta página para empezar tu prueba gratuita.",
|
||||
"refresh_page_after_starting_free_trial": "Por favor, actualiza esta página después de empezar tu prueba gratuita.",
|
||||
"refresh_page_after_subscribing": "Por favor, actualiza esta página después de suscribirte.",
|
||||
"regards": "Atentamente",
|
||||
"register": "Registrarse",
|
||||
"register_to_edit_template": "Por favor regístrate para editar la plantilla __templateName__",
|
||||
|
||||
@@ -239,6 +239,7 @@
|
||||
"reconnecting": "Yhdistetään uudelleen",
|
||||
"reconnecting_in_x_secs": "Yhteys muodostetaan uudestaan __seconds__ sekunnin kuluttua",
|
||||
"refresh_page_after_starting_free_trial": "Ole hyvä ja päivitä tämä sivu aloitettuasi ilmaisen kokeilusi.",
|
||||
"refresh_page_after_subscribing": "Ole hyvä ja päivitä tämä sivu tilattuasi.",
|
||||
"regards": "Kiittäen",
|
||||
"register": "Rekisteröidy",
|
||||
"register_to_edit_template": "Ole hyvä ja rekisteröidy muokataksesi mallia __templateName__",
|
||||
|
||||
@@ -876,7 +876,8 @@
|
||||
"reference_sync": "Synchro. avec gestionnaire de références",
|
||||
"refresh": "Rafraîchir",
|
||||
"refresh_page_after_linking_dropbox": "Veuillez rafraîchir cette page après avoir lié votre compte à Dropbox.",
|
||||
"refresh_page_after_starting_free_trial": "Veuillez actualiser cette page avant de commencer votre essai gratuit.",
|
||||
"refresh_page_after_starting_free_trial": "Veuillez actualiser cette page après avoir commencé votre essai gratuit.",
|
||||
"refresh_page_after_subscribing": "Veuillez actualiser cette page après votre abonnement.",
|
||||
"refreshing": "Actualisation",
|
||||
"regards": "Merci",
|
||||
"register": "S’inscrire",
|
||||
|
||||
@@ -265,6 +265,7 @@
|
||||
"reconnecting": "Riconnessione",
|
||||
"reconnecting_in_x_secs": "Riconnessione fra __seconds__ secondi",
|
||||
"refresh_page_after_starting_free_trial": "Per favore aggiorna questa pagina dopo l’inizio del tuo trial gratuito.",
|
||||
"refresh_page_after_subscribing": "Per favore aggiorna questa pagina dopo l’abbonamento.",
|
||||
"regards": "Saluti",
|
||||
"register": "Registrati",
|
||||
"register_to_edit_template": "Per favore registrati per modificare il modello __templateName__",
|
||||
|
||||
@@ -341,6 +341,7 @@
|
||||
"reconnecting_in_x_secs": "__seconds__秒後に再接続",
|
||||
"reference_error_relink_hint": "エラーが継続して発生する場合は、こちらでアカウントを再リンク付けしてください:",
|
||||
"refresh_page_after_starting_free_trial": "無料トライアルを開始したらこのページの再読み込みを行ってください。",
|
||||
"refresh_page_after_subscribing": "ご登録後、このページの再読み込みを行ってください。",
|
||||
"regards": "よろしくお願いいたします",
|
||||
"register": "登録する",
|
||||
"register_to_edit_template": "__templateName__ テンプレートを編集するには登録してください",
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"reference_search": "고급 레퍼런스 검색",
|
||||
"reference_sync": "레퍼런스 매니저 동기화",
|
||||
"refresh_page_after_starting_free_trial": "무료 시험 시작 후 이 페이지를 새로고침하세요.",
|
||||
"refresh_page_after_subscribing": "구독 후 이 페이지를 새로고침하세요.",
|
||||
"regards": "감사합니다",
|
||||
"register": "등록",
|
||||
"register_to_edit_template": "__templateName__ 템플릿을 편집하기위해 등록해주세요",
|
||||
|
||||
@@ -390,6 +390,7 @@
|
||||
"reduce_costs_group_licenses": "Je kunt de administratie verkleinen en de kosten verlagen met onze scherp geprijsde groeplicenties.",
|
||||
"reference_error_relink_hint": "Als deze foutmelding blijft verschijnen, probeer dan je account hier opnieuw te linken:",
|
||||
"refresh_page_after_starting_free_trial": "Ververs deze pagina nadat je de gratis proefperiode hebt gestart.",
|
||||
"refresh_page_after_subscribing": "Ververs deze pagina nadat je een abonnement hebt afgesloten.",
|
||||
"regards": "Groeten",
|
||||
"register": "Registreren",
|
||||
"register_to_edit_template": "Registreet om het sjabloon __templateName__ te bewerken",
|
||||
|
||||
@@ -272,6 +272,7 @@
|
||||
"reconnecting": "Kobler til",
|
||||
"reconnecting_in_x_secs": "Kobler til om __seconds__ sekunder",
|
||||
"refresh_page_after_starting_free_trial": "Vennligst last inn siden på nytt etter at du har startet din gratis prøveperiode.",
|
||||
"refresh_page_after_subscribing": "Vennligst last inn siden på nytt etter at du har abonnert.",
|
||||
"regards": "Takk",
|
||||
"register": "Registrer",
|
||||
"register_to_edit_template": "Vennligst registrer deg for å redigere __templateName__ malen",
|
||||
|
||||
@@ -158,6 +158,7 @@
|
||||
"reconnecting": "Ponowne łączenie",
|
||||
"reconnecting_in_x_secs": "Próba połączenia za __seconds__ s",
|
||||
"refresh_page_after_starting_free_trial": "Odśwież tę stronę po rozpoczęciu darmowego trialu",
|
||||
"refresh_page_after_subscribing": "Odśwież tę stronę po zasubskrybowaniu.",
|
||||
"regards": "Dziękujemy",
|
||||
"register": "Zarejestruj się",
|
||||
"register_to_edit_template": "Zarejestruj się, żeby edytować szablon __templateName__",
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
"reference_search": "Busca avançada de referências",
|
||||
"reference_sync": "Gerenciador de sincronia de referências",
|
||||
"refresh_page_after_starting_free_trial": "Por favor atualize essa página depois de iniciar seu teste grátis.",
|
||||
"refresh_page_after_subscribing": "Por favor, atualize esta página depois de assinar.",
|
||||
"regards": "Saudações",
|
||||
"register": "Registrar",
|
||||
"register_to_edit_template": "Por favor, registre-se para editar o modelo __templateName__",
|
||||
|
||||
@@ -330,7 +330,8 @@
|
||||
"recompile_pdf": "Перекомпилировать PDF",
|
||||
"reconnecting": "Пересоединение",
|
||||
"reconnecting_in_x_secs": "Повторное соединение через __seconds__ секунд",
|
||||
"refresh_page_after_starting_free_trial": "Пожалуйста, обновите страницу",
|
||||
"refresh_page_after_starting_free_trial": "Пожалуйста, обновите страницу после начала бесплатного пробного периода.",
|
||||
"refresh_page_after_subscribing": "Пожалуйста, обновите страницу после оформления подписки.",
|
||||
"regards": "С уважением",
|
||||
"register": "Регистрация",
|
||||
"register_to_edit_template": "Пожалуйста, зарегистрируйтесь, чтобы редактировать шаблон __templateName__",
|
||||
|
||||
@@ -656,6 +656,7 @@
|
||||
"reference_sync": "Referenshanterare synk",
|
||||
"refresh": "Uppdatera",
|
||||
"refresh_page_after_starting_free_trial": "Vänligen uppdatera denna sida efter att du startat din gratis provapå period.",
|
||||
"refresh_page_after_subscribing": "Vänligen uppdatera denna sida efter att du prenumererat.",
|
||||
"regards": "Vänliga hälsningar",
|
||||
"register": "Registrera",
|
||||
"register_error": "Registreringsfel",
|
||||
|
||||
@@ -266,6 +266,7 @@
|
||||
"reconnecting": "Yeniden bağlanıyor",
|
||||
"reconnecting_in_x_secs": "__seconds__ saniye içinde tekrar bağlanılmaya çalışılacak",
|
||||
"refresh_page_after_starting_free_trial": "Ücretsiz denemenize başladıktan sonra lütfen sayfayı yenileyin",
|
||||
"refresh_page_after_subscribing": "Abone olduktan sonra lütfen sayfayı yenileyin.",
|
||||
"regards": "Saygılarımızla",
|
||||
"register": "Kayıt ol",
|
||||
"register_to_edit_template": "__templateName__ şablonunu düzenlemek için lütfen kayıt olunuz",
|
||||
|
||||
@@ -1610,6 +1610,7 @@
|
||||
"refresh": "刷新",
|
||||
"refresh_page_after_linking_dropbox": "请在将您的帐户链接到Dropbox后刷新此页。",
|
||||
"refresh_page_after_starting_free_trial": "请在您开始免费试用之后刷新此页面",
|
||||
"refresh_page_after_subscribing": "请在您订阅后刷新此页。",
|
||||
"refreshing": "正在刷新",
|
||||
"regards": "感谢",
|
||||
"register": "注册",
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { render, screen, fireEvent } from '@testing-library/react'
|
||||
import sinon from 'sinon'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { OwnerPaywallPrompt } from '@/features/history/components/change-list/owner-paywall-prompt'
|
||||
|
||||
function renderPrompt() {
|
||||
return render(
|
||||
<SplitTestProvider>
|
||||
<OwnerPaywallPrompt />
|
||||
</SplitTestProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('<OwnerPaywallPrompt/>', function () {
|
||||
let openStub: sinon.SinonStub
|
||||
|
||||
beforeEach(function () {
|
||||
// StartFreeTrialButton opens the plans page in a new tab on click
|
||||
openStub = sinon.stub(window, 'open')
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
openStub.restore()
|
||||
window.metaAttributesCache.delete('ol-splitTestVariants')
|
||||
})
|
||||
|
||||
it('shows the "Start free trial" CTA and free-trial refresh message', function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {})
|
||||
renderPrompt()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Start free trial' }))
|
||||
screen.getByText('Please refresh this page after starting your free trial.')
|
||||
})
|
||||
|
||||
it('shows the "Subscribe now" CTA and subscribe refresh message when paywall-cta-trial-ineligible is enabled', function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'paywall-cta-trial-ineligible': 'enabled',
|
||||
})
|
||||
renderPrompt()
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Subscribe now' }))
|
||||
screen.getByText('Please refresh this page after subscribing.')
|
||||
})
|
||||
})
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { CompileTimeWarningUpgradePromptInner } from '@/features/pdf-preview/components/compile-time-warning-upgrade-prompt-inner'
|
||||
|
||||
function renderPrompt() {
|
||||
return render(
|
||||
<SplitTestProvider>
|
||||
<CompileTimeWarningUpgradePromptInner
|
||||
handleDismissWarning={() => {}}
|
||||
segmentation={{}}
|
||||
/>
|
||||
</SplitTestProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('<CompileTimeWarningUpgradePromptInner/>', function () {
|
||||
afterEach(function () {
|
||||
window.metaAttributesCache.delete('ol-splitTestVariants')
|
||||
})
|
||||
|
||||
it('shows the "Start free trial" CTA by default', function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {})
|
||||
renderPrompt()
|
||||
screen.getByRole('button', { name: 'Start free trial' })
|
||||
})
|
||||
|
||||
it('shows the "Subscribe now" CTA when paywall-cta-trial-ineligible is enabled', function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'paywall-cta-trial-ineligible': 'enabled',
|
||||
})
|
||||
renderPrompt()
|
||||
screen.getByRole('button', { name: 'Subscribe now' })
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user