Add new event tracking to react and angular version of the empty project page (#11472)

GitOrigin-RevId: 28ffe919851121bdba82eea3b6ef29cd6fffeb76
This commit is contained in:
M Fahru 2023-01-30 10:16:45 -07:00 committed by Copybot
parent 56cb937672
commit 3507463c4e
5 changed files with 240 additions and 17 deletions

View file

@ -4,9 +4,21 @@
div.welcome.text-centered(ng-cloak)
h2 #{translate("welcome_to_sl")}
p #{translate("new_to_latex_look_at")}
a(href="/templates") #{translate("templates").toLowerCase()}
a(
href="/templates"
event-tracking="welcome-page-templates-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default"}'
) #{translate("templates").toLowerCase()}
| #{translate("or")}
a(href="/learn") #{translate("latex_help_guide")}
a(
href="/learn"
event-tracking="welcome-page-latex-help-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default"}'
) #{translate("latex_help_guide")}
.row
@ -16,7 +28,12 @@
href="#",
data-toggle="dropdown",
dropdown-toggle
event-tracking="welcome-page-create-first-project-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default", "dropdownMenu": "main-button", "dropdownOpen": "null" }'
)
//- We can't know if dropdown is open or not, so will send "dropdownOpen: null" as a segmentation above
| Create First Project
ul.dropdown-menu.minimal-create-proj-dropdown-menu(role="menu")
@ -24,23 +41,42 @@
a(
href,
ng-click="openCreateProjectModal()"
event-tracking="welcome-page-create-first-project-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default", "dropdownMenu": "blank-project", "dropdownOpen": "true" }'
) #{translate("blank_project")}
li
a(
href,
ng-click="openCreateProjectModal('example')"
event-tracking="welcome-page-create-first-project-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default", "dropdownMenu": "example-project", "dropdownOpen": "true" }'
) #{translate("example_project")}
li
a(
href,
ng-click="openUploadProjectModal()"
event-tracking="welcome-page-create-first-project-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation='{"project-dashboard-react": "default", "dropdownMenu": "upload-project", "dropdownOpen": "true" }'
) #{translate("upload_project")}
!= moduleIncludes("newProjectMenu", locals)
if (templates)
li.divider
li.dropdown-header #{translate("templates")}
each item in templates
- var eventSegmentation = '{"project-dashboard-react": "default", "dropdownMenu":"' + item.trackingKey + '", "dropdownOpen": "true" }'
li
a.menu-indent(href=item.url) #{translate(item.name)}
a.menu-indent(
href=item.url
event-tracking="welcome-page-create-first-project-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation=eventSegmentation
) #{translate(item.name)}

View file

