diff --git a/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.test.tsx b/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.test.tsx
index 4486b69949..612fdfba91 100644
--- a/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.test.tsx
+++ b/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.test.tsx
@@ -5,6 +5,7 @@ import { renderWithProviders } from 'shared/utils/renderWithProviders';
import { mockedApplet, mockedCurrentWorkspace } from 'shared/mock';
import { Roles } from 'shared/consts';
import { initialStateData } from 'shared/state';
+import { Mixpanel, MixpanelEventType, MixpanelProps } from 'shared/utils';
import { HeaderOptions } from './HeaderOptions';
@@ -47,8 +48,11 @@ vi.mock('react-router-dom', async () => {
};
});
+const spyMixpanelTrack = vi.spyOn(Mixpanel, 'track');
+
describe('HeaderOptions', () => {
beforeEach(() => {
+ spyMixpanelTrack.mockReset();
renderWithProviders(, { preloadedState: getPreloadedState() });
});
@@ -70,6 +74,16 @@ describe('HeaderOptions', () => {
expect(screen.queryByTestId('header-option-audit-logs-button')).toBeInTheDocument();
});
+ test('should track ExportAuditLogsClick when audit logs option is clicked', () => {
+ fireEvent.click(screen.getByTestId('header-option-export-button'));
+ fireEvent.click(screen.getByTestId('header-option-audit-logs-button'));
+
+ expect(spyMixpanelTrack).toHaveBeenCalledWith({
+ action: MixpanelEventType.ExportAuditLogsClick,
+ [MixpanelProps.AppletId]: testAppletId,
+ });
+ });
+
test('should contain link to settings page', () => {
expect(screen.getByTestId('header-option-settings-link')).toHaveAttribute(
'href',
diff --git a/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.tsx b/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.tsx
index bd3eeb1e98..001da65e13 100644
--- a/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.tsx
+++ b/src/modules/Dashboard/components/HeaderOptions/HeaderOptions.tsx
@@ -12,6 +12,7 @@ import {
checkIfCanAccessData,
checkIfCanEdit,
MixpanelEventType,
+ MixpanelProps,
checkIfFullAccess,
} from 'shared/utils';
import { workspaces } from 'shared/state';
@@ -42,7 +43,10 @@ export const HeaderOptions = () => {
const handleOpenAuditLogs = () => {
setIsAuditLogsExportOpen(true);
- Mixpanel.track({ action: MixpanelEventType.ExportAuditLogsClick });
+ Mixpanel.track({
+ action: MixpanelEventType.ExportAuditLogsClick,
+ [MixpanelProps.AppletId]: appletId,
+ });
};
const handleOpenResponseData = () => {
diff --git a/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.test.tsx b/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.test.tsx
index cf29313d18..e9c759d201 100644
--- a/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.test.tsx
+++ b/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.test.tsx
@@ -4,6 +4,7 @@ import { vi } from 'vitest';
import { initialStateData } from 'redux/modules';
import { mockedApplet } from 'shared/mock';
import { renderWithProviders } from 'shared/utils/renderWithProviders';
+import { Mixpanel, MixpanelEventType, MixpanelProps } from 'shared/utils';
import { AuditLogsExportSetting } from './AuditLogsExportSetting';
@@ -29,6 +30,8 @@ vi.mock('shared/utils/exportTemplate', () => ({
exportTemplate: vi.fn().mockResolvedValue(true),
}));
+const spyMixpanelTrack = vi.spyOn(Mixpanel, 'track');
+
const dataTestId = 'audit-logs-export';
describe('AuditLogsExportSetting', () => {
@@ -36,6 +39,7 @@ describe('AuditLogsExportSetting', () => {
vi.useFakeTimers({ shouldAdvanceTime: true });
vi.setSystemTime(mockedNow);
mockedExportAuditLogsApi.mockClear();
+ spyMixpanelTrack.mockReset();
});
afterEach(() => {
@@ -169,4 +173,75 @@ describe('AuditLogsExportSetting', () => {
expect(mockedExportAuditLogsApi).toHaveBeenCalledTimes(2);
});
});
+
+ it('should track ExportAuditLogsDownload when the download button is clicked', async () => {
+ mockedExportAuditLogsApi.mockResolvedValueOnce({
+ data: { result: [], count: 0 },
+ });
+
+ renderWithProviders(
+ ,
+ { preloadedState },
+ );
+
+ fireEvent.click(screen.getByTestId(`${dataTestId}-settings-download-button`));
+
+ expect(spyMixpanelTrack).toHaveBeenCalledWith({
+ action: MixpanelEventType.ExportAuditLogsDownload,
+ [MixpanelProps.AppletId]: mockedApplet.id,
+ });
+ });
+
+ it('should track ExportAuditLogsSuccessful when the export completes', async () => {
+ mockedExportAuditLogsApi.mockResolvedValueOnce({
+ data: { result: [], count: 0 },
+ });
+
+ renderWithProviders(
+ ,
+ { preloadedState },
+ );
+
+ fireEvent.click(screen.getByTestId(`${dataTestId}-settings-download-button`));
+
+ await waitFor(() => {
+ expect(spyMixpanelTrack).toHaveBeenCalledWith({
+ action: MixpanelEventType.ExportAuditLogsSuccessful,
+ [MixpanelProps.AppletId]: mockedApplet.id,
+ });
+ });
+ });
+
+ it('should track ExportAuditLogsFailed when the export fails', async () => {
+ mockedExportAuditLogsApi.mockRejectedValueOnce(new Error('Network error'));
+
+ renderWithProviders(
+ ,
+ { preloadedState },
+ );
+
+ fireEvent.click(screen.getByTestId(`${dataTestId}-settings-download-button`));
+
+ await waitFor(() => {
+ expect(spyMixpanelTrack).toHaveBeenCalledWith({
+ action: MixpanelEventType.ExportAuditLogsFailed,
+ [MixpanelProps.AppletId]: mockedApplet.id,
+ });
+ });
+ });
});
diff --git a/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.tsx b/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.tsx
index 6307140720..ee492ecfa5 100644
--- a/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.tsx
+++ b/src/shared/features/AppletSettings/AuditLogsExportSetting/AuditLogsExportSetting.tsx
@@ -7,6 +7,7 @@ import { ObjectSchema } from 'yup';
import { getNormalizedTimezoneDate } from 'shared/utils/dateTimezone';
import { DateRangePickerType } from 'shared/components/DateRangePicker';
import { applet } from 'shared/state/Applet';
+import { Mixpanel, MixpanelEventType, MixpanelProps } from 'shared/utils';
import {
AuditLogsExportFormValues,
@@ -66,6 +67,10 @@ export const AuditLogsExportSetting = ({
onExportSettingsClose();
}}
onExport={() => {
+ Mixpanel.track({
+ action: MixpanelEventType.ExportAuditLogsDownload,
+ [MixpanelProps.AppletId]: appletId,
+ });
setDataIsExporting(true);
onExportSettingsClose();
}}
diff --git a/src/shared/features/AppletSettings/AuditLogsExportSetting/Popups/AuditLogsExportPopup/useAuditLogsExport.tsx b/src/shared/features/AppletSettings/AuditLogsExportSetting/Popups/AuditLogsExportPopup/useAuditLogsExport.tsx
index d13cfff438..26fcadb91c 100644
--- a/src/shared/features/AppletSettings/AuditLogsExportSetting/Popups/AuditLogsExportPopup/useAuditLogsExport.tsx
+++ b/src/shared/features/AppletSettings/AuditLogsExportSetting/Popups/AuditLogsExportPopup/useAuditLogsExport.tsx
@@ -6,6 +6,7 @@ import { getExportAuditLogsApi } from 'api';
import { getExportPageAmount } from 'modules/Dashboard/api/api.utils';
import { DateRangePickerType } from 'shared/components/DateRangePicker';
import { DateFormats } from 'shared/consts';
+import { Mixpanel, MixpanelEventType, MixpanelProps } from 'shared/utils';
import { getLast24hUTCRange } from 'shared/utils';
import { AuditLogsExportFormValues } from '../../AuditLogsExportSetting.types';
@@ -71,8 +72,16 @@ export const useAuditLogsExport = (
setCurrentPage(page);
}
+ Mixpanel.track({
+ action: MixpanelEventType.ExportAuditLogsSuccessful,
+ [MixpanelProps.AppletId]: appletId,
+ });
handlePopupCloseRef.current();
} catch (e) {
+ Mixpanel.track({
+ action: MixpanelEventType.ExportAuditLogsFailed,
+ [MixpanelProps.AppletId]: appletId,
+ });
setError(e as Error);
} finally {
isExportingRef.current = false;
diff --git a/src/shared/utils/mixpanel/mixpanel.types.ts b/src/shared/utils/mixpanel/mixpanel.types.ts
index 66ea170897..d8051e5b0a 100644
--- a/src/shared/utils/mixpanel/mixpanel.types.ts
+++ b/src/shared/utils/mixpanel/mixpanel.types.ts
@@ -65,6 +65,9 @@ export enum MixpanelEventType {
AppletCreatedSuccessfully = 'Applet Created Successfully',
ExportDataClick = 'Export Data click',
ExportAuditLogsClick = 'Export Audit Logs click',
+ ExportAuditLogsDownload = 'Export Audit Logs download',
+ ExportAuditLogsSuccessful = 'Export Audit Logs Successful',
+ ExportAuditLogsFailed = 'Export Audit Logs Failed',
TakeNowDialogClosed = 'Take Now dialogue closed',
MultiInformantStartActivityClick = 'Multi-informant Start Activity click',
ProvidingResponsesDropdownOpened = '"Who will be providing responses" dropdown opened',
@@ -249,6 +252,18 @@ export type ExportAuditLogsClickEvent = WithAppletId<{
action: MixpanelEventType.ExportAuditLogsClick;
}>;
+export type ExportAuditLogsDownloadEvent = WithAppletId<{
+ action: MixpanelEventType.ExportAuditLogsDownload;
+}>;
+
+export type ExportAuditLogsSuccessfulEvent = WithAppletId<{
+ action: MixpanelEventType.ExportAuditLogsSuccessful;
+}>;
+
+export type ExportAuditLogsFailedEvent = WithAppletId<{
+ action: MixpanelEventType.ExportAuditLogsFailed;
+}>;
+
type TakeNowEvent = WithFeature<
WithAppletId<{
[MixpanelProps.MultiInformantAssessmentId]?: string | null;
@@ -571,6 +586,9 @@ export type MixpanelEvent =
| AppletCreatedSuccessfullyEvent
| ExportDataClickEvent
| ExportAuditLogsClickEvent
+ | ExportAuditLogsDownloadEvent
+ | ExportAuditLogsSuccessfulEvent
+ | ExportAuditLogsFailedEvent
| TakeNowDialogClosedEvent
| MultiInformantStartActivityClickEvent
| ProvidingResponsesDropdownOpenedEvent