Skip to content

Commit 869e01f

Browse files
chore: Emit metric when wizard is unmounted
1 parent 747e321 commit 869e01f

File tree

4 files changed

+120
-7
lines changed

4 files changed

+120
-7
lines changed

pages/wizard/navigation.page.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React, { useState } from 'react';
4+
import Wizard, { WizardProps } from '~components/wizard';
5+
import Toggle from '~components/toggle';
6+
import Button from '~components/button';
7+
import Link from '~components/link';
8+
import styles from './styles.scss';
9+
10+
import { i18nStrings } from './common';
11+
12+
const steps: WizardProps.Step[] = [
13+
{
14+
title: 'Step 1',
15+
content: (
16+
<div className={styles['step-content']}>
17+
<div id="content-text">Content 1</div>
18+
</div>
19+
),
20+
},
21+
{
22+
title: 'Step 2',
23+
content: (
24+
<div className={styles['step-content']}>
25+
<div id="content-text">Content 2</div>
26+
</div>
27+
),
28+
},
29+
{
30+
title: 'Step 3',
31+
info: <Link variant="info">Info</Link>,
32+
content: (
33+
<div className={styles['step-content']}>
34+
{Array.from(Array(15).keys()).map(key => (
35+
<div key={key} className={styles['content-item']}>
36+
Item {key}
37+
</div>
38+
))}
39+
</div>
40+
),
41+
},
42+
];
43+
44+
export default function WizardPage() {
45+
const [activeStepIndex, setActiveStepIndex] = useState(0);
46+
const [renderWizard, setRenderWizard] = useState<boolean>(true);
47+
return (
48+
<div>
49+
<Toggle checked={renderWizard} ariaLabel={'toggle'} onChange={({ detail }) => setRenderWizard(detail.checked)} />
50+
<input id="focus-reset" aria-label="input" />
51+
{renderWizard && (
52+
<Wizard
53+
id="wizard"
54+
steps={steps}
55+
i18nStrings={i18nStrings}
56+
activeStepIndex={activeStepIndex}
57+
onNavigate={e => setActiveStepIndex(e.detail.requestedStepIndex)}
58+
secondaryActions={activeStepIndex === 2 ? <Button>Save as draft</Button> : null}
59+
/>
60+
)}
61+
</div>
62+
);
63+
}

src/wizard/__tests__/wizard.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,6 @@ describe('Metrics', () => {
695695
eventContext: 'csa_wizard_step2',
696696
eventDetail: 'step2',
697697
eventType: 'csa_wizard_submit',
698-
eventValue: expect.any(String),
699698
timestamp: expect.any(Number),
700699
})
701700
);

src/wizard/index.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ import useBaseComponent from '../internal/hooks/use-base-component';
1616
import { useMergeRefs } from '../internal/hooks/use-merge-refs';
1717
import { useVisualRefresh } from '../internal/hooks/use-visual-mode';
1818

19-
import { trackStartStep, trackNavigate, trackSubmit, trackStartWizard } from './internal/analytics';
19+
import {
20+
trackStartStep,
21+
trackNavigate,
22+
trackSubmit,
23+
trackStartWizard,
24+
trackEndWizard,
25+
trackCancel,
26+
} from './internal/analytics';
2027

2128
export { WizardProps };
2229

@@ -61,7 +68,10 @@ export default function Wizard({
6168
};
6269
const onStepClick = (stepIndex: number) => navigationEvent(stepIndex, 'step');
6370
const onSkipToClick = (stepIndex: number) => navigationEvent(stepIndex, 'skip');
64-
const onCancelClick = () => fireNonCancelableEvent(onCancel);
71+
const onCancelClick = () => {
72+
trackCancel(actualActiveStepIndex, funnelId);
73+
fireNonCancelableEvent(onCancel);
74+
};
6575
const onPreviousClick = () => navigationEvent(actualActiveStepIndex - 1, 'previous');
6676
const onPrimaryClick = () => {
6777
if (isLastStep) {
@@ -90,6 +100,11 @@ export default function Wizard({
90100

91101
useEffect(() => {
92102
trackStartWizard();
103+
104+
return () => {
105+
trackEndWizard(funnelId);
106+
};
107+
// eslint-disable-next-line react-hooks/exhaustive-deps -- this is intentional
93108
}, []);
94109

95110
useEffect(() => {

src/wizard/internal/analytics.tsx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ const createEventDetail = (stepIndex = 0) => `step${stepIndex + 1}`;
1616
// A custom time cache is used to not clear the timer between navigation attempts
1717
// This allows us the ability to track time to attempt each step as well as the time to complete
1818
// each step
19-
const timeCache: Record<string, number> = {};
19+
let timeCache: Record<string, number>;
20+
let currentStepIndex: number;
21+
let success: boolean;
22+
2023
const timeStart = (key = 'current') => {
2124
timeCache[key] = Date.now();
2225
};
@@ -36,10 +39,29 @@ const timeEnd = (key = 'current', clear = false) => {
3639
};
3740

3841
export const trackStartWizard = () => {
42+
timeCache = {};
43+
currentStepIndex = 0;
44+
success = false;
45+
3946
timeStart(prefix);
4047
};
4148

42-
export const trackStartStep = (stepIndex?: number, funnelId?: string) => {
49+
export const trackEndWizard = (funnelId: string | undefined) => {
50+
// End the timer of the wizard
51+
const time = timeEnd(prefix, true);
52+
53+
const eventContext = createEventContext(currentStepIndex);
54+
metrics.sendPanoramaMetric({
55+
eventContext,
56+
eventDetail: `${success}`,
57+
eventType: createEventType('end'),
58+
...(time !== undefined && { eventValue: time.toString() }),
59+
...(funnelId && { funnel: funnelId }),
60+
});
61+
};
62+
63+
export const trackStartStep = (stepIndex: number, funnelId?: string) => {
64+
currentStepIndex = stepIndex;
4365
const eventContext = createEventContext(stepIndex);
4466

4567
// End the timer of the previous step
@@ -76,9 +98,9 @@ export const trackNavigate = (
7698
};
7799

78100
export const trackSubmit = (stepIndex: number, funnelId?: string) => {
79-
const eventContext = createEventContext(stepIndex);
80-
// End the timer of the wizard
101+
success = true;
81102
const time = timeEnd(prefix);
103+
const eventContext = createEventContext(stepIndex);
82104

83105
metrics.sendPanoramaMetric({
84106
eventContext,
@@ -88,3 +110,17 @@ export const trackSubmit = (stepIndex: number, funnelId?: string) => {
88110
...(funnelId && { funnel: funnelId }),
89111
});
90112
};
113+
114+
export const trackCancel = (stepIndex: number, funnelId?: string) => {
115+
success = false;
116+
const time = timeEnd(prefix);
117+
const eventContext = createEventContext(stepIndex);
118+
119+
metrics.sendPanoramaMetric({
120+
eventContext,
121+
eventDetail: createEventDetail(stepIndex),
122+
eventType: createEventType('cancel'),
123+
...(time !== undefined && { eventValue: time.toString() }),
124+
...(funnelId && { funnel: funnelId }),
125+
});
126+
};

0 commit comments

Comments
 (0)