Skip to content

Commit

Permalink
chore: [IOPAE-1187] Add services Mixpanel analytics events (#5804)
Browse files Browse the repository at this point in the history
## Short description
This PR adds Mixpanel events for services.

## List of changes proposed in this pull request
- added analitycs events
- removed old analitycs events
- added middleware

## How to test
Check that the events are registered on Mixpanel

---------

Co-authored-by: Giuseppe Di Pinto <[email protected]>
Co-authored-by: Giuseppe Di Pinto <[email protected]>
  • Loading branch information
3 people authored Jun 10, 2024
1 parent 47d1dbb commit 592673a
Show file tree
Hide file tree
Showing 15 changed files with 469 additions and 113 deletions.
15 changes: 13 additions & 2 deletions ts/features/bonus/cgn/components/CgnServiceCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { fold, isLoading } from "../../../../common/model/RemoteValue";
import { cgnUnsubscribeSelector } from "../store/reducers/unsubscribe";
import { loadServicePreference } from "../../../services/details/store/actions/preference";
import { loadAvailableBonuses } from "../../common/store/actions/availableBonusesTypes";
import * as analytics from "../../../services/common/analytics";

type CgnServiceCtaProps = {
serviceId: ServiceId;
Expand Down Expand Up @@ -69,11 +70,17 @@ export const CgnServiceCta = ({ serviceId }: CgnServiceCtaProps) => {
},
{
text: I18n.t("global.buttons.deactivate"),
onPress: () => dispatch(cgnUnsubscribe.request())
onPress: () => {
analytics.trackSpecialServiceStatusChanged({
is_active: false,
service_id: serviceId
});
dispatch(cgnUnsubscribe.request());
}
}
]
),
[dispatch]
[dispatch, serviceId]
);

