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 7ec0600a17..85b3f3331f 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 @@ -2,8 +2,8 @@ import { memo, useCallback, useEffect } from 'react' import { Button } from 'react-bootstrap' import { Trans, useTranslation } from 'react-i18next' 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 { startFreeTrial } from '../../../main/account-upgrade' import usePersistedState from '../../../shared/hooks/use-persisted-state' const ONE_DAY = 24 * 60 * 60 * 24 * 1000 @@ -45,18 +45,13 @@ function CompileTimeWarning() { setDisplayStatus(displayStatus => ({ ...displayStatus, dismissed: true })) }, [getTimeSinceDisplayed, setShowCompileTimeWarning, setDisplayStatus]) - const handleUpgradeClick = useCallback( - event => { - event.preventDefault() - startFreeTrial('compile-time-warning') - eventTracking.sendMB('compile-time-warning-upgrade-click', { - 'time-since-displayed': getTimeSinceDisplayed(), - }) - setShowCompileTimeWarning(false) - setDisplayStatus(displayStatus => ({ ...displayStatus, dismissed: true })) - }, - [getTimeSinceDisplayed, setShowCompileTimeWarning, setDisplayStatus] - ) + const handleUpgradeClick = useCallback(() => { + eventTracking.sendMB('compile-time-warning-upgrade-click', { + 'time-since-displayed': getTimeSinceDisplayed(), + }) + setShowCompileTimeWarning(false) + setDisplayStatus(displayStatus => ({ ...displayStatus, dismissed: true })) + }, [getTimeSinceDisplayed, setShowCompileTimeWarning, setDisplayStatus]) if (!showCompileTimeWarning || displayStatus.dismissed) { return null @@ -81,9 +76,13 @@ function CompileTimeWarning() { />
- +
diff --git a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.js b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.js index ac888ee2b9..a73b20cbf9 100644 --- a/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.js +++ b/services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt.js @@ -32,8 +32,10 @@ function TimeoutUpgradePrompt() {

)} diff --git a/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.js b/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.js index 8c7623ffdc..b3a07abb43 100644 --- a/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.js +++ b/services/web/frontend/js/features/share-project-modal/components/add-collaborators-upgrade.js @@ -33,8 +33,8 @@ export default function AddCollaboratorsUpgrade() {

{user.allowedFreeTrial ? ( setStartedFreeTrial(true)} source="project-sharing" /> ) : ( diff --git a/services/web/frontend/js/features/share-project-modal/components/link-sharing.js b/services/web/frontend/js/features/share-project-modal/components/link-sharing.js index a4912076d2..fa8519c5a9 100644 --- a/services/web/frontend/js/features/share-project-modal/components/link-sharing.js +++ b/services/web/frontend/js/features/share-project-modal/components/link-sharing.js @@ -297,8 +297,8 @@ function LinkSharingUpgradePrompt({ canAddCollaborators }) { />

setStartedFreeTrial(true)} source="link-sharing" /> diff --git a/services/web/frontend/js/main/account-upgrade.js b/services/web/frontend/js/main/account-upgrade.js index 3f89ca71ed..a92c507838 100644 --- a/services/web/frontend/js/main/account-upgrade.js +++ b/services/web/frontend/js/main/account-upgrade.js @@ -8,36 +8,32 @@ const interstitialPaymentAfterPaywallVariant = function startFreeTrial(source, version, $scope) { const plan = 'collaborator_free_trial_7_days' - const w = window.open() - const go = function () { - if (typeof ga === 'function') { - ga('send', 'event', 'subscription-funnel', 'upgraded-free-trial', source) - } - eventTracking.sendMB('paywall-click', { 'paywall-type': source }) + eventTracking.send('subscription-funnel', 'upgraded-free-trial', source) + eventTracking.sendMB('paywall-click', { 'paywall-type': source }) - const searchParams = new URLSearchParams({ itm_campaign: source }) + const searchParams = new URLSearchParams({ + planCode: 'collaborator_free_trial_7_days', + ssp: 'true', + itm_campaign: source, + }) - if (version) { - searchParams.set('itm_content', version) - } - - let url - if (interstitialPaymentAfterPaywallVariant === 'active') { - url = `/user/subscription/choose-your-plan?${searchParams.toString()}` - } else { - searchParams.set('ssp', 'true') - searchParams.set('planCode', plan) - url = `/user/subscription/new?${searchParams.toString()}` - } - - if ($scope) { - $scope.startedFreeTrial = true - } - - w.location = url + if (version) { + searchParams.set('itm_content', version) } - go() + if ($scope) { + $scope.startedFreeTrial = true + } + + if (interstitialPaymentAfterPaywallVariant === 'active') { + window.open( + `/user/subscription/choose-your-plan?${searchParams.toString()}` + ) + } else { + searchParams.set('ssp', 'true') + searchParams.set('planCode', plan) + window.open(`/user/subscription/new?${searchParams.toString()}`) + } } function upgradePlan(source, $scope) { diff --git a/services/web/frontend/js/shared/components/start-free-trial-button.js b/services/web/frontend/js/shared/components/start-free-trial-button.js deleted file mode 100644 index 2add72491a..0000000000 --- a/services/web/frontend/js/shared/components/start-free-trial-button.js +++ /dev/null @@ -1,73 +0,0 @@ -import { useCallback, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import { Button } from 'react-bootstrap' -import PropTypes from 'prop-types' -import { useSplitTestContext } from '../context/split-test-context' -import * as eventTracking from '../../infrastructure/event-tracking' - -export default function StartFreeTrialButton({ - buttonStyle = 'info', - children, - classes = {}, - setStartedFreeTrial, - source, -}) { - const { t } = useTranslation() - - const { splitTestVariants } = useSplitTestContext({ - splitTestVariants: PropTypes.object, - }) - const interstitialPaymentFromPaywallVariant = - splitTestVariants['interstitial-payment-from-paywall'] - - useEffect(() => { - eventTracking.sendMB('paywall-prompt', { 'paywall-type': source }) - }, [source]) - - const handleClick = useCallback( - event => { - event.preventDefault() - - eventTracking.send('subscription-funnel', 'upgraded-free-trial', source) - eventTracking.sendMB('paywall-click', { 'paywall-type': source }) - - if (setStartedFreeTrial) { - setStartedFreeTrial(true) - } - - const params = new URLSearchParams({ - planCode: 'collaborator_free_trial_7_days', - ssp: 'true', - itm_campaign: source, - }) - - if (interstitialPaymentFromPaywallVariant === 'active') { - window.open( - `/user/subscription/choose-your-plan?itm_campaign=${source}` - ) - } else { - window.open(`/user/subscription/new?${params}`) - } - }, - [setStartedFreeTrial, source, interstitialPaymentFromPaywallVariant] - ) - - return ( - - ) -} -StartFreeTrialButton.propTypes = { - buttonStyle: PropTypes.string, - children: PropTypes.any, - classes: PropTypes.shape({ - button: PropTypes.string.isRequired, - }), - setStartedFreeTrial: PropTypes.func, - source: PropTypes.string.isRequired, -} diff --git a/services/web/frontend/js/shared/components/start-free-trial-button.tsx b/services/web/frontend/js/shared/components/start-free-trial-button.tsx new file mode 100644 index 0000000000..ba025b7ba4 --- /dev/null +++ b/services/web/frontend/js/shared/components/start-free-trial-button.tsx @@ -0,0 +1,48 @@ +import { MouseEventHandler, useCallback, useEffect } from 'react' +import { useTranslation } from 'react-i18next' +import { Button } from 'react-bootstrap' +import { startFreeTrial } from '../../main/account-upgrade' +import * as eventTracking from '../../infrastructure/event-tracking' + +type StartFreeTrialButtonProps = { + source: string + buttonProps?: Button.ButtonProps + children?: React.ReactNode + handleClick?: MouseEventHandler + ) +} diff --git a/services/web/frontend/stories/start-free-trial-button.stories.js b/services/web/frontend/stories/start-free-trial-button.stories.js new file mode 100644 index 0000000000..9c31348c0b --- /dev/null +++ b/services/web/frontend/stories/start-free-trial-button.stories.js @@ -0,0 +1,30 @@ +import StartFreeTrialButton from '../js/shared/components/start-free-trial-button' +import { ScopeDecorator } from './decorators/scope' + +export const Default = args => { + return +} + +export const CustomText = args => { + return ( + Some Custom Text! + ) +} + +export const ButtonStyle = args => { + return ( + + ) +} + +export default { + title: 'Shared / Components / Start Free Trial Button', + component: StartFreeTrialButton, + args: { + source: 'storybook', + }, + decorators: [ScopeDecorator], +} diff --git a/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx b/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx new file mode 100644 index 0000000000..c1a4828319 --- /dev/null +++ b/services/web/test/frontend/components/shared/start-free-trial-button.spec.tsx @@ -0,0 +1,90 @@ +import StartFreeTrialButton from '../../../../frontend/js/shared/components/start-free-trial-button' + +describe('start free trial button', function () { + beforeEach(function () { + cy.intercept('POST', '/event/paywall-prompt', { + statusCode: 204, + }).as('event-paywall-prompt') + cy.intercept('POST', '/event/paywall-click', { + statusCode: 204, + }).as('event-paywall-click') + }) + + it('renders the button with default text', function () { + cy.mount() + + cy.wait('@event-paywall-prompt') + .its('request.body.paywall-type') + .should('eq', 'cypress-test') + + cy.get('button').contains('Start Free Trial!') + }) + + it('renders the button with custom text', function () { + cy.mount( + + Some Custom Text + + ) + + cy.wait('@event-paywall-prompt') + .its('request.body.paywall-type') + .should('eq', 'cypress-test') + + cy.get('button').contains('Some Custom Text') + }) + + it('renders the button with styled button', function () { + cy.mount( + + ) + + cy.wait('@event-paywall-prompt') + + cy.get('button.btn.btn-danger.btn-lg').contains('Start Free Trial!') + }) + + it('renders the button with custom class', function () { + cy.mount( + + ) + + cy.wait('@event-paywall-prompt') + .its('request.body.paywall-type') + .should('eq', 'cypress-test') + + cy.get('.ct-test-class').contains('Start Free Trial!') + }) + + it('calls onClick callback and opens a new tab to the subscription page on click', function () { + const onClickStub = cy.stub() + cy.mount( + + ) + + cy.wait('@event-paywall-prompt') + + cy.window().then(win => { + cy.stub(win, 'open').as('Open') + }) + cy.get('button.btn') + .contains('Start Free Trial!') + .click() + .then(() => { + cy.wait('@event-paywall-click') + .its('request.body.paywall-type') + .should('eq', 'cypress-test') + cy.get('@Open').should( + 'have.been.calledOnceWithExactly', + '/user/subscription/new?planCode=collaborator_free_trial_7_days&ssp=true&itm_campaign=cypress-test' + ) + expect(onClickStub).to.be.called + }) + }) +})