@ -1,4 +1,4 @@
import { useState } from 'react'
import { useCallback, useState } from 'react'
import { Dropdown, MenuItem } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { ExposedSettings } from '../../../../../types/exposed-settings'
@ -9,17 +9,35 @@ import NewProjectButtonModal, {
NewProjectButtonModalVariant,
} from './new-project-button/new-project-button-modal'
import { Nullable } from '../../../../../types/utils'
import { sendMB } from '../../../infrastructure/event-tracking'
type SendTrackingEvent = {
dropdownMenu: string
dropdownOpen: boolean
institutionTemplateName?: string
}
type Segmentation = SendTrackingEvent & {
'project-dashboard-react': 'enabled'
}
type ModalMenuClickOptions = {
modalVariant: NewProjectButtonModalVariant
dropdownMenuEvent: string
}
type NewProjectButtonProps = {
id: string
buttonText?: string
className?: string
trackingKey?: string
}
function NewProjectButton({
id,
buttonText,
className,
trackingKey,
}: NewProjectButtonProps) {
const { t } = useTranslation()
const { templateLinks } = getMeta('ol-ExposedSettings') as ExposedSettings
@ -27,9 +45,100 @@ function NewProjectButton({
useState<Nullable<NewProjectButtonModalVariant>>(null)
const portalTemplates = getMeta('ol-portalTemplates') as PortalTemplate[]
const sendTrackingEvent = useCallback(
({
dropdownMenu,
dropdownOpen,
institutionTemplateName,
}: SendTrackingEvent) => {
if (trackingKey) {
let segmentation: Segmentation = {
'project-dashboard-react': 'enabled',
dropdownMenu,
dropdownOpen,
}
if (institutionTemplateName) {
segmentation = {
...segmentation,
institutionTemplateName,
}
}
sendMB(trackingKey, segmentation)
}
},
[trackingKey]
)
const handleMainButtonClick = useCallback(
(dropdownOpen: boolean) => {
sendTrackingEvent({
dropdownMenu: 'main-button',
dropdownOpen,
})
},
[sendTrackingEvent]
)
const handleModalMenuClick = useCallback(
(
e: React.MouseEvent<Record<string, unknown>>,
{ modalVariant, dropdownMenuEvent }: ModalMenuClickOptions
) => {
// avoid invoking the "onClick" callback on the main dropdown button
e.stopPropagation()
sendTrackingEvent({
dropdownMenu: dropdownMenuEvent,
dropdownOpen: true,
})
setModal(modalVariant)
},
[sendTrackingEvent]
)
const handlePortalTemplateClick = useCallback(
(
e: React.MouseEvent<Record<string, unknown>>,
institutionTemplateName: string
) => {
// avoid invoking the "onClick" callback on the main dropdown button
e.stopPropagation()
sendTrackingEvent({
dropdownMenu: 'institution-template',
dropdownOpen: true,
institutionTemplateName,
})
},
[sendTrackingEvent]
)
const handleStaticTemplateClick = useCallback(
(
e: React.MouseEvent<Record<string, unknown>>,
templateTrackingKey: string
) => {
// avoid invoking the "onClick" callback on the main dropdown button
e.stopPropagation()
sendTrackingEvent({
dropdownMenu: templateTrackingKey,
dropdownOpen: true,
})
},
[sendTrackingEvent]
)
return (
<>
<ControlledDropdown id={id} className={className}>
<ControlledDropdown
id={id}
className={className}
onMainButtonClick={handleMainButtonClick}
>
<Dropdown.Toggle
noCaret
className="new-project-button"
@ -38,16 +147,44 @@ function NewProjectButton({
{buttonText || t('new_project')}
</Dropdown.Toggle>
<Dropdown.Menu>
<MenuItem onClick={() => setModal('blank_project')}>
<MenuItem
onClick={e =>
handleModalMenuClick(e, {
modalVariant: 'blank_project',
dropdownMenuEvent: 'blank-project',
})
}
>
{t('blank_project')}
</MenuItem>
<MenuItem onClick={() => setModal('example_project')}>
<MenuItem
onClick={e =>
handleModalMenuClick(e, {
modalVariant: 'example_project',
dropdownMenuEvent: 'example-project',
})
}
>
{t('example_project')}
</MenuItem>
<MenuItem onClick={() => setModal('upload_project')}>
<MenuItem
onClick={e =>
handleModalMenuClick(e, {
modalVariant: 'upload_project',
dropdownMenuEvent: 'upload-project',
})
}
>
{t('upload_project')}
</MenuItem>
<MenuItem onClick={() => setModal('import_from_github')}>
<MenuItem
onClick={e =>
handleModalMenuClick(e, {
modalVariant: 'import_from_github',
dropdownMenuEvent: 'import-from-github',
})
}
>
{t('import_from_github')}
</MenuItem>
{portalTemplates?.length > 0 ? (
@ -60,6 +197,9 @@ function NewProjectButton({
<MenuItem
key={`portal-template-${index}`}
href={`${portalTemplate.url}#templates`}
onClick={e =>
handlePortalTemplateClick(e, portalTemplate.name)
}
>
{portalTemplate.name}
</MenuItem>
@ -72,6 +212,9 @@ function NewProjectButton({
<MenuItem
key={`new-project-button-template-${index}`}
href={templateLink.url}
onClick={e =>
handleStaticTemplateClick(e, templateLink.trackingKey)
}
>
{templateLink.name === 'view_all'
? t('view_all')

View file

@ -1,19 +1,37 @@
import { useCallback } from 'react'
import { Col, Row } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { sendMB } from '../../../infrastructure/event-tracking'
import NewProjectButton from './new-project-button'
export default function WelcomeMessage() {
const { t } = useTranslation()
const handleTemplatesClick = useCallback(() => {
sendMB('welcome-page-templates-click', {
'project-dashboard-react': 'enabled',
})
}, [])
const handleLatexHelpClick = useCallback(() => {
sendMB('welcome-page-latex-help-click', {
'project-dashboard-react': 'enabled',
})
}, [])
return (
<div className="card card-thin">
<div className="welcome text-centered">
<h2>{t('welcome_to_sl')}</h2>
<p>
{t('new_to_latex_look_at')}&nbsp;
<a href="/templates">{t('templates').toLowerCase()}</a>
<a href="/templates" onClick={handleTemplatesClick}>
{t('templates').toLowerCase()}
</a>
&nbsp;{t('or')}&nbsp;
<a href="/learn">{t('latex_help_guide')}</a>
<a href="/learn" onClick={handleLatexHelpClick}>
{t('latex_help_guide')}
</a>
</p>
<Row>
<Col md={4} mdOffset={4}>
@ -21,6 +39,7 @@ export default function WelcomeMessage() {
<NewProjectButton
id="new-project-button-welcome"
buttonText={t('create_first_project')}
trackingKey="welcome-page-create-first-project-click"
/>
</div>
</Col>

View file

@ -1,14 +1,38 @@
import { Children, cloneElement, type FC, isValidElement } from 'react'
import React, {
Children,
cloneElement,
type FC,
isValidElement,
useCallback,
} from 'react'
import { Dropdown, DropdownProps } from 'react-bootstrap'
import useDropdown from '../hooks/use-dropdown'
const ControlledDropdown: FC<
DropdownProps & { defaultOpen?: boolean }
> = props => {
const dropdownProps = useDropdown(Boolean(props.defaultOpen))
type ControlledDropdownProps = DropdownProps & {
defaultOpen?: boolean
onMainButtonClick?: (dropdownOpen: boolean) => void
}
const ControlledDropdown: FC<ControlledDropdownProps> = ({
defaultOpen,
onMainButtonClick,
...props
}) => {
const { onClick, ...dropdownProps } = useDropdown(Boolean(defaultOpen))
const handleClick = useCallback(
(e: React.MouseEvent<Dropdown, MouseEvent>) => {
onClick(e)
if (onMainButtonClick) {
onMainButtonClick(dropdownProps.open)
}
},
[onClick, onMainButtonClick, dropdownProps.open]
)
return (
<Dropdown {...props} {...dropdownProps}>
<Dropdown {...props} {...dropdownProps} onClick={handleClick}>
{Children.map(props.children, child => {
if (!isValidElement(child)) {
return child

View file

@ -1,6 +1,7 @@
type TemplateLink = {
name: string
url: string
trackingKey: string
}
export type ExposedSettings = {