mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add new event tracking to react and angular version of the empty project page (#11472)
GitOrigin-RevId: 28ffe919851121bdba82eea3b6ef29cd6fffeb76
This commit is contained in:
parent
56cb937672
commit
3507463c4e
5 changed files with 240 additions and 17 deletions
|
@ -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)}
|
||||
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')}
|
||||
<a href="/templates">{t('templates').toLowerCase()}</a>
|
||||
<a href="/templates" onClick={handleTemplatesClick}>
|
||||
{t('templates').toLowerCase()}
|
||||
</a>
|
||||
{t('or')}
|
||||
<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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
type TemplateLink = {
|
||||
name: string
|
||||
url: string
|
||||
trackingKey: string
|
||||
}
|
||||
|
||||
export type ExposedSettings = {
|
||||
|
|
Loading…
Reference in a new issue