Skip to content

Commit

Permalink
feat: STAKE-827: track additional pooled staking events (#12290)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
Adds additional event tracking for pooled-staking tooltips and currency
switching.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Related issues**

Jira Ticket: [STAKE-827: Track more events in
Mixpanel](https://consensyssoftware.atlassian.net/browse/STAKE-827)

## **Manual testing steps**

**note: there's an ongoing issues with tracking events on local dev.
Results may vary.**

Prerequisite: Add `export MM_POOLED_STAKING_UI_ENABLED=true` to your
local `.js.env` file

Testing Currency Switch Events
1. Click on Ethereum in assets list
2. Click "Stake", "Stake More", or "Unstake" buttons to navigate to the
input screen
3. Switch the currency between native and fiat near the top of the
screen

Testing Tooltip Events
1. Click on Ethereum in assets list
2. Click on available tooltip icons: 
  - Annual rate in the "Your earnings" section within ETH details page
  - Learn more tooltip on the staking input screen
  - Various tooltips on the stake and unstake confirmation views
## **Screenshots/Recordings**
N/A

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
Matt561 authored Nov 14, 2024
1 parent 22a4989 commit 7b9bd02
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const KeyValueRowLabel = ({ label, tooltip }: KeyValueRowLabelProps) => {
const onNavigateToTooltipModal = () => {
if (!hasTooltip) return;
openTooltipModal(tooltip.title, tooltip.content);
tooltip?.onPress?.();
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ interface KeyValueRowTooltip {
* @default TooltipSizes.Md
*/
size?: ButtonIconSizes;
/**
* Optional onPress handler
*/
onPress?: (...args: unknown[]) => unknown;
}

/**
Expand Down
31 changes: 20 additions & 11 deletions app/components/UI/Stake/Views/StakeInputView/StakeInputView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import styleSheet from './StakeInputView.styles';
import useStakingInputHandlers from '../../hooks/useStakingInput';
import InputDisplay from '../../components/InputDisplay';
import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics';
import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics';

const StakeInputView = () => {
const title = strings('stake.stake_eth');
Expand Down Expand Up @@ -55,15 +56,6 @@ const StakeInputView = () => {
navigation.navigate('StakeModals', {
screen: Routes.STAKING.MODALS.LEARN_MORE,
});
trackEvent(
createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED)
.addProperties({
selected_provider: 'consensys',
text: 'Tooltip Question Mark Trigger',
location: 'Stake Input View',
})
.build(),
);
};

const handleStakePress = useCallback(() => {
Expand Down Expand Up @@ -153,13 +145,30 @@ const StakeInputView = () => {
fiatAmount={fiatAmount}
isEth={isEth}
currentCurrency={currentCurrency}
handleCurrencySwitch={handleCurrencySwitch}
handleCurrencySwitch={withMetaMetrics(handleCurrencySwitch, {
event: MetaMetricsEvents.STAKE_INPUT_CURRENCY_SWITCH_CLICKED,
properties: {
selected_provider: 'consensys',
text: 'Currency Switch Trigger',
location: 'Stake Input View',
// We want to track the currency switching to. Not the current currency.
currency_type: isEth ? 'fiat' : 'native',
},
})}
currencyToggleValue={currencyToggleValue}
/>
<View style={styles.rewardsRateContainer}>
<EstimatedAnnualRewardsCard
estimatedAnnualRewards={estimatedAnnualRewards}
onIconPress={navigateToLearnMoreModal}
onIconPress={withMetaMetrics(navigateToLearnMoreModal, {
event: MetaMetricsEvents.TOOLTIP_OPENED,
properties: {
selected_provider: 'consensys',
text: 'Tooltip Opened',
location: 'Stake Input View',
tooltip_name: 'MetaMask Pool Estimated Rewards',
},
})}
isLoading={isLoadingVaultData}
/>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ exports[`StakeInputView render matches snapshot 1`] = `
onPress={[Function]}
>
<SvgMock
color="#6a737d"
color="#9fa6ae"
height={16}
name="Question"
style={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import InputDisplay from '../../components/InputDisplay';
import Routes from '../../../../../constants/navigation/Routes';
import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics';
import useUnstakingInputHandlers from '../../hooks/useUnstakingInput';
import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics';

const UnstakeInputView = () => {
const title = strings('stake.unstake_eth');
Expand Down Expand Up @@ -68,14 +69,21 @@ const UnstakeInputView = () => {
});
trackEvent(
createEventBuilder(MetaMetricsEvents.REVIEW_UNSTAKE_BUTTON_CLICKED)
.addProperties({
selected_provider: 'consensys',
tokens_to_stake_native_value: amountEth,
tokens_to_stake_usd_value: fiatAmount,
})
.build(),
.addProperties({
selected_provider: 'consensys',
tokens_to_stake_native_value: amountEth,
tokens_to_stake_usd_value: fiatAmount,
})
.build(),
);
}, [amountEth, amountWei, createEventBuilder, fiatAmount, navigation, trackEvent]);
}, [
amountEth,
amountWei,
createEventBuilder,
fiatAmount,
navigation,
trackEvent,
]);

return (
<ScreenLayout style={styles.container}>
Expand All @@ -88,7 +96,16 @@ const UnstakeInputView = () => {
fiatAmount={fiatAmount}
isEth={isEth}
currentCurrency={currentCurrency}
handleCurrencySwitch={handleCurrencySwitch}
handleCurrencySwitch={withMetaMetrics(handleCurrencySwitch, {
event: MetaMetricsEvents.UNSTAKE_INPUT_CURRENCY_SWITCH_CLICKED,
properties: {
selected_provider: 'consensys',
text: 'Currency Switch Trigger',
location: 'Unstake Input View',
// We want to track the currency switching to. Not the current currency.
currency_type: isEth ? 'fiat' : 'native',
},
})}
currencyToggleValue={currencyToggleValue}
/>
<UnstakeInputViewBanner style={styles.unstakeBanner} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const EstimatedAnnualRewardsCard = ({
>
<Icon
name={IconName.Question}
color={IconColor.Alternative}
color={IconColor.Muted}
size={IconSize.Sm}
/>
</TouchableOpacity>
Expand Down
39 changes: 20 additions & 19 deletions app/components/UI/Stake/components/LearnMoreModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import { useNavigation } from '@react-navigation/native';
import { strings } from '../../../../../../locales/i18n';
import { POOLED_STAKING_FAQ_URL } from '../../constants';
import createLearnMoreModalStyles from './LearnMoreModal.styles';
import { MetaMetricsEvents, useMetrics } from '../../../../hooks/useMetrics';
import { MetaMetricsEvents } from '../../../../hooks/useMetrics';
import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics';

const styles = createLearnMoreModalStyles();

Expand All @@ -42,12 +43,21 @@ const LearnMoreModal = () => {
const sheetRef = useRef<BottomSheetRef>(null);

const navigation = useNavigation();
const { trackEvent, createEventBuilder } = useMetrics();

const handleClose = () => {
sheetRef.current?.onCloseBottomSheet();
};

const handleLearnMoreBrowserRedirect = () => {
// Take to the faq page
navigation.navigate('Webview', {
screen: 'SimpleWebview',
params: {
url: POOLED_STAKING_FAQ_URL,
},
});
};

return (
<BottomSheet ref={sheetRef}>
<View style={styles.container}>
Expand Down Expand Up @@ -86,23 +96,14 @@ const LearnMoreModal = () => {
<View style={styles.buttonContainer}>
<View style={styles.button}>
<Button
onPress={() => {
navigation.navigate('Webview', {
screen: 'SimpleWebview',
params: {
url: POOLED_STAKING_FAQ_URL,
},
});
trackEvent(
createEventBuilder(MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED)
.addProperties({
selected_provider: 'consensys',
text: 'Learn More',
location: 'Learn More Modal'
})
.build()
);
}} // Take to the faq page
onPress={withMetaMetrics(handleLearnMoreBrowserRedirect, {
event: MetaMetricsEvents.STAKE_LEARN_MORE_CLICKED,
properties: {
selected_provider: 'consensys',
text: 'Learn More',
location: 'Learn More Modal',
},
})}
label={strings('stake.learn_more')}
variant={ButtonVariants.Secondary}
width={ButtonWidthTypes.Full}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { useStyles } from '../../../../../hooks/useStyles';
import Card from '../../../../../../component-library/components/Cards/Card';
import styleSheet from './RewardsCard.styles';
import { RewardsCardProps } from './RewardsCard.types';
import { createTooltipOpenedEvent } from '../../../utils/metaMetrics/tooltipMetaMetricsUtils';
import { useMetrics } from '../../../../../hooks/useMetrics';

const RewardsCard = ({
rewardRate,
Expand All @@ -20,6 +22,8 @@ const RewardsCard = ({
}: RewardsCardProps) => {
const { styles } = useStyles(styleSheet, {});

const { trackEvent } = useMetrics();

return (
<Card style={styles.card} disabled>
<KeyValueRow
Expand All @@ -29,6 +33,10 @@ const RewardsCard = ({
title: strings('tooltip_modal.reward_rate.title'),
content: strings('tooltip_modal.reward_rate.tooltip'),
size: TooltipSizes.Sm,
onPress: () =>
trackEvent(
createTooltipOpenedEvent('Rewards Card', 'Reward Rate'),
),
},
}}
value={{
Expand Down Expand Up @@ -57,6 +65,10 @@ const RewardsCard = ({
title: strings('tooltip_modal.reward_frequency.title'),
content: strings('tooltip_modal.reward_frequency.tooltip'),
size: TooltipSizes.Sm,
onPress: () =>
trackEvent(
createTooltipOpenedEvent('Rewards Card', 'Reward Frequency'),
),
},
}}
value={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import { useStyles } from '../../../../../hooks/useStyles';
import styleSheet from './UnstakeTimeCard.styles';
import { TextVariant } from '../../../../../../component-library/components/Texts/Text';
import { strings } from '../../../../../../../locales/i18n';
import { useMetrics } from '../../../../../hooks/useMetrics';
import { createTooltipOpenedEvent } from '../../../utils/metaMetrics/tooltipMetaMetricsUtils';

const UnstakingTimeCard = () => {
const { styles } = useStyles(styleSheet, {});

const { trackEvent } = useMetrics();

return (
<Card style={styles.card} disabled>
<KeyValueRow
Expand All @@ -20,6 +24,13 @@ const UnstakingTimeCard = () => {
title: strings('tooltip_modal.unstaking_time.title'),
content: strings('tooltip_modal.unstaking_time.tooltip'),
size: TooltipSizes.Sm,
onPress: () =>
trackEvent(
createTooltipOpenedEvent(
'Unstaking Time Card',
'Unstaking Time',
),
),
},
}}
value={{
Expand Down
13 changes: 11 additions & 2 deletions app/components/UI/Stake/components/StakingEarnings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import { StakeSDKProvider } from '../../sdk/stakeSdkProvider';
import useStakingEarnings from '../../hooks/useStakingEarnings';
import usePooledStakes from '../../hooks/usePooledStakes';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
import { withMetaMetrics } from '../../utils/metaMetrics/withMetaMetrics';
import { MetaMetricsEvents } from '../../../../hooks/useMetrics';
import { getTooltipMetricProperties } from '../../utils/metaMetrics/tooltipMetaMetricsUtils';

const StakingEarningsContent = () => {
const { styles } = useStyles(styleSheet, {});
Expand All @@ -38,7 +41,7 @@ const StakingEarningsContent = () => {
isLoadingEarningsData,
} = useStakingEarnings();

const onNavigateToTooltipModal = () =>
const onDisplayAnnualRateTooltip = () =>
openTooltipModal(
strings('stake.annual_rate'),
strings('tooltip_modal.reward_rate.tooltip'),
Expand Down Expand Up @@ -76,7 +79,13 @@ const StakingEarningsContent = () => {
accessibilityLabel={strings(
'stake.accessibility_labels.stake_annual_rate_tooltip',
)}
onPress={onNavigateToTooltipModal}
onPress={withMetaMetrics(onDisplayAnnualRateTooltip, {
event: MetaMetricsEvents.TOOLTIP_OPENED,
properties: getTooltipMetricProperties(
'Staking Earnings',
'Annual Rate',
),
})}
/>
</View>
{isLoadingEarningsData ? (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MetricsEventBuilder } from '../../../../../core/Analytics/MetricsEventBuilder';
import { MetaMetricsEvents } from '../../../../hooks/useMetrics';

export const getTooltipMetricProperties = (
location: string,
tooltipName: string,
) => ({
selected_provider: 'consensys',
text: 'Tooltip Opened',
location,
tooltip_name: tooltipName,
});

export const createTooltipOpenedEvent = (
location: string,
tooltipName: string,
) => {
const createEventBuilder = MetricsEventBuilder.createEventBuilder;

return createEventBuilder(MetaMetricsEvents.TOOLTIP_OPENED)
.addProperties(getTooltipMetricProperties(location, tooltipName))
.build();
};
56 changes: 56 additions & 0 deletions app/components/UI/Stake/utils/metaMetrics/withMetaMetrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
IMetaMetricsEvent,
JsonMap,
} from '../../../../../core/Analytics/MetaMetrics.types';
import { MetricsEventBuilder } from '../../../../../core/Analytics/MetricsEventBuilder';
import { MetaMetrics } from '../../../../../core/Analytics';

interface WithMetaMetricsEvent {
event: IMetaMetricsEvent;
properties?: JsonMap;
}

const createEventBuilder = MetricsEventBuilder.createEventBuilder;

const shouldAddProperties = (properties?: JsonMap): properties is JsonMap => {
if (!properties) return false;
return Object.keys(properties).length > 0;
};

const buildEvent = (e: WithMetaMetricsEvent) => {
const eventBuilder = createEventBuilder(e.event);

if (shouldAddProperties(e?.properties)) {
eventBuilder.addProperties(e.properties);
}

return eventBuilder.build();
};

export const withMetaMetrics = <T extends (...args: unknown[]) => unknown>(
func: T,
events: WithMetaMetricsEvent | WithMetaMetricsEvent[],
) => {
if (!Array.isArray(events)) {
events = [events];
}

const builtEvents = events.map((event) => buildEvent(event));

return (...args: Parameters<T>): ReturnType<T> | Promise<ReturnType<T>> => {
const result = func(...args);

if (result instanceof Promise) {
return result.then((res) => {
builtEvents.forEach((event) =>
MetaMetrics.getInstance().trackEvent(event),
);
return res;
}) as Promise<ReturnType<T>>;
}

builtEvents.forEach((event) => MetaMetrics.getInstance().trackEvent(event));

return result as ReturnType<T>;
};
};
Loading

0 comments on commit 7b9bd02

Please sign in to comment.