Merge pull request #11078 from overleaf/jel-features-page-analytics

[web] Add analytics to React dash features link

GitOrigin-RevId: 5f62af1af3854b1443734cda6b97334e6eb42711
This commit is contained in:
Jessica Lawshe 2023-01-09 10:21:06 -06:00 committed by Copybot
parent 38db8bee30
commit bd3b9007c8
8 changed files with 87 additions and 8 deletions

View file

@ -1,6 +1,8 @@
import { useTranslation, Trans } from 'react-i18next' import { useTranslation, Trans } from 'react-i18next'
import { CommonsPlanSubscription } from '../../../../../../types/project/dashboard/subscription' import { CommonsPlanSubscription } from '../../../../../../types/project/dashboard/subscription'
import Tooltip from '../../../../shared/components/tooltip' import Tooltip from '../../../../shared/components/tooltip'
import getMeta from '../../../../utils/meta'
import * as eventTracking from '../../../../infrastructure/event-tracking'
type CommonsPlanProps = Pick< type CommonsPlanProps = Pick<
CommonsPlanSubscription, CommonsPlanSubscription,
@ -16,6 +18,14 @@ function CommonsPlan({
const currentPlanLabel = ( const currentPlanLabel = (
<Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} /> <Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} />
) )
const featuresPageVariant = getMeta('ol-splitTestVariants')?.['features-page']
function handleLinkClick() {
eventTracking.sendMB('features-page-link', {
splitTest: 'features-page',
splitTestVariant: featuresPageVariant,
})
}
return ( return (
<> <>
@ -28,7 +38,11 @@ function CommonsPlan({
id="commons-plan" id="commons-plan"
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
<a href={featuresPageURL} className="current-plan-label hidden-xs"> <a
href={featuresPageURL}
className="current-plan-label hidden-xs"
onClick={handleLinkClick}
>
{currentPlanLabel} <span className="info-badge" /> {currentPlanLabel} <span className="info-badge" />
</a> </a>
</Tooltip> </Tooltip>

View file

@ -3,6 +3,7 @@ import { Button } from 'react-bootstrap'
import { FreePlanSubscription } from '../../../../../../types/project/dashboard/subscription' import { FreePlanSubscription } from '../../../../../../types/project/dashboard/subscription'
import Tooltip from '../../../../shared/components/tooltip' import Tooltip from '../../../../shared/components/tooltip'
import * as eventTracking from '../../../../infrastructure/event-tracking' import * as eventTracking from '../../../../infrastructure/event-tracking'
import getMeta from '../../../../utils/meta'
type FreePlanProps = Pick<FreePlanSubscription, 'featuresPageURL'> type FreePlanProps = Pick<FreePlanSubscription, 'featuresPageURL'>
@ -16,6 +17,14 @@ function FreePlan({ featuresPageURL }: FreePlanProps) {
eventTracking.sendMB('upgrade-button-click', { source: 'dashboard-top' }) eventTracking.sendMB('upgrade-button-click', { source: 'dashboard-top' })
} }
const featuresPageVariant = getMeta('ol-splitTestVariants')?.['features-page']
function handleLinkClick() {
eventTracking.sendMB('features-page-link', {
splitTest: 'features-page',
splitTestVariant: featuresPageVariant,
})
}
return ( return (
<> <>
<span className="current-plan-label visible-xs">{currentPlanLabel}</span> <span className="current-plan-label visible-xs">{currentPlanLabel}</span>
@ -24,7 +33,11 @@ function FreePlan({ featuresPageURL }: FreePlanProps) {
id="free-plan" id="free-plan"
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
<a href={featuresPageURL} className="current-plan-label hidden-xs"> <a
href={featuresPageURL}
className="current-plan-label hidden-xs"
onClick={handleLinkClick}
>
{currentPlanLabel} <span className="info-badge" /> {currentPlanLabel} <span className="info-badge" />
</a> </a>
</Tooltip>{' '} </Tooltip>{' '}

View file

@ -1,6 +1,8 @@
import { useTranslation, Trans } from 'react-i18next' import { useTranslation, Trans } from 'react-i18next'
import { GroupPlanSubscription } from '../../../../../../types/project/dashboard/subscription' import { GroupPlanSubscription } from '../../../../../../types/project/dashboard/subscription'
import Tooltip from '../../../../shared/components/tooltip' import Tooltip from '../../../../shared/components/tooltip'
import getMeta from '../../../../utils/meta'
import * as eventTracking from '../../../../infrastructure/event-tracking'
type GroupPlanProps = Pick< type GroupPlanProps = Pick<
GroupPlanSubscription, GroupPlanSubscription,
@ -29,6 +31,14 @@ function GroupPlan({
<Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} /> <Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} />
) )
const featuresPageVariant = getMeta('ol-splitTestVariants')?.['features-page']
function handleLinkClick() {
eventTracking.sendMB('features-page-link', {
splitTest: 'features-page',
splitTestVariant: featuresPageVariant,
})
}
return ( return (
<> <>
<span className="current-plan-label visible-xs">{currentPlanLabel}</span> <span className="current-plan-label visible-xs">{currentPlanLabel}</span>
@ -44,7 +54,11 @@ function GroupPlan({
id="group-plan" id="group-plan"
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
<a href={featuresPageURL} className="current-plan-label hidden-xs"> <a
href={featuresPageURL}
className="current-plan-label hidden-xs"
onClick={handleLinkClick}
>
{currentPlanLabel} <span className="info-badge" /> {currentPlanLabel} <span className="info-badge" />
</a> </a>
</Tooltip> </Tooltip>

View file

@ -1,6 +1,8 @@
import { useTranslation, Trans } from 'react-i18next' import { useTranslation, Trans } from 'react-i18next'
import { IndividualPlanSubscription } from '../../../../../../types/project/dashboard/subscription' import { IndividualPlanSubscription } from '../../../../../../types/project/dashboard/subscription'
import Tooltip from '../../../../shared/components/tooltip' import Tooltip from '../../../../shared/components/tooltip'
import getMeta from '../../../../utils/meta'
import * as eventTracking from '../../../../infrastructure/event-tracking'
type IndividualPlanProps = Pick< type IndividualPlanProps = Pick<
IndividualPlanSubscription, IndividualPlanSubscription,
@ -28,6 +30,14 @@ function IndividualPlan({
<Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} /> <Trans i18nKey="premium_plan_label" components={{ b: <strong /> }} />
) )
const featuresPageVariant = getMeta('ol-splitTestVariants')?.['features-page']
function handleLinkClick() {
eventTracking.sendMB('features-page-link', {
splitTest: 'features-page',
splitTestVariant: featuresPageVariant,
})
}
return ( return (
<> <>
<span className="current-plan-label visible-xs">{currentPlanLabel}</span> <span className="current-plan-label visible-xs">{currentPlanLabel}</span>
@ -36,7 +46,11 @@ function IndividualPlan({
id="individual-plan" id="individual-plan"
overlayProps={{ placement: 'bottom' }} overlayProps={{ placement: 'bottom' }}
> >
<a href={featuresPageURL} className="current-plan-label hidden-xs"> <a
href={featuresPageURL}
className="current-plan-label hidden-xs"
onClick={handleLinkClick}
>
{currentPlanLabel} <span className="info-badge" /> {currentPlanLabel} <span className="info-badge" />
</a> </a>
</Tooltip> </Tooltip>

View file

@ -27,6 +27,10 @@ export function sendOnce(category, action, label, value) {
} }
export function sendMB(key, segmentation = {}) { export function sendMB(key, segmentation = {}) {
if (!segmentation.page) {
segmentation.page = window.location.pathname
}
sendBeacon(key, segmentation) sendBeacon(key, segmentation)
if (typeof window.gtag !== 'function') return if (typeof window.gtag !== 'function') return

View file

@ -136,6 +136,7 @@ describe('<LayoutDropdownButton />', function () {
sinon.assert.calledWith(sendMBSpy, 'project-layout-change', { sinon.assert.calledWith(sendMBSpy, 'project-layout-change', {
layout: 'flat', layout: 'flat',
view: 'editor', view: 'editor',
page: '/detacher',
}) })
}) })

View file

@ -52,6 +52,7 @@ describe('<CurrentPlanWidget />', function () {
expect(sendMBSpy).to.be.calledOnce expect(sendMBSpy).to.be.calledOnce
expect(sendMBSpy).calledWith('upgrade-button-click', { expect(sendMBSpy).calledWith('upgrade-button-click', {
source: 'dashboard-top', source: 'dashboard-top',
page: '/',
}) })
}) })
}) })
@ -245,6 +246,8 @@ describe('<CurrentPlanWidget />', function () {
}) })
describe('features page split test', function () { describe('features page split test', function () {
let sendMBSpy: sinon.SinonSpy
const variants = [ const variants = [
{ name: 'default', link: '/learn/how-to/Overleaf_premium_features' }, { name: 'default', link: '/learn/how-to/Overleaf_premium_features' },
{ name: 'new', link: '/about/features-overview' }, { name: 'new', link: '/about/features-overview' },
@ -279,6 +282,14 @@ describe('<CurrentPlanWidget />', function () {
}, },
] ]
beforeEach(function () {
sendMBSpy = sinon.spy(eventTracking, 'sendMB')
})
afterEach(function () {
sendMBSpy.restore()
})
for (const variant of variants) { for (const variant of variants) {
describe(`${variant.name} variant`, function () { describe(`${variant.name} variant`, function () {
beforeEach(function () { beforeEach(function () {
@ -291,7 +302,7 @@ describe('<CurrentPlanWidget />', function () {
}) })
for (const plan of plans) { for (const plan of plans) {
it(`links to ${variant.name} features page on ${plan.type} plan`, function () { it(`links to ${variant.name} features page on ${plan.type} plan and sends analytics event`, function () {
window.metaAttributesCache.set('ol-usersBestSubscription', { window.metaAttributesCache.set('ol-usersBestSubscription', {
...plan, ...plan,
}) })
@ -300,6 +311,14 @@ describe('<CurrentPlanWidget />', function () {
const links = screen.getAllByRole('link') const links = screen.getAllByRole('link')
expect(links[0].getAttribute('href')).to.equal(variant.link) expect(links[0].getAttribute('href')).to.equal(variant.link)
fireEvent.click(links[0])
expect(sendMBSpy).to.be.calledOnce
expect(sendMBSpy).calledWith('features-page-link', {
splitTest: 'features-page',
splitTestVariant: variant.name,
page: '/',
})
window.metaAttributesCache.delete('ol-usersBestSubscription') window.metaAttributesCache.delete('ol-usersBestSubscription')
}) })
} }

View file

@ -75,7 +75,7 @@ describe('<LeaversSurveyAlert/>', function () {
expect(sendMBSpy).to.be.calledOnce expect(sendMBSpy).to.be.calledOnce
expect(sendMBSpy).calledWith( expect(sendMBSpy).calledWith(
'institutional-leavers-survey-notification', 'institutional-leavers-survey-notification',
{ type: 'view' } { type: 'view', page: '/' }
) )
}) })
@ -84,7 +84,7 @@ describe('<LeaversSurveyAlert/>', function () {
expect(sendMBSpy).to.be.calledTwice expect(sendMBSpy).to.be.calledTwice
expect(sendMBSpy).calledWith( expect(sendMBSpy).calledWith(
'institutional-leavers-survey-notification', 'institutional-leavers-survey-notification',
{ type: 'click' } { type: 'click', page: '/' }
) )
}) })
@ -93,7 +93,7 @@ describe('<LeaversSurveyAlert/>', function () {
expect(sendMBSpy).to.be.calledTwice expect(sendMBSpy).to.be.calledTwice
expect(sendMBSpy).calledWith( expect(sendMBSpy).calledWith(
'institutional-leavers-survey-notification', 'institutional-leavers-survey-notification',
{ type: 'close' } { type: 'close', page: '/' }
) )
}) })
}) })