1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: add user tracking to demo (#3637)

https://linear.app/unleash/issue/2-946/explore-and-implement-options-for-user-tracking

Adds user tracking to the interactive demo, so we can measure how users
are using this feature and improve it in the feature.

## Events

- **start** - When the user starts the demo by clicking on the "Try
Unleash Demo" button;
- **finish** - When the user finishes the demo by seeing the "You
finished the demo" dialog;
- **restart** - When the user decides to restart the demo on the "You
finished the demo" dialog;
- **close** - When the user closes a demo dialog;
- **topic** - In what topic this happened (topic title, can also be
`start` if user closes on the start dialog);
- **step** - In what step this happened (step number, `1` would mean
first step);
- **start_topic** - When the user decides to start a specific topic by
clicking it in the list;
  - **topic** - What topic was clicked (topic title);
- **ask_questions** - When the user decides to ask questions by clicking
the appropriate option in the top banner;
- **see_plans** - When the user decides to see the plans by clicking the
appropriate option in the top banner;
- **plan** - What plan was clicked (one of: `open_source`, `pro`,
`enterprise` or `compare_plans`);
- **open_demo_web** - User decided to open the demo website using the
link on the start dialog;
- **view_demo_link** - User decided to open the start dialog again on
the bottom of the topics list;

Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#3537
This commit is contained in:
Nuno Góis 2023-04-27 14:12:02 +01:00 committed by GitHub
parent 9deff83d74
commit 3c48171c78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 260 additions and 131 deletions

View File

@ -8,6 +8,7 @@ import { DemoDialogFinish } from './DemoDialog/DemoDialogFinish/DemoDialogFinish
import { DemoDialogPlans } from './DemoDialog/DemoDialogPlans/DemoDialogPlans'; import { DemoDialogPlans } from './DemoDialog/DemoDialogPlans/DemoDialogPlans';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { DemoBanner } from './DemoBanner/DemoBanner'; import { DemoBanner } from './DemoBanner/DemoBanner';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const defaultProgress = { const defaultProgress = {
welcomeOpen: true, welcomeOpen: true,
@ -22,6 +23,7 @@ interface IDemoProps {
export const Demo = ({ children }: IDemoProps): JSX.Element => { export const Demo = ({ children }: IDemoProps): JSX.Element => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const { trackEvent } = usePlausibleTracker();
const { value: storedProgress, setValue: setStoredProgress } = const { value: storedProgress, setValue: setStoredProgress } =
createLocalStorage('Tutorial:v1', defaultProgress); createLocalStorage('Tutorial:v1', defaultProgress);
@ -66,6 +68,12 @@ export const Demo = ({ children }: IDemoProps): JSX.Element => {
if (completedSteps === totalSteps) { if (completedSteps === totalSteps) {
setFinishOpen(true); setFinishOpen(true);
trackEvent('demo', {
props: {
eventType: 'finish',
},
});
} }
}; };
@ -76,6 +84,12 @@ export const Demo = ({ children }: IDemoProps): JSX.Element => {
<DemoBanner <DemoBanner
onPlans={() => { onPlans={() => {
setPlansOpen(true); setPlansOpen(true);
trackEvent('demo', {
props: {
eventType: 'see_plans',
},
});
}} }}
/> />
{children} {children}
@ -84,10 +98,23 @@ export const Demo = ({ children }: IDemoProps): JSX.Element => {
onClose={() => { onClose={() => {
setWelcomeOpen(false); setWelcomeOpen(false);
setExpanded(false); setExpanded(false);
trackEvent('demo', {
props: {
eventType: 'close',
topic: 'start',
},
});
}} }}
onStart={() => { onStart={() => {
setWelcomeOpen(false); setWelcomeOpen(false);
onStart(); onStart();
trackEvent('demo', {
props: {
eventType: 'start',
},
});
}} }}
/> />
<DemoDialogFinish <DemoDialogFinish
@ -99,6 +126,12 @@ export const Demo = ({ children }: IDemoProps): JSX.Element => {
onRestart={() => { onRestart={() => {
setFinishOpen(false); setFinishOpen(false);
onStart(); onStart();
trackEvent('demo', {
props: {
eventType: 'restart',
},
});
}} }}
/> />
<DemoDialogPlans <DemoDialogPlans
@ -117,9 +150,24 @@ export const Demo = ({ children }: IDemoProps): JSX.Element => {
newSteps[topic] = 0; newSteps[topic] = 0;
return newSteps; return newSteps;
}); });
trackEvent('demo', {
props: {
eventType: 'start_topic',
step: TOPICS[topic].title,
},
});
}} }}
topics={TOPICS} topics={TOPICS}
onWelcome={() => setWelcomeOpen(true)} onWelcome={() => {
setWelcomeOpen(true);
trackEvent('demo', {
props: {
eventType: 'view_demo_link',
},
});
}}
/> />
<DemoSteps <DemoSteps
setExpanded={setExpanded} setExpanded={setExpanded}

