Skip to content

Commit

Permalink
feat: Standardize download analytics events, add location value
Browse files Browse the repository at this point in the history
Add another event to the events.js file and use it in both list-view and standalone download pages. Add testing where relevant and do some cleanup on the prior feature's implementation.
  • Loading branch information
tm-ruxandra committed Mar 13, 2024
1 parent d6bb94c commit 33ba3f3
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 47 deletions.
29 changes: 25 additions & 4 deletions src/monitoring/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,38 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';

import { useAnalytics } from 'monitoring/analytics';

export const useShareEvent = () => {
const { trackEvent } = useAnalytics();
const pageUrl = useMemo(() => window.location, []);

const onShare = method => {
trackEvent('share', { props: { url: pageUrl.toString(), method } });
};
const onShare = useCallback(
method => {
trackEvent('share', { props: { url: pageUrl.toString(), method } });
},
[trackEvent, pageUrl]
);

return { onShare };
};

export const useDownloadEvent = () => {
const { trackEvent } = useAnalytics();

const onDownload = useCallback(
(entityType, ownerSlug, location) => {
trackEvent('dataEntry.file.download', {
props: {
[entityType]: ownerSlug,
'download location': location,
},
});
},
[trackEvent]
);

return { onDownload };
};
39 changes: 31 additions & 8 deletions src/monitoring/events.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,20 @@
import { render } from 'tests/utils';

import { useAnalytics } from 'monitoring/analytics';
import { useShareEvent } from 'monitoring/events';
import { useDownloadEvent, useShareEvent } from 'monitoring/events';

jest.mock('monitoring/analytics', () => ({
...jest.requireActual('monitoring/analytics'),
useAnalytics: jest.fn(),
}));

const Component = () => {
const { onShare } = useShareEvent();

onShare('test');
return <div></div>;
};

test('Events: onShare', async () => {
const Component = () => {
const { onShare } = useShareEvent();
onShare('test');
return <div></div>;
};

const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
Expand All @@ -50,3 +49,27 @@ test('Events: onShare', async () => {
},
});
});

test('Events: onDownload', async () => {
const Component = () => {
const { onDownload } = useDownloadEvent();
onDownload('group', 'abc', 'test');
return <div></div>;
};

const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
});

await render(<Component />);

const eventCall = trackEvent.mock.calls[0];
expect(eventCall[0]).toStrictEqual('dataEntry.file.download');
expect(eventCall[1]).toStrictEqual({
props: {
group: 'abc',
'download location': 'test',
},
});
});
22 changes: 14 additions & 8 deletions src/navigation/components/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import React, { useMemo } from 'react';
import { matchPath, Route, Routes, useLocation } from 'react-router-dom';

import { withProps } from 'react-hoc';

