Skip to content

Commit

Permalink
chore: Emit component updated metrics during table interactions (#2901)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldowseza authored Oct 23, 2024
1 parent fd86923 commit b1a1a4b
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 161 deletions.
10 changes: 9 additions & 1 deletion src/internal/analytics/__tests__/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { setFunnelMetrics, setPerformanceMetrics } from '../../../../lib/components/internal/analytics';
import {
setComponentMetrics,
setFunnelMetrics,
setPerformanceMetrics,
} from '../../../../lib/components/internal/analytics';

export const mockedFunnelInteractionId = 'mocked-funnel-id';
export function mockFunnelMetrics() {
Expand Down Expand Up @@ -33,6 +37,10 @@ export function mockPerformanceMetrics() {
});
}

export function mockComponentMetrics() {
setComponentMetrics({ componentMounted: jest.fn(), componentUpdated: jest.fn() });
}

export function mockInnerText() {
if (!('innerText' in HTMLElement.prototype)) {
// JSDom does not support the `innerText` property. For tests, `textContent` is usually close enough.
Expand Down
2 changes: 2 additions & 0 deletions src/internal/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ export let ComponentMetrics: IComponentMetrics = {
componentMounted(): string {
return '';
},

componentUpdated(): void {},
};
15 changes: 14 additions & 1 deletion src/internal/analytics/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,27 @@ export interface IPerformanceMetrics {
modalPerformanceData: ModalPerformanceDataMethod;
}

type JSONValue = string | number | boolean | null | undefined;
export interface JSONObject {
[key: string]: JSONObject | JSONValue;
}

export interface ComponentMountedProps {
componentName: string;
taskInteractionId?: string;
details: Record<string, string | boolean | number | undefined>;
componentConfiguration: JSONObject;
}

export interface ComponentUpdatedProps extends ComponentMountedProps {
taskInteractionId: string;
actionType: string;
}

export type ComponentMountedMethod = (props: ComponentMountedProps) => string;
export type ComponentUpdatedMethod = (props: ComponentUpdatedProps) => void;
export interface IComponentMetrics {
componentMounted: ComponentMountedMethod;
componentUpdated: ComponentUpdatedMethod;
}

// Interface for modal metrics
Expand Down

This file was deleted.

39 changes: 0 additions & 39 deletions src/internal/hooks/use-component-analytics/index.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/internal/hooks/use-dom-attribute/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { useEffect, useRef } from 'react';

/*
* This hook allows setting an DOM attribute after the first render, without rerendering the component.
*/
export function useDOMAttribute(elementRef: React.RefObject<HTMLElement>, attributeName: string, value: string) {
const attributeValueRef = useRef<string | undefined>();

useEffect(() => {
// With this effect, we apply the attribute only on the client, to avoid hydration errors.
attributeValueRef.current = value;
elementRef.current?.setAttribute(attributeName, value);
}, [attributeName, value, elementRef]);

return {
[attributeName]: attributeValueRef.current,
};
}
25 changes: 4 additions & 21 deletions src/internal/hooks/use-performance-marks/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { useEffect, useRef } from 'react';
import { useEffect } from 'react';

import { useModalContext } from '../../context/modal-context';
import { useDOMAttribute } from '../use-dom-attribute';
import { useEffectOnUpdate } from '../use-effect-on-update';
import { useRandomId } from '../use-unique-id';

/*
This hook allows setting an HTML attribute after the first render, without rerendering the component.
*/
function usePerformanceMarkAttribute(elementRef: React.RefObject<HTMLElement>, value: string) {
const attributeName = 'data-analytics-performance-mark';

const attributeValueRef = useRef<string | undefined>();

useEffect(() => {
// With this effect, we apply the attribute only on the client, to avoid hydration errors.
attributeValueRef.current = value;
elementRef.current?.setAttribute(attributeName, value);
}, [value, elementRef]);

return {
[attributeName]: attributeValueRef.current,
};
}

/**
* This function returns an object that needs to be spread onto the same
* element as the `elementRef`, so that the data attribute is applied
Expand All @@ -40,7 +22,8 @@ export function usePerformanceMarks(
) {
const id = useRandomId();
const { isInModal } = useModalContext();
const attributes = usePerformanceMarkAttribute(elementRef, id);
const attributes = useDOMAttribute(elementRef, 'data-analytics-performance-mark', id);

useEffect(() => {
if (!enabled || !elementRef.current || isInModal) {
return;
Expand Down
Loading

0 comments on commit b1a1a4b

Please sign in to comment.