View File

@ -1,4 +1,5 @@
import { Button, styled } from '@mui/material'; import { Button, styled } from '@mui/material';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const StyledBanner = styled('div')(({ theme }) => ({ const StyledBanner = styled('div')(({ theme }) => ({
position: 'sticky', position: 'sticky',
@ -30,22 +31,33 @@ interface IDemoBannerProps {
onPlans: () => void; onPlans: () => void;
} }
export const DemoBanner = ({ onPlans }: IDemoBannerProps) => ( export const DemoBanner = ({ onPlans }: IDemoBannerProps) => {
<StyledBanner> const { trackEvent } = usePlausibleTracker();
<span>
This is a <strong>demo of Unleash</strong>. Play around as much as return (
you want. Reach out when you're ready. <StyledBanner>
</span> <span>
<StyledQuestionsButton This is a <strong>demo of Unleash</strong>. Play around as much
variant="outlined" as you want. Reach out when you're ready.
sx={{ ml: 1 }} </span>
href="https://slack.unleash.run/" <StyledQuestionsButton
target="_blank" variant="outlined"
> sx={{ ml: 1 }}
Ask questions href="https://slack.unleash.run/"
</StyledQuestionsButton> target="_blank"
<StyledButton variant="contained" color="primary" onClick={onPlans}> onClick={() => {
Get Unleash trackEvent('demo', {
</StyledButton> props: {
</StyledBanner> eventType: 'ask_questions',
); },
});
}}
>
Ask questions
</StyledQuestionsButton>
<StyledButton variant="contained" color="primary" onClick={onPlans}>
Get Unleash
</StyledButton>
</StyledBanner>
);
};

View File

@ -2,6 +2,7 @@ import { Button, Typography, styled } from '@mui/material';
import { DemoDialog } from '../DemoDialog'; import { DemoDialog } from '../DemoDialog';
import { GitHub } from '@mui/icons-material'; import { GitHub } from '@mui/icons-material';
import { Launch } from '@mui/icons-material'; import { Launch } from '@mui/icons-material';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const StyledDemoDialog = styled(DemoDialog)(({ theme }) => ({ const StyledDemoDialog = styled(DemoDialog)(({ theme }) => ({
'& .MuiDialog-paper': { '& .MuiDialog-paper': {
@ -51,80 +52,122 @@ interface IDemoDialogPlansProps {
onClose: () => void; onClose: () => void;
} }
export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => ( export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => {
<StyledDemoDialog open={open} onClose={onClose}> const { trackEvent } = usePlausibleTracker();
<DemoDialog.Header>Want to keep going with Unleash?</DemoDialog.Header>
<StyledPlans> return (
<StyledPlan> <StyledDemoDialog open={open} onClose={onClose}>
<Typography variant="h5" fontWeight="bold"> <DemoDialog.Header>
Open Source Want to keep going with Unleash?
</Typography> </DemoDialog.Header>
<Typography variant="body2" color="textSecondary"> <StyledPlans>
Self-hosted basic feature management solution <StyledPlan>
</Typography> <Typography variant="h5" fontWeight="bold">
<Typography variant="h6" fontWeight="normal"> Open Source
Free
</Typography>
<Button
variant="outlined"
color="primary"
startIcon={<GitHub />}
href="https://github.com/unleash/unleash"
target="_blank"
>
View project on GitHub
</Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Pro
</Typography>
<Typography variant="body2" color="textSecondary">
Free your team to collaborate. We'll do the heavy lifting.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
$80/month
</Typography> </Typography>
<Typography variant="body2">includes 5 seats</Typography> <Typography variant="body2" color="textSecondary">
</div> Self-hosted basic feature management solution
<Button
variant="contained"
color="primary"
href="https://www.getunleash.io/plans/pro"
target="_blank"
>
Start 14-day free trial
</Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Enterprise
</Typography>
<Typography variant="body2" color="textSecondary">
Security, compliance, and development controls for scale.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
Custom
</Typography> </Typography>
<Typography variant="body2">unlimited seats</Typography> <Typography variant="h6" fontWeight="normal">
</div> Free
<Button </Typography>
variant="contained" <Button
color="web" variant="outlined"
href="https://www.getunleash.io/plans/enterprise" color="primary"
target="_blank" startIcon={<GitHub />}
> href="https://github.com/unleash/unleash"
Contact sales target="_blank"
</Button> onClick={() => {
</StyledPlan> trackEvent('demo', {
</StyledPlans> props: {
<StyledCompareLink eventType: 'see_plan',
href="https://www.getunleash.io/plans" plan: 'open_source',
target="_blank" },
> });
Compare plans <Launch /> }}
</StyledCompareLink> >
</StyledDemoDialog> View project on GitHub
); </Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Pro
</Typography>
<Typography variant="body2" color="textSecondary">
Free your team to collaborate. We'll do the heavy
lifting.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
$80/month
</Typography>
<Typography variant="body2">
includes 5 seats
</Typography>
</div>
<Button
variant="contained"
color="primary"
href="https://www.getunleash.io/plans/pro"
target="_blank"
onClick={() => {
trackEvent('demo', {
props: {
eventType: 'see_plan',
plan: 'pro',
},
});
}}
>
Start 14-day free trial
</Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Enterprise
</Typography>
<Typography variant="body2" color="textSecondary">
Security, compliance, and development controls for
scale.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
Custom
</Typography>
<Typography variant="body2">unlimited seats</Typography>
</div>
<Button
variant="contained"
color="web"
href="https://www.getunleash.io/plans/enterprise"
target="_blank"
onClick={() => {
trackEvent('demo', {
props: {
eventType: 'see_plan',
plan: 'enterprise',
},
});
}}
>
Contact sales
</Button>
</StyledPlan>
</StyledPlans>
<StyledCompareLink
href="https://www.getunleash.io/plans"
target="_blank"
onClick={() => {
trackEvent('demo', {
props: {
eventType: 'see_plan',
plan: 'compare_plans',
},
});
}}
>
Compare plans <Launch />
</StyledCompareLink>
</StyledDemoDialog>
);
};

View File

@ -3,6 +3,7 @@ import qrImage from 'assets/img/demo_qr.png';
import { formatAssetPath } from 'utils/formatPath'; import { formatAssetPath } from 'utils/formatPath';
import { Launch } from '@mui/icons-material'; import { Launch } from '@mui/icons-material';
import { DemoDialog } from '../DemoDialog'; import { DemoDialog } from '../DemoDialog';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const StyledDemoPane = styled('div')(({ theme }) => ({ const StyledDemoPane = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
@ -55,39 +56,53 @@ export const DemoDialogWelcome = ({
open, open,
onClose, onClose,
onStart, onStart,
}: IDemoDialogWelcomeProps) => ( }: IDemoDialogWelcomeProps) => {
<DemoDialog open={open} onClose={onClose}> const { trackEvent } = usePlausibleTracker();
<DemoDialog.Header>Explore Unleash</DemoDialog.Header>
<Typography color="textSecondary" sx={{ mt: 2 }}> return (
You can explore Unleash on your own, however for the best experience <DemoDialog open={open} onClose={onClose}>
it's recommended you follow our interactive demo. To get started, <DemoDialog.Header>Explore Unleash</DemoDialog.Header>
you will need to open the demo website below. <Typography color="textSecondary" sx={{ mt: 2 }}>
</Typography> You can explore Unleash on your own, however for the best
<StyledDemoPane> experience it's recommended you follow our interactive demo. To
<StyledScanMessage> get started, you will need to open the demo website below.
Scan the QR code with your phone
</StyledScanMessage>
<StyledQRCode src={formatAssetPath(qrImage)} alt="Demo QR Code" />
<StyledDivider>OR</StyledDivider>
<Typography>
Open demo website in another tab:{' '}
<StyledLink
href="https://demo.unleash-hosted.com/"
target="_blank"
>
demo.unleash-hosted.com <Launch />
</StyledLink>
</Typography> </Typography>
<Typography color="textSecondary"> <StyledDemoPane>
(we recommend you keep the pages open side by side) <StyledScanMessage>
</Typography> Scan the QR code with your phone
</StyledDemoPane> </StyledScanMessage>
<StyledStartButton <StyledQRCode
variant="contained" src={formatAssetPath(qrImage)}
color="primary" alt="Demo QR Code"
onClick={onStart} />
> <StyledDivider>OR</StyledDivider>
Try Unleash demo <Typography>
</StyledStartButton> Open demo website in another tab:{' '}
</DemoDialog> <StyledLink
); href="https://demo.unleash-hosted.com/"
target="_blank"
onClick={() => {
trackEvent('demo', {
props: {
eventType: 'open_demo_web',
},
});
}}
>
demo.unleash-hosted.com <Launch />
</StyledLink>
</Typography>
<Typography color="textSecondary">
(we recommend you keep the pages open side by side)
</Typography>
</StyledDemoPane>
<StyledStartButton
variant="contained"
color="primary"
onClick={onStart}
>
Try Unleash demo
</StyledStartButton>
</DemoDialog>
);
};

View File

@ -8,6 +8,7 @@ import { ITutorialTopic, ITutorialTopicStep } from '../demo-topics';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { DemoStepTooltip } from './DemoStepTooltip/DemoStepTooltip'; import { DemoStepTooltip } from './DemoStepTooltip/DemoStepTooltip';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IDemoStepsProps { interface IDemoStepsProps {
setExpanded: React.Dispatch<React.SetStateAction<boolean>>; setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
@ -31,6 +32,7 @@ export const DemoSteps = ({
const theme = useTheme(); const theme = useTheme();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const { trackEvent } = usePlausibleTracker();
const [run, setRun] = useState(false); const [run, setRun] = useState(false);
const [flow, setFlow] = useState<'next' | 'back' | 'load'>('load'); const [flow, setFlow] = useState<'next' | 'back' | 'load'>('load');
@ -51,6 +53,14 @@ export const DemoSteps = ({
const close = () => { const close = () => {
abortController.abort(); abortController.abort();
setTopicStep(-1); setTopicStep(-1);
trackEvent('demo', {
props: {
eventType: 'close',
topic: topics[topic].title,
step: steps[topic] + 1,
},
});
}; };
const back = () => { const back = () => {

View File

@ -24,7 +24,8 @@ export type CustomEvents =
| 'project_stickiness_set' | 'project_stickiness_set'
| 'notifications' | 'notifications'
| 'batch_operations' | 'batch_operations'
| 'strategyTitle'; | 'strategyTitle'
| 'demo';
export const usePlausibleTracker = () => { export const usePlausibleTracker = () => {
const plausible = useContext(PlausibleContext); const plausible = useContext(PlausibleContext);