import NotFound from 'layout/NotFound';
import AccountLogin from 'account/components/AccountLogin';
import AccountProfile from 'account/components/AccountProfile';
Expand Down Expand Up @@ -108,13 +110,17 @@ const paths = [
showBreadcrumbs: true,
breadcrumbsLabel: 'group.breadcrumbs_visualization',
}),
path('/groups/:groupSlug/download/:shareUuid', SharedResourceDownload, {
optionalAuth: {
enabled: true,
topMessage:
'sharedData.shared_resource_download_optional_auth_top_message',
},
}),
path(
'/groups/:groupSlug/download/:shareUuid',
withProps(SharedResourceDownload, { entityType: 'group' }),
{
optionalAuth: {
enabled: true,
topMessage:
'sharedData.shared_resource_download_optional_auth_top_message',
},
}
),
path('/landscapes/map', LandscapeMapEmbed, {
optionalAuth: {
enabled: true,
Expand Down Expand Up @@ -167,7 +173,7 @@ const paths = [
),
path(
'/landscapes/:landscapeSlug/download/:shareUuid',
SharedResourceDownload,
withProps(SharedResourceDownload, { entityType: 'landscape' }),
{
optionalAuth: {
enabled: true,
Expand Down
13 changes: 10 additions & 3 deletions src/sharedData/components/SharedResourceDownload.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,24 @@ import { Button, Paper, Stack, Typography } from '@mui/material';
import NotFound from 'layout/NotFound';
import PageContainer from 'layout/PageContainer';
import PageLoader from 'layout/PageLoader';
import { useDownloadEvent } from 'monitoring/events';
import { generateReferrerPath } from 'navigation/navigationUtils';
import { fetchSharedResource } from 'sharedData/sharedDataSlice';

const SharedResourceDownload = () => {
const SharedResourceDownload = props => {
const { t } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
const { shareUuid } = useParams();
const { shareUuid, ...params } = useParams();
const { data: sharedResource, fetching: fetchingSharedResource } =
useSelector(state => state.sharedData.sharedResource);
const hasToken = useSelector(state => state.account.hasToken);

const { entityType } = props;
const ownerSlug =
entityType === 'group' ? params.groupSlug : params.landscapeSlug;
const { onDownload } = useDownloadEvent();

useFetchData(
useCallback(() => fetchSharedResource({ shareUuid }), [shareUuid])
);
Expand All @@ -59,8 +65,9 @@ const SharedResourceDownload = () => {
}, [fetchingSharedResource, location, sharedResource, hasToken, navigate]);

const downloadFile = useCallback(() => {
onDownload(entityType, ownerSlug, 'download page');
window.open(sharedResource.downloadUrl, '_blank');
}, [sharedResource]);
}, [onDownload, entityType, ownerSlug, sharedResource]);

if (fetchingSharedResource) {
return <PageLoader />;
Expand Down
78 changes: 62 additions & 16 deletions src/sharedData/components/SharedResourceDownload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ import { when } from 'jest-when';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import * as terrasoApi from 'terraso-client-shared/terrasoApi/api';

import { useDownloadEvent } from 'monitoring/events';

import SharedResourceDownload from './SharedResourceDownload';

jest.mock('terraso-client-shared/terrasoApi/api');

jest.mock('monitoring/events', () => ({
useDownloadEvent: jest.fn(),
}));

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn(),
Expand All @@ -37,8 +43,25 @@ const DEFAULT_ACCOUNT = {
},
};

const setup = async (account = DEFAULT_ACCOUNT) => {
await render(<SharedResourceDownload />, {
const setupData = () => {
when(terrasoApi.requestGraphQL)
.calledWith(
expect.stringContaining('query sharedResource'),
expect.anything()
)
.mockResolvedValue({
sharedResource: {
downloadUrl: 'https://example.com',
source: {
name: 'map',
resourceType: 'geojson',
},
},
});
};

const setup = async (account = DEFAULT_ACCOUNT, entityType = 'group') => {
await render(<SharedResourceDownload entityType={entityType} />, {
account,
});
};
Expand All @@ -47,29 +70,22 @@ beforeEach(() => {
window.open = jest.fn();
useParams.mockReturnValue({
shareUuid: 'share-uuid-1',
groupSlug: 'private-1',
landscapeSlug: 'private-2',
});
useNavigate.mockReturnValue(jest.fn());
useLocation.mockReturnValue({
pathname:
'/groups/private-1/shared-resource/download/72bd83f7-229e-4770-a686-42f5a922468b',
});

useDownloadEvent.mockReturnValue({
onDownload: jest.fn(),
});
});

test('SharedResourceDownload: Has access', async () => {
when(terrasoApi.requestGraphQL)
.calledWith(
expect.stringContaining('query sharedResource'),
expect.anything()
)
.mockResolvedValue({
sharedResource: {
downloadUrl: 'https://example.com',
source: {
name: 'map',
resourceType: 'geojson',
},
},
});
setupData();
await setup();

expect(
Expand Down Expand Up @@ -114,3 +130,33 @@ test('SharedResourceDownload: Login redirect', async () => {
'/account?referrer=%2Fgroups%2Fprivate-1%2Fshared-resource%2Fdownload%2F72bd83f7-229e-4770-a686-42f5a922468b'
);
});

test('SharedResourceDownload: Group download event', async () => {
const { onDownload } = useDownloadEvent();
setupData();
await setup(DEFAULT_ACCOUNT, 'group');

const downloadButton = screen.getByRole('button', { name: 'Download File' });
await act(async () => fireEvent.click(downloadButton));

expect(onDownload).toHaveBeenCalledWith(
'group',
'private-1',
'download page'
);
});

test('SharedResourceDownload: Landscape download event', async () => {
const { onDownload } = useDownloadEvent();
setupData();
await setup(DEFAULT_ACCOUNT, 'landscape');

const downloadButton = screen.getByRole('button', { name: 'Download File' });
await act(async () => fireEvent.click(downloadButton));

expect(onDownload).toHaveBeenCalledWith(
'landscape',
'private-2',
'download page'
);
});
12 changes: 4 additions & 8 deletions src/sharedData/sharedDataHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,18 @@
import { useCallback } from 'react';

import { useCollaborationContext } from 'collaboration/collaborationContext';
import { useAnalytics } from 'monitoring/analytics';
import { useDownloadEvent } from 'monitoring/events';

export const useSharedData = () => {
const { trackEvent } = useAnalytics();
const { onDownload } = useDownloadEvent();
const { owner, entityType } = useCollaborationContext();

const downloadFile = useCallback(
file => {
trackEvent('dataEntry.file.download', {
props: {
[entityType]: owner.slug,
},
});
onDownload(entityType, owner.slug, 'landscape/group page');
window.open(file.url, '_blank');
},
[trackEvent, owner, entityType]
[onDownload, owner, entityType]
);

return { downloadFile };
Expand Down

0 comments on commit 33ba3f3

Please sign in to comment.