if (!servicePreferenceResponseSuccess) {
Expand Down Expand Up @@ -102,6 +109,10 @@ export const CgnServiceCta = ({ serviceId }: CgnServiceCtaProps) => {
loading={isLoadingStatus}
testID="service-activate-bonus-button"
onPress={() => {
analytics.trackSpecialServiceStatusChanged({
is_active: true,
service_id: serviceId
});
dispatch(loadAvailableBonuses.request());
dispatch(cgnActivationStart());
}}
Expand Down
15 changes: 10 additions & 5 deletions ts/features/pn/components/ServiceCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ import { useOnFirstRender } from "../../../utils/hooks/useOnFirstRender";
import { loadServicePreference } from "../../services/details/store/actions/preference";
import {
trackPNServiceActivated,
trackPNServiceDeactivated,
trackPNServiceStartActivation,
trackPNServiceStartDeactivation
trackPNServiceDeactivated
} from "../analytics";
import * as analytics from "../../services/common/analytics";

type PnServiceCtaProps = {
serviceId: ServiceId;
Expand Down Expand Up @@ -99,7 +98,10 @@ export const PnServiceCta = ({ serviceId, activate }: PnServiceCtaProps) => {
label={I18n.t("features.pn.service.activate")}
loading={isLoading}
onPress={() => {
trackPNServiceStartActivation();
analytics.trackSpecialServiceStatusChanged({
is_active: true,
service_id: serviceId
});
dispatch(
pnActivationUpsert.request({
value: true,
Expand All @@ -120,7 +122,10 @@ export const PnServiceCta = ({ serviceId, activate }: PnServiceCtaProps) => {
label={I18n.t("features.pn.service.deactivate")}
loading={isLoading}
onPress={() => {
trackPNServiceStartDeactivation();
analytics.trackSpecialServiceStatusChanged({
is_active: false,
service_id: serviceId
});
dispatch(
pnActivationUpsert.request({
value: false,
Expand Down
276 changes: 276 additions & 0 deletions ts/features/services/common/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
import { getType } from "typesafe-actions";
import { mixpanel, mixpanelTrack } from "../../../../mixpanel";
import { Action } from "../../../../store/actions/types";
import { buildEventProperties } from "../../../../utils/analytics";
import { searchPaginatedInstitutionsGet } from "../../search/store/actions";
import { getNetworkErrorMessage } from "../../../../utils/errors";
import { paginatedServicesGet } from "../../institution/store/actions";
import {
featuredInstitutionsGet,
featuredServicesGet,
paginatedInstitutionsGet
} from "../../home/store/actions";
import { loadServicePreference } from "../../details/store/actions/preference";
import { CTAS } from "../../../messages/types/MessageCTA";

type ServiceBaseType = {
service_name: string;
} & InstitutionBaseType;

type InstitutionBaseType = {
organization_name: string;
};

type ServiceDetailsType = {
bottom_cta_available: boolean;
organization_fiscal_code: string;
service_category: "special" | "standard";
service_id: string;
} & ServiceBaseType;

type ServiceDetailsConsentType = {
is_special_service: boolean;
main_consent_status: boolean;
push_consent_status: boolean;
read_confirmation_consent_status: boolean;
service_id: string;
};

const ConsentTypeLabels = {
inbox: "main",
email: "email",
push: "push",
can_access_message_read_status: "read_confirmation"
} as const;

type ServiceConsentChangedType = {
consent_type: keyof typeof ConsentTypeLabels;
consent_status: boolean;
service_id: string;
};

type ServiceDetailsUserExitType = {
link: string;
service_id: string;
};

type SpecialServiceStatusChangedType = {
is_active: boolean;
service_id: string;
};

type InstitutionDetailsType = {
organization_fiscal_code: string;
services_count: number;
} & InstitutionBaseType;

type ServiceSelectedType = {
source: "featured_services" | "organization_detail";
} & ServiceBaseType;

type InstitutionSelectedType = {
source:
| "featured_organizations"
| "main_list"
| "search_list"
| "recent_list";
} & InstitutionBaseType;

type SearchStartType = {
source: "bottom_link" | "header_icon" | "search_bar";
};

type ServiceDetailsCtaTappedType = {
cta: keyof CTAS;
service_id: string;
};

export const trackServicesHome = () =>
void mixpanelTrack("SERVICES", buildEventProperties("UX", "screen_view"));

export const trackServicesHomeError = (
reason: string,
source: "featured_services" | "featured_organizations" | "main_list"
) =>
void mixpanelTrack(
"SERVICES_ERROR",
buildEventProperties("KO", undefined, { reason, source })
);

export const trackInstitutionsScroll = () =>
void mixpanelTrack("SERVICES_SCROLL", buildEventProperties("UX", "action"));

export const trackSearchStart = (props: SearchStartType) =>
void mixpanelTrack(
"SERVICES_SEARCH_START",
buildEventProperties("UX", "action", props)
);

export const trackServiceSelected = ({
organization_name,
service_name,
source
}: ServiceSelectedType) =>
void mixpanelTrack(
"SERVICES_SELECTED",
buildEventProperties("UX", "action", {
service_name,
organization_name,
source
})
);

export const trackInstitutionSelected = ({
organization_name,
source
}: InstitutionSelectedType) =>
void mixpanelTrack(
"SERVICES_ORGANIZATION_SELECTED",
buildEventProperties("UX", "action", {
organization_name,
source
})
);

export const trackInstitutionDetails = ({
organization_fiscal_code,
organization_name,
services_count = 0
}: InstitutionDetailsType) =>
void mixpanelTrack(
"SERVICES_ORGANIZATION_DETAIL",
buildEventProperties("UX", "screen_view", {
organization_fiscal_code,
organization_name,
services_count
})
);

export const trackInstitutionDetailsError = (reason: string) =>
void mixpanelTrack(
"SERVICES_ORGANIZATION_DETAIL_ERROR",
buildEventProperties("KO", undefined, { reason })
);

export const trackSearchPage = () =>
void mixpanelTrack(
"SERVICES_SEARCH_PAGE",
buildEventProperties("UX", "screen_view")
);

export const trackSearchInput = () =>
void mixpanelTrack(
"SERVICES_SEARCH_INPUT",
buildEventProperties("UX", "action")
);

export const trackSearchResult = (results_count: number = 0) =>
void mixpanelTrack(
"SERVICES_SEARCH_RESULT_PAGE",
buildEventProperties("UX", "screen_view", { results_count })
);

export const trackSearchResultScroll = () =>
void mixpanelTrack(
"SERVICES_SEARCH_RESULT_SCROLL",
buildEventProperties("UX", "action")
);

export const trackSearchError = (reason: string) =>
void mixpanelTrack(
"SERVICES_SEARCH_ERROR",
buildEventProperties("KO", undefined, { reason })
);

export const trackServiceDetails = (props: ServiceDetailsType) =>
void mixpanelTrack(
"SERVICES_DETAIL",
buildEventProperties("UX", "screen_view", props)
);

export const trackServiceDetailsConsent = (props: ServiceDetailsConsentType) =>
void mixpanelTrack(
"SERVICES_DETAIL_CONSENT",
buildEventProperties("UX", "screen_view", props)
);

export const trackServiceConsentChanged = ({
consent_type,
...rest
}: ServiceConsentChangedType) =>
void mixpanelTrack(
"SERVICES_CONSENT_CHANGED",
buildEventProperties("UX", "action", {
...rest,
consent_type: ConsentTypeLabels[consent_type]
})
);

export const trackServiceDetailsUserExit = (
props: ServiceDetailsUserExitType
) =>
void mixpanelTrack(
"SERVICES_DETAIL_USER_EXIT",
buildEventProperties("UX", "exit", props)
);

export const trackSpecialServiceStatusChanged = (
props: SpecialServiceStatusChangedType
) =>
void mixpanelTrack(
"SERVICES_SPECIAL_SERVICE_STATUS_CHANGED",
buildEventProperties("UX", "action", props)
);

export const trackServiceDetailsError = (reason: string) =>
void mixpanelTrack(
"SERVICES_DETAIL_ERROR",
buildEventProperties("KO", undefined, { reason })
);

export const trackServiceDetailsCtaTapped = (
props: ServiceDetailsCtaTappedType
) =>
void mixpanelTrack(
"SERVICES_DETAIL_CTA_TAPPED",
buildEventProperties("UX", "action", props)
);

/**
* Isolated tracker for services actions
*/
export const trackServicesAction =
(_: NonNullable<typeof mixpanel>) =>
(action: Action): void => {
switch (action.type) {
// Services home
case getType(paginatedInstitutionsGet.failure):
return trackServicesHomeError(
getNetworkErrorMessage(action.payload),
"main_list"
);
case getType(featuredServicesGet.failure):
return trackServicesHomeError(
getNetworkErrorMessage(action.payload),
"featured_services"
);
case getType(featuredInstitutionsGet.failure):
return trackServicesHomeError(
getNetworkErrorMessage(action.payload),
"featured_organizations"
);
// Search results
case getType(searchPaginatedInstitutionsGet.success):
return trackSearchResult(action.payload.count);
case getType(searchPaginatedInstitutionsGet.failure):
return trackSearchError(getNetworkErrorMessage(action.payload));
// Institution details
case getType(paginatedServicesGet.failure):
return trackInstitutionDetailsError(
getNetworkErrorMessage(action.payload)
);
// Service details
case getType(loadServicePreference.failure):
return trackServiceDetailsError(getNetworkErrorMessage(action.payload));
}
};
Loading

0 comments on commit 592673a

Please sign in to comment.