From 7a57d09aefc5c160631315ad35b9265a8f1d83c7 Mon Sep 17 00:00:00 2001 From: martinaCampoli Date: Thu, 19 Dec 2024 12:19:13 +0100 Subject: [PATCH 1/3] Added new mixPanel events --- src/api/eservice/eservice.downloads.ts | 1 + src/api/hooks/useDownloadFile.ts | 16 ++++- src/config/tracking.ts | 60 +++++++++++++++++-- .../ConsumerEServiceCatalog.page.tsx | 22 ++++++- .../EServiceCreateStepDocuments.tsx | 2 + .../EServiceCreateStepGeneral.tsx | 6 ++ .../ProviderEServiceGeneralInfoSection.tsx | 5 ++ .../ProviderEServiceImportVersionDrawer.tsx | 13 ++++ 8 files changed, 117 insertions(+), 8 deletions(-) diff --git a/src/api/eservice/eservice.downloads.ts b/src/api/eservice/eservice.downloads.ts index af51adb27..a1913cfbc 100644 --- a/src/api/eservice/eservice.downloads.ts +++ b/src/api/eservice/eservice.downloads.ts @@ -30,6 +30,7 @@ function useExportVersion() { return useDownloadFile(EServiceServices.exportVersion, { errorToastLabel: t('outcome.error'), loadingLabel: t('loading'), + kindFile: 'ESERVICE', }) } diff --git a/src/api/hooks/useDownloadFile.ts b/src/api/hooks/useDownloadFile.ts index 2359a7a9f..e4c9d6b78 100644 --- a/src/api/hooks/useDownloadFile.ts +++ b/src/api/hooks/useDownloadFile.ts @@ -1,4 +1,6 @@ +import { trackEvent } from '@/config/tracking' import { useLoadingOverlay, useToastNotification } from '@/stores' +import { AxiosError } from 'axios' export function downloadFile(responseData: File | string, filename = 'download') { const blob = new Blob([responseData], { type: 'application/octet-stream' }) @@ -20,7 +22,12 @@ export function downloadFile(responseData: File | string, filename = 'download') export function useDownloadFile( service: (args: T) => Promise, - config: { errorToastLabel?: string; successToastLabel?: string; loadingLabel: string } + config: { + errorToastLabel?: string + successToastLabel?: string + loadingLabel: string + kindFile?: 'ESERVICE' + } ) { const { showOverlay, hideOverlay } = useLoadingOverlay() const { showToast } = useToastNotification() @@ -40,9 +47,14 @@ export function useDownloadFile( } else { downloadFile(data, filename) } - + if (config.kindFile) { + trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_SUCCESS', {}) + } config.successToastLabel && showToast(config.successToastLabel, 'success') } catch (error) { + if (config.kindFile && error instanceof AxiosError && error.response) { + trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_ERROR', { errorCode: error.response.status }) + } console.error(error) config.errorToastLabel && showToast(config.errorToastLabel, 'error') } finally { diff --git a/src/config/tracking.ts b/src/config/tracking.ts index 4a38f29e4..815e1c1a8 100644 --- a/src/config/tracking.ts +++ b/src/config/tracking.ts @@ -11,16 +11,66 @@ import { STORAGE_KEY_SESSION_TOKEN } from './constants' import { parseJwt } from '@/api/auth/auth.utils' // This should be an union of all the possible mixpanel events -type MixPanelEvent = { - eventName: 'INTEROP_CATALOG_READ' - properties: MixPanelCatalogReadEventProps -} +type MixPanelEvent = + | { + eventName: 'INTEROP_CATALOG_READ' + properties: MixPanelCatalogReadAndDownloadEventProps + } + | { + eventName: 'INTEROP_CATALOG_SEARCH_KEYWORD' + properties: MixPanelSearchKeywordEventProps + } + | { + eventName: 'INTEROP_EXT_LINK_DTD_ESERVICE_GUIDE' + properties: MixPanelLinkEserviceGuideAndApiCheckerEventProps + } + | { + eventName: 'INTEROP_EXT_LINK_DTD_API_CHECKER' + properties: MixPanelLinkEserviceGuideAndApiCheckerEventProps + } + | { + eventName: 'INTEROP_ESERVICE_DOWNLOAD_REQUEST' + properties: MixPanelCatalogReadAndDownloadEventProps + } + | { + eventName: 'INTEROP_ESERVICE_DOWNLOAD_RESPONSE_SUCCESS' + properties: {} + } + | { + eventName: 'INTEROP_ESERVICE_DOWNLOAD_RESPONSE_ERROR' + properties: MixPanelResponseErrorEvent + } + | { + eventName: 'INTEROP_ESERVICE_UPLOAD_REQUEST' + properties: {} + } + | { + eventName: 'INTEROP_ESERVICE_UPLOAD_RESPONSE_SUCCESS' + properties: {} + } + | { + eventName: 'INTEROP_ESERVICE_UPLOAD_RESPONSE_ERROR' + properties: MixPanelResponseErrorEvent + } -type MixPanelCatalogReadEventProps = { +type MixPanelCatalogReadAndDownloadEventProps = { eserviceId: string descriptorId: string } +type MixPanelSearchKeywordEventProps = { + q?: string + producersId?: string[] +} + +type MixPanelLinkEserviceGuideAndApiCheckerEventProps = { + src: 'CREATE_ESERVICE' +} + +type MixPanelResponseErrorEvent = { + errorCode: number +} + const isTrackingEnabled = NODE_ENV === 'production' && STAGE === 'PROD' const getTrackingDefaultProps = () => { diff --git a/src/pages/ConsumerEServiceCatalogPage/ConsumerEServiceCatalog.page.tsx b/src/pages/ConsumerEServiceCatalogPage/ConsumerEServiceCatalog.page.tsx index fe56055f5..a28c3f641 100644 --- a/src/pages/ConsumerEServiceCatalogPage/ConsumerEServiceCatalog.page.tsx +++ b/src/pages/ConsumerEServiceCatalogPage/ConsumerEServiceCatalog.page.tsx @@ -12,6 +12,8 @@ import { } from '@pagopa/interop-fe-commons' import type { EServiceDescriptorState, GetEServicesCatalogParams } from '@/api/api.generatedTypes' import { keepPreviousData, useQuery } from '@tanstack/react-query' +import { trackEvent } from '@/config/tracking' +import { debounce } from 'lodash' const ConsumerEServiceCatalogPage: React.FC = () => { const { t } = useTranslation('pages', { keyPrefix: 'consumerEServiceCatalog' }) @@ -33,7 +35,11 @@ const ConsumerEServiceCatalogPage: React.FC = () => { const { filtersParams, ...filtersHandlers } = useFilters< Omit >([ - { name: 'q', label: tEservice('nameField.label'), type: 'freetext' }, + { + name: 'q', + label: tEservice('nameField.label'), + type: 'freetext', + }, { name: 'producersIds', label: tEservice('providerField.label'), @@ -52,6 +58,20 @@ const ConsumerEServiceCatalogPage: React.FC = () => { placeholderData: keepPreviousData, }) + React.useEffect(() => { + const debouncedTrackEvent = debounce(() => { + if (filtersParams.q || filtersParams.producersIds) { + trackEvent('INTEROP_CATALOG_SEARCH_KEYWORD', { + q: filtersParams.q, + producersId: filtersParams.producersIds, + }) + } + }, 4000) + + debouncedTrackEvent() + return () => debouncedTrackEvent.cancel() + }, [filtersParams.q, filtersParams.producersIds]) + return ( diff --git a/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepDocuments/EServiceCreateStepDocuments.tsx b/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepDocuments/EServiceCreateStepDocuments.tsx index 2a76e0b0b..1f2f6e239 100644 --- a/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepDocuments/EServiceCreateStepDocuments.tsx +++ b/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepDocuments/EServiceCreateStepDocuments.tsx @@ -12,6 +12,7 @@ import ArrowForwardIcon from '@mui/icons-material/ArrowForward' import { IconLink } from '@/components/shared/IconLink' import LaunchIcon from '@mui/icons-material/Launch' import { openApiCheckerLink } from '@/config/constants' +import { trackEvent } from '@/config/tracking' export const EServiceCreateStepDocuments: React.FC = () => { const { t } = useTranslation('eservice') @@ -29,6 +30,7 @@ export const EServiceCreateStepDocuments: React.FC = () => { href={openApiCheckerLink} target="_blank" endIcon={} + onClick={() => trackEvent('INTEROP_EXT_LINK_DTD_API_CHECKER', { src: 'CREATE_ESERVICE' })} > {t('create.step4.interface.description.restLinkLabel')} diff --git a/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepGeneral/EServiceCreateStepGeneral.tsx b/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepGeneral/EServiceCreateStepGeneral.tsx index 676088bbd..8248d07cd 100644 --- a/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepGeneral/EServiceCreateStepGeneral.tsx +++ b/src/pages/ProviderEServiceCreatePage/components/EServiceCreateStepGeneral/EServiceCreateStepGeneral.tsx @@ -17,6 +17,7 @@ import LaunchIcon from '@mui/icons-material/Launch' import { eserviceNamingBestPracticeLink } from '@/config/constants' import { STAGE } from '@/config/env' import { PagoPAEnvVars } from '@/types/common.types' +import { trackEvent } from '@/config/tracking' export type EServiceCreateStepGeneralFormValues = { name: string @@ -94,6 +95,11 @@ export const EServiceCreateStepGeneral: React.FC = () => { href={eserviceNamingBestPracticeLink} target="_blank" endIcon={} + onClick={() => + trackEvent('INTEROP_EXT_LINK_DTD_ESERVICE_GUIDE', { + src: 'CREATE_ESERVICE', + }) + } > {t('create.step1.detailsDescription.linkLabel')} {' '} diff --git a/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx b/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx index 7c2324622..25b293937 100644 --- a/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx +++ b/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx @@ -14,6 +14,7 @@ import { ProviderEServiceUpdateDescriptionDrawer } from './ProviderEServiceUpdat import { useSuspenseQuery } from '@tanstack/react-query' import { useGetDelegationUserRole } from '@/hooks/useGetDelegationUserRole' import { AuthHooks } from '@/api/auth' +import { trackEvent } from '@/config/tracking' export const ProviderEServiceGeneralInfoSection: React.FC = () => { const { t } = useTranslation('eservice', { @@ -58,6 +59,10 @@ export const ProviderEServiceGeneralInfoSection: React.FC = () => { } const handleExportVersion = () => { + trackEvent('INTEROP_ESERVICE_DOWNLOAD_REQUEST', { + eserviceId: eserviceId, + descriptorId: descriptorId, + }) exportVersion({ eserviceId, descriptorId }) } diff --git a/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx b/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx index 253b02d6c..b86d2dad2 100644 --- a/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx +++ b/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx @@ -2,9 +2,11 @@ import { EServiceMutations } from '@/api/eservice' import { Drawer } from '@/components/shared/Drawer' import { RHFSingleFileInput } from '@/components/shared/react-hook-form-inputs' import { importExportEServiceGuideLink } from '@/config/constants' +import { trackEvent } from '@/config/tracking' import { useNavigate } from '@/router' import { Box, FormControlLabel, Link, Stack, Switch, Typography } from '@mui/material' import { InformationContainer } from '@pagopa/interop-fe-commons' +import { AxiosError } from 'axios' import React from 'react' import { FormProvider, useForm } from 'react-hook-form' import { Trans, useTranslation } from 'react-i18next' @@ -44,12 +46,14 @@ export const ProviderEServiceImportVersionDrawer: React.FC< const { mutate: importVersion } = EServiceMutations.useImportVersion() const onSubmit = async (values: EServiceImportVersionDocFormValues) => { + trackEvent('INTEROP_ESERVICE_UPLOAD_REQUEST', {}) if (!values.eserviceFile || !isConfirmedImport) return importVersion( { eserviceFile: values.eserviceFile }, { onSuccess: (res) => { + trackEvent('INTEROP_ESERVICE_UPLOAD_RESPONSE_SUCCESS', {}) onClose() navigate('PROVIDE_ESERVICE_SUMMARY', { params: { @@ -58,6 +62,15 @@ export const ProviderEServiceImportVersionDrawer: React.FC< }, }) }, + onError: (error) => { + if (error instanceof AxiosError) { + if (error.response) { + trackEvent('INTEROP_ESERVICE_UPLOAD_RESPONSE_ERROR', { + errorCode: error.response.status, + }) + } + } + }, } ) } From def94e688eefa340ea4cacad4c9ea08c746fa6f8 Mon Sep 17 00:00:00 2001 From: Carmine Porricelli Date: Fri, 20 Dec 2024 16:54:56 +0100 Subject: [PATCH 2/3] Updated track events success/fail logic --- src/api/eservice/eservice.downloads.ts | 1 - src/api/hooks/useDownloadFile.ts | 28 +++++++++---------- .../ProviderEServiceGeneralInfoSection.tsx | 14 +++++++++- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/api/eservice/eservice.downloads.ts b/src/api/eservice/eservice.downloads.ts index a1913cfbc..af51adb27 100644 --- a/src/api/eservice/eservice.downloads.ts +++ b/src/api/eservice/eservice.downloads.ts @@ -30,7 +30,6 @@ function useExportVersion() { return useDownloadFile(EServiceServices.exportVersion, { errorToastLabel: t('outcome.error'), loadingLabel: t('loading'), - kindFile: 'ESERVICE', }) } diff --git a/src/api/hooks/useDownloadFile.ts b/src/api/hooks/useDownloadFile.ts index e4c9d6b78..cf5acf448 100644 --- a/src/api/hooks/useDownloadFile.ts +++ b/src/api/hooks/useDownloadFile.ts @@ -1,6 +1,4 @@ -import { trackEvent } from '@/config/tracking' import { useLoadingOverlay, useToastNotification } from '@/stores' -import { AxiosError } from 'axios' export function downloadFile(responseData: File | string, filename = 'download') { const blob = new Blob([responseData], { type: 'application/octet-stream' }) @@ -22,18 +20,24 @@ export function downloadFile(responseData: File | string, filename = 'download') export function useDownloadFile( service: (args: T) => Promise, - config: { + labels: { errorToastLabel?: string successToastLabel?: string loadingLabel: string - kindFile?: 'ESERVICE' } ) { const { showOverlay, hideOverlay } = useLoadingOverlay() const { showToast } = useToastNotification() - return async (args: T, filename?: string) => { - showOverlay(config.loadingLabel) + return async ( + args: T, + filename?: string, + config?: { + onSuccess?: () => void + onError?: (error: unknown) => void + } + ) => { + showOverlay(labels.loadingLabel) try { const data = await service(args) @@ -47,16 +51,12 @@ export function useDownloadFile( } else { downloadFile(data, filename) } - if (config.kindFile) { - trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_SUCCESS', {}) - } - config.successToastLabel && showToast(config.successToastLabel, 'success') + labels.successToastLabel && showToast(labels.successToastLabel, 'success') + config?.onSuccess?.() } catch (error) { - if (config.kindFile && error instanceof AxiosError && error.response) { - trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_ERROR', { errorCode: error.response.status }) - } console.error(error) - config.errorToastLabel && showToast(config.errorToastLabel, 'error') + labels.errorToastLabel && showToast(labels.errorToastLabel, 'error') + config?.onError?.(error) } finally { hideOverlay() } diff --git a/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx b/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx index 25b293937..66c581e7e 100644 --- a/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx +++ b/src/pages/ProviderEServiceDetailsPage/components/ProviderEServiceDetailsTab/ProviderEServiceGeneralInfoSection/ProviderEServiceGeneralInfoSection.tsx @@ -15,6 +15,7 @@ import { useSuspenseQuery } from '@tanstack/react-query' import { useGetDelegationUserRole } from '@/hooks/useGetDelegationUserRole' import { AuthHooks } from '@/api/auth' import { trackEvent } from '@/config/tracking' +import { isAxiosError } from 'axios' export const ProviderEServiceGeneralInfoSection: React.FC = () => { const { t } = useTranslation('eservice', { @@ -63,7 +64,18 @@ export const ProviderEServiceGeneralInfoSection: React.FC = () => { eserviceId: eserviceId, descriptorId: descriptorId, }) - exportVersion({ eserviceId, descriptorId }) + exportVersion({ eserviceId, descriptorId }, undefined, { + onSuccess: () => { + trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_SUCCESS', {}) + }, + onError: (error) => { + if (isAxiosError(error) && error.response) { + trackEvent('INTEROP_ESERVICE_DOWNLOAD_RESPONSE_ERROR', { + errorCode: error.response.status, + }) + } + }, + }) } const hasSingleVersion = From 3bd2b17be0866ed8943e9913cba963600cdf13bb Mon Sep 17 00:00:00 2001 From: Carmine Porricelli Date: Fri, 20 Dec 2024 17:12:03 +0100 Subject: [PATCH 3/3] Update ProviderEServiceImportVersionDrawer.tsx --- .../ProviderEServiceImportVersionDrawer.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx b/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx index b86d2dad2..8751e02e2 100644 --- a/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx +++ b/src/pages/ProviderEServiceListPage/components/ProviderEServiceImportVersionDrawer.tsx @@ -6,7 +6,7 @@ import { trackEvent } from '@/config/tracking' import { useNavigate } from '@/router' import { Box, FormControlLabel, Link, Stack, Switch, Typography } from '@mui/material' import { InformationContainer } from '@pagopa/interop-fe-commons' -import { AxiosError } from 'axios' +import { isAxiosError } from 'axios' import React from 'react' import { FormProvider, useForm } from 'react-hook-form' import { Trans, useTranslation } from 'react-i18next' @@ -63,12 +63,10 @@ export const ProviderEServiceImportVersionDrawer: React.FC< }) }, onError: (error) => { - if (error instanceof AxiosError) { - if (error.response) { - trackEvent('INTEROP_ESERVICE_UPLOAD_RESPONSE_ERROR', { - errorCode: error.response.status, - }) - } + if (isAxiosError(error) && error.response) { + trackEvent('INTEROP_ESERVICE_UPLOAD_RESPONSE_ERROR', { + errorCode: error.response.status, + }) } }, }