mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
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:
parent
38db8bee30
commit
bd3b9007c8
8 changed files with 87 additions and 8 deletions
|
@ -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>
|
||||||
|
|
|
@ -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>{' '}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: '/' }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue