Skip to content

Commit

Permalink
feat: Added Story Map collaboration events (#1177)
Browse files Browse the repository at this point in the history
  • Loading branch information
josebui authored Sep 28, 2023
1 parent fd7ec19 commit 83398f1
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 5 deletions.
13 changes: 11 additions & 2 deletions src/storyMap/components/StoryMapForm/ShareDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import MembershipsList from 'collaboration/components/MembershipsList';
import ConfirmButton from 'common/components/ConfirmButton';
import ExternalLink from 'common/components/ExternalLink';
import UserEmailAutocomplete from 'common/components/UserEmailAutocomplete';
import { useAnalytics } from 'monitoring/analytics';
import Restricted from 'permissions/components/Restricted';
import {
MEMBERSHIP_ROLE_EDITOR,
Expand Down Expand Up @@ -74,6 +75,7 @@ const RoleComponent = ({ member }) => {
const RemoveButton = props => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { trackEvent } = useAnalytics();
const { data: currentUser } = useSelector(state => state.account.currentUser);
const processing = useSelector(
state =>
Expand All @@ -100,9 +102,10 @@ const RemoveButton = props => {
if (isOwnMembership) {
navigate(-1);
}
trackEvent('storymap.share.remove');
}
});
}, [dispatch, navigate, member, storyMap, isOwnMembership]);
}, [dispatch, navigate, trackEvent, member, storyMap, isOwnMembership]);

const resource = useMemo(() => {
if (!member?.userRole || member?.userRole === MEMBERSHIP_ROLE_OWNER) {
Expand Down Expand Up @@ -162,6 +165,7 @@ const RemoveButton = props => {
const ShareDialog = props => {
const dispatch = useDispatch();
const { t } = useTranslation();
const { trackEvent } = useAnalytics();
const processing = useSelector(
state => state.storyMap.memberships.add.saving
);
Expand Down Expand Up @@ -192,10 +196,15 @@ const ShareDialog = props => {
const success = data?.meta?.requestStatus === 'fulfilled';
if (success) {
setNewEditors([]);
trackEvent('storymap.share.invite', {
props: {
count: newEditors.length,
},
});
onClose();
}
});
}, [dispatch, onClose, storyMap, newEditors]);
}, [dispatch, trackEvent, onClose, storyMap, newEditors]);

const memberships = useMemo(
() => [
Expand Down
5 changes: 4 additions & 1 deletion src/storyMap/components/StoryMapInvite.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ import { Alert } from '@mui/material';
import { useDocumentTitle } from 'common/document';
import PageContainer from 'layout/PageContainer';
import PageLoader from 'layout/PageLoader';
import { useAnalytics } from 'monitoring/analytics';
import { approveMembershipToken } from 'storyMap/storyMapSlice';

const StoryMapInvite = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const dispatch = useDispatch();
const { trackEvent } = useAnalytics();
const [searchParams] = useSearchParams();
const token = useMemo(() => searchParams.get('token'), [searchParams]);
const decodedToken = useMemo(() => (token ? jwt(token) : null), [token]);
Expand Down Expand Up @@ -82,7 +84,8 @@ const StoryMapInvite = () => {
return;
}
navigate(`/tools/story-maps/${storyMap.storyMapId}/${storyMap.slug}/edit`);
}, [success, navigate, storyMap]);
trackEvent('storymap.share.accept');
}, [success, navigate, trackEvent, storyMap]);

useDocumentTitle(t('storyMap.invite_document_title'));

Expand Down
20 changes: 20 additions & 0 deletions src/storyMap/components/StoryMapInvite.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { render, screen, waitFor, within } from 'tests/utils';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { mockTerrasoAPIrequestGraphQL } from 'tests/apiUtils';

import { useAnalytics } from 'monitoring/analytics';

import StoryMapInvite from './StoryMapInvite';

// Generated token with https://jwt.io/
Expand All @@ -38,11 +40,27 @@ jest.mock('react-router-dom', () => ({
useSearchParams: jest.fn(),
}));

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

beforeEach(() => {
useAnalytics.mockReturnValue({
trackEvent: jest.fn(),
});
});

const setup = async initialState => {
await render(<StoryMapInvite />, initialState);
};

test('StoryMapInvite: Valid token', async () => {
const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
});

const navigate = jest.fn();
useNavigate.mockReturnValue(navigate);

Expand Down Expand Up @@ -79,6 +97,8 @@ test('StoryMapInvite: Valid token', async () => {
expect(navigate.mock.calls[0]).toEqual([
'/tools/story-maps/story-map-id-1/hello-world/edit',
]);

expect(trackEvent).toHaveBeenCalledWith('storymap.share.accept');
});

test('StoryMapInvite: Invalid token', async () => {
Expand Down
28 changes: 28 additions & 0 deletions src/storyMap/components/StoryMapUpdate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { mockTerrasoAPIrequestGraphQL } from 'tests/apiUtils';
import { changeCombobox } from 'tests/uiUtils';

import i18n from 'localization/i18n';
import { useAnalytics } from 'monitoring/analytics';
import { MEMBERSHIP_ROLE_EDITOR } from 'storyMap/storyMapConstants';

import StoryMapUpdate from './StoryMapUpdate';
Expand All @@ -29,6 +30,11 @@ jest.mock('terraso-client-shared/terrasoApi/api');

jest.mock('./StoryMap', () => props => <div>Test</div>);

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

const CONFIG = {
title: 'Story Map Title',
subtitle: 'Story Map Subtitle',
Expand Down Expand Up @@ -92,6 +98,12 @@ const API_STORY_MAP = {
},
};

beforeEach(() => {
useAnalytics.mockReturnValue({
trackEvent: jest.fn(),
});
});

const setup = async user => {
await render(<StoryMapUpdate />, {
account: {
Expand Down Expand Up @@ -177,6 +189,10 @@ test('StoryMapUpdate: Show Share Dialog', async () => {
});

test('StoryMapUpdate: Share Dialog invite members', async () => {
const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
});
mockTerrasoAPIrequestGraphQL({
'query fetchStoryMap': Promise.resolve({
storyMaps: {
Expand Down Expand Up @@ -245,9 +261,19 @@ test('StoryMapUpdate: Share Dialog invite members', async () => {
expect(
within(membersList).getByRole('listitem', { name: 'Manuel Perez' })
).toBeInTheDocument();

expect(trackEvent).toHaveBeenCalledWith('storymap.share.invite', {
props: {
count: 2,
},
});
});

test('StoryMapUpdate: Share Dialog remove members', async () => {
const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
});
mockTerrasoAPIrequestGraphQL({
'query fetchStoryMap': Promise.resolve({
storyMaps: {
Expand Down Expand Up @@ -290,6 +316,8 @@ test('StoryMapUpdate: Share Dialog remove members', async () => {
storyMapSlug: 'test-slug',
},
});

expect(trackEvent).toHaveBeenCalledWith('storymap.share.remove');
});

test('StoryMapUpdate: See story map as editor', async () => {
Expand Down
5 changes: 4 additions & 1 deletion src/storyMap/components/StoryMapsCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { MEMBERSHIP_STATUS_PENDING } from 'collaboration/collaborationConstants'
import RouterButton from 'common/components/RouterButton';
import RouterLink from 'common/components/RouterLink';
import { formatDate } from 'localization/utils';
import { useAnalytics } from 'monitoring/analytics';
import Restricted from 'permissions/components/Restricted';
import HomeCard from 'home/components/HomeCard';
import { approveMembership, removeUserStoryMap } from 'storyMap/storyMapSlice';
Expand Down Expand Up @@ -75,6 +76,7 @@ const CollaborationIndicator = props => {
const StoryMapListItem = props => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { trackEvent } = useAnalytics();
const { t, i18n } = useTranslation();
const { storyMap } = props;

Expand Down Expand Up @@ -106,9 +108,10 @@ const StoryMapListItem = props => {
const storyMapId = data.payload.storyMap.storyMapId;
const storyMapSlug = data.payload.storyMap.slug;
navigate(`/tools/story-maps/${storyMapId}/${storyMapSlug}/edit`);
trackEvent('storymap.share.accept');
}
});
}, [dispatch, navigate, storyMap, accountMembership]);
}, [dispatch, navigate, trackEvent, storyMap, accountMembership]);

const onDeleteSuccess = useCallback(() => {
dispatch(removeUserStoryMap(storyMap.id));
Expand Down
90 changes: 89 additions & 1 deletion src/storyMap/components/StoryMapsToolHome.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,27 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { render, screen, within } from 'tests/utils';
import { act, fireEvent, render, screen, within } from 'tests/utils';
import * as terrasoApi from 'terraso-client-shared/terrasoApi/api';
import { mockTerrasoAPIrequestGraphQL } from 'tests/apiUtils';

import { useAnalytics } from 'monitoring/analytics';

import StoryMapsToolsHome from './StoryMapsToolHome';

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

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

beforeEach(() => {
useAnalytics.mockReturnValue({
trackEvent: jest.fn(),
});
});

test('StoryMapsToolHome: samples renders correctly', async () => {
terrasoApi.requestGraphQL.mockReturnValue(
Promise.resolve({
Expand Down Expand Up @@ -158,3 +172,77 @@ test('StoryMapsToolHome: user story maps render correctly', async () => {
const link1 = within(items[1]).getByRole('link', { name: 'Story 1' });
expect(link1).toHaveAttribute('href', '/tools/story-maps/46h36we/id-1/edit');
});

test('StoryMapsToolHome: accept story map invite', async () => {
const trackEvent = jest.fn();
useAnalytics.mockReturnValue({
trackEvent,
});
mockTerrasoAPIrequestGraphQL({
'query storyMapsHome': Promise.resolve({
userStoryMaps: {
edges: [
{
node: {
id: 'id-1',
slug: 'id-1',
storyMapId: '46h36we',
title: 'Story 1',
isPublished: false,
updatedAt: '2023-01-31T22:25:42.916303+00:00',
createdBy: {
userId: 'other-user-id',
firstName: 'Pablo',
lastName: 'Perez',
},
membershipList: {
membershipsCount: 0,
accountMembership: {
id: '12eb041f-e847-4f78-89ec-46a6a6b7c5c6',
userRole: 'editor',
membershipStatus: 'PENDING',
},
},
},
},
],
},
}),
'mutation approveMembership': Promise.resolve({
approveStoryMapMembership: {
membership: {
id: 'membership-id-1',
},
storyMap: {
id: 'story-map-id-1',
title: 'Hello world',
storyMapId: 'story-map-id-1',
slug: 'hello-world',
},
},
}),
});

await render(<StoryMapsToolsHome />, {
account: {
currentUser: {
data: {
email: '[email protected]',
firstName: 'Jodies',
},
},
},
});

const storyMapItem = screen.getByRole('listitem', { name: 'Story 1' });

const acceptButton = within(storyMapItem).getByRole('button', {
name: 'Accept',
});

await act(async () => {
fireEvent.click(acceptButton);
});

expect(trackEvent).toHaveBeenCalledWith('storymap.share.accept');
});

0 comments on commit 83398f1

Please sign in to comment.