From e020f9ef3190c5e14b47ee2666ada1677e6b2dba Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 26 Aug 2024 17:03:23 +1000 Subject: [PATCH 1/2] Copy changes & remove gravatar - Address feedback from Gen/Product - Remove gravatar icon from profile dropdown & associated test - Use the correct case regarding the CSTG value types & update tests - Fix punctuation, pluralisation and upper/lower case in a bunch of other places - Make the instructions for mobile app IDs clearer - Add a link to our docs on the sharing permissions page --- .../CstgAddDialog.spec.tsx | 4 +-- .../CstgAddDialog.tsx | 7 ++-- .../ClientSideTokenGeneration/CstgHelper.ts | 11 ++++++ .../ClientSideTokenGeneration/CstgTable.tsx | 19 ++++++---- .../AddParticipantDialog.tsx | 2 +- .../PortalHeader/PortalHeader.spec.tsx | 35 +++++++------------ .../components/PortalHeader/PortalHeader.tsx | 10 +----- src/web/components/TeamMember/TeamMember.tsx | 2 +- src/web/screens/clientSideIntegration.tsx | 8 ++--- src/web/screens/manageParticipants.tsx | 2 +- src/web/screens/sharingPermissions.tsx | 26 +++++++++----- 11 files changed, 67 insertions(+), 59 deletions(-) diff --git a/src/web/components/ClientSideTokenGeneration/CstgAddDialog.spec.tsx b/src/web/components/ClientSideTokenGeneration/CstgAddDialog.spec.tsx index a9bb05ca..1544bc01 100644 --- a/src/web/components/ClientSideTokenGeneration/CstgAddDialog.spec.tsx +++ b/src/web/components/ClientSideTokenGeneration/CstgAddDialog.spec.tsx @@ -147,7 +147,7 @@ describe('CstgAddDialog', () => { ); await submitDialogDomains(); - expect(screen.getByText('Please specify Root-Level Domains.')).toBeInTheDocument(); + expect(screen.getByText('Please specify root-level domains.')).toBeInTheDocument(); }); it('should be able to click save if user types in correct single mobile app ID', async () => { @@ -282,6 +282,6 @@ describe('CstgAddDialog', () => { ); await submitDialogMobileAppIds(); - expect(screen.getByText('Please specify Mobile App IDs.')).toBeInTheDocument(); + expect(screen.getByText('Please specify mobile app IDs.')).toBeInTheDocument(); }); }); diff --git a/src/web/components/ClientSideTokenGeneration/CstgAddDialog.tsx b/src/web/components/ClientSideTokenGeneration/CstgAddDialog.tsx index 18c59afa..95979d7b 100644 --- a/src/web/components/ClientSideTokenGeneration/CstgAddDialog.tsx +++ b/src/web/components/ClientSideTokenGeneration/CstgAddDialog.tsx @@ -14,6 +14,7 @@ import { AddCstgValuesFormProps, CstgValueType, extractTopLevelDomain, + formatCstgValueType, getUniqueCstgValues, validateAppId, } from './CstgHelper'; @@ -57,7 +58,7 @@ function CstgAddDialog({ deleteExistingList ); if (newCstgValues.length === 0) { - handleError(`The ${cstgValueType}s entered already exist.`); + handleError(`The ${formatCstgValueType(cstgValueType)}s entered already exist.`); } else if (cstgValueType === CstgValueType.Domain) { newCstgValues.forEach((newDomain, index) => { newCstgValues[index] = extractTopLevelDomain(newDomain); @@ -109,12 +110,12 @@ function CstgAddDialog({ onClick={onClickCheckbox} checked={deleteExistingList} /> -
{`Replace all existing ${cstgValueType}s with the new ones.`}
+
{`Replace all existing ${formatCstgValueType(cstgValueType)}s with the new ones.`}
diff --git a/src/web/components/ClientSideTokenGeneration/CstgHelper.ts b/src/web/components/ClientSideTokenGeneration/CstgHelper.ts index d20995ac..e65b6765 100644 --- a/src/web/components/ClientSideTokenGeneration/CstgHelper.ts +++ b/src/web/components/ClientSideTokenGeneration/CstgHelper.ts @@ -26,6 +26,17 @@ export enum CstgValueType { MobileAppId = 'Mobile App ID', } +export const formatCstgValueType = (valueType: CstgValueType) => { + switch (valueType) { + case CstgValueType.Domain: + return 'root-level domain'; + case CstgValueType.MobileAppId: + return 'mobile app ID'; + default: + return valueType; + } +}; + export const extractTopLevelDomain = (domainName: string) => { const topLevelDomain = parse(domainName).domain; if (topLevelDomain && topLevelDomain !== domainName) { diff --git a/src/web/components/ClientSideTokenGeneration/CstgTable.tsx b/src/web/components/ClientSideTokenGeneration/CstgTable.tsx index c04d9842..57fc907b 100644 --- a/src/web/components/ClientSideTokenGeneration/CstgTable.tsx +++ b/src/web/components/ClientSideTokenGeneration/CstgTable.tsx @@ -8,7 +8,12 @@ import { TableNoDataPlaceholder } from '../Core/Tables/TableNoDataPlaceholder'; import { TriStateCheckbox, TriStateCheckboxState } from '../Input/TriStateCheckbox'; import CstgAddDialog from './CstgAddDialog'; import CstgDeleteDialog from './CstgDeleteDialog'; -import { CstgValueType, getPagedValues, UpdateCstgValuesResponse } from './CstgHelper'; +import { + CstgValueType, + formatCstgValueType, + getPagedValues, + UpdateCstgValuesResponse, +} from './CstgHelper'; import { CstgItem } from './CstgItem'; import './CstgTable.scss'; @@ -229,7 +234,7 @@ export function CstgTable({ type='text' className='cstg-values-search-bar' onChange={handleSearchCstgValue} - placeholder={`Search ${cstgValueType}s`} + placeholder={`Search ${formatCstgValueType(cstgValueType)}s`} value={searchText} /> @@ -273,9 +278,9 @@ export function CstgTable({ ))} - {searchText && !searchedCstgValues.length && ( - - {`There are no ${cstgValueType}s that match this search.`} + {cstgValues.length !== 0 && searchText && !searchedCstgValues.length && ( + + {`There are no ${formatCstgValueType(cstgValueType)}s that match this search.`} )} {!!searchedCstgValues.length && ( @@ -288,8 +293,8 @@ export function CstgTable({ )} {!cstgValues.length && ( - - {`There are no ${cstgValueType}s`} + + {`There are no ${formatCstgValueType(cstgValueType)}s.`} )}
diff --git a/src/web/components/ParticipantManagement/AddParticipantDialog.tsx b/src/web/components/ParticipantManagement/AddParticipantDialog.tsx index 19fe83d9..58a051c0 100644 --- a/src/web/components/ParticipantManagement/AddParticipantDialog.tsx +++ b/src/web/components/ParticipantManagement/AddParticipantDialog.tsx @@ -84,7 +84,7 @@ function AddParticipantDialog({ async (formData: AddParticipantForm) => { const response = await onAddParticipant(formData); if (response.status === 200) { - SuccessToast('Participant Added.'); + SuccessToast('Participant added.'); } onOpenChange(); }, diff --git a/src/web/components/PortalHeader/PortalHeader.spec.tsx b/src/web/components/PortalHeader/PortalHeader.spec.tsx index 9c2ae835..5e80f113 100644 --- a/src/web/components/PortalHeader/PortalHeader.spec.tsx +++ b/src/web/components/PortalHeader/PortalHeader.spec.tsx @@ -1,29 +1,20 @@ import { composeStories } from '@storybook/react'; -import { render, screen, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render, screen } from '@testing-library/react'; import * as stories from './PortalHeader.stories'; -const { ValidEmailAddress, InvalidEmailAddress, NoEmailAddress } = composeStories(stories); +const { InvalidEmailAddress, NoEmailAddress } = composeStories(stories); -test('when the drop is clicked, a gravatar is displayed', async () => { - const user = userEvent.setup(); - render(); - const button = screen.getByRole('button'); - await user.click(button); - const menu = screen.getByRole('menu'); - const avatar = within(menu).getByRole('img'); - expect(avatar).toHaveAttribute('src', expect.stringContaining('//www.gravatar.com/avatar/')); -}); - -test('when an invalid email address is provided, a home link is still displayed', async () => { - render(); - const link = screen.getByRole('link'); - expect(link).toHaveAttribute('href', expect.stringContaining('/home')); -}); +describe('Portal Header tests', () => { + test('when an invalid email address is provided, a home link is still displayed', async () => { + render(); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', expect.stringContaining('/home')); + }); -test('when no email is provided, the dropdown text shows that there is no logged in user', async () => { - render(); - const button = screen.getByRole('button'); - expect(button).toHaveTextContent('Not logged in'); + test('when no email is provided, the dropdown text shows that there is no logged in user', async () => { + render(); + const button = screen.getByRole('button'); + expect(button).toHaveTextContent('Not logged in'); + }); }); diff --git a/src/web/components/PortalHeader/PortalHeader.tsx b/src/web/components/PortalHeader/PortalHeader.tsx index a31edd80..58b01956 100644 --- a/src/web/components/PortalHeader/PortalHeader.tsx +++ b/src/web/components/PortalHeader/PortalHeader.tsx @@ -71,16 +71,8 @@ export function PortalHeader({ -
- - {!!email && ( - Profile avatar - )} - -
{LoggedInUser?.user && ( <> - {routes.map((route) => { return ( - Log out + Log Out
diff --git a/src/web/components/TeamMember/TeamMember.tsx b/src/web/components/TeamMember/TeamMember.tsx index ad00b44d..01503c4e 100644 --- a/src/web/components/TeamMember/TeamMember.tsx +++ b/src/web/components/TeamMember/TeamMember.tsx @@ -58,7 +58,7 @@ function TeamMember({ setInviteState(InviteState.inProgress); try { await resendInvite(person.id); - SuccessToast('Invitation sent'); + SuccessToast('Invitation sent.'); setInviteState(InviteState.sent); } catch (e) { setErrorInfo(e as Error); diff --git a/src/web/screens/clientSideIntegration.tsx b/src/web/screens/clientSideIntegration.tsx index 4bbde2f6..420d41b8 100644 --- a/src/web/screens/clientSideIntegration.tsx +++ b/src/web/screens/clientSideIntegration.tsx @@ -76,7 +76,7 @@ function ClientSideIntegration() { try { await UpdateKeyPair({ name, subscriptionId, disabled }, participant!.id!); reloader.revalidate(); - SuccessToast('Key Pair updated.'); + SuccessToast('Key pair updated.'); } catch (e: unknown) { handleErrorToast(e); } @@ -105,7 +105,7 @@ function ClientSideIntegration() { domains = invalidDomains; } else { reloader.revalidate(); - SuccessToast(`Root-Level Domains ${action}.`); + SuccessToast(`Root-level domains ${action}.`); } const updatedDomainNamesResponse: UpdateCstgValuesResponse = { cstgValues: sortStringsAlphabetically(domains), @@ -120,7 +120,7 @@ function ClientSideIntegration() { try { const appIds = await UpdateAppIds(updatedAppIds, participant!.id); reloader.revalidate(); - SuccessToast(`Mobile App IDs ${action}.`); + SuccessToast(`Mobile app IDs ${action}.`); const updatedAppIdsResponse: UpdateCstgValuesResponse = { cstgValues: sortStringsAlphabetically(appIds), @@ -200,7 +200,7 @@ function ClientSideIntegration() { onAddCstgValues={onAddCstgValues} onUpdateCstgValues={handleUpdateAppIds} cstgValueType={CstgValueType.MobileAppId} - addInstructions='Please register the Android App ID, iOS/tvOS Bundle ID, and iOS App Store ID.' + addInstructions='Add any mobile app IDs that apply: Android App IDs and/or iOS/tvOS Bundle IDs with corresponding iOS App Store IDs.' /> )} diff --git a/src/web/screens/manageParticipants.tsx b/src/web/screens/manageParticipants.tsx index b74ce221..ea98d58b 100644 --- a/src/web/screens/manageParticipants.tsx +++ b/src/web/screens/manageParticipants.tsx @@ -69,7 +69,7 @@ function ManageParticipants() { const p = await GetUsersDefaultParticipant(); setParticipant(p); } - SuccessToast('Participant updated'); + SuccessToast('Participant updated.'); reloader.revalidate(); }; diff --git a/src/web/screens/sharingPermissions.tsx b/src/web/screens/sharingPermissions.tsx index fee25513..46ce7121 100644 --- a/src/web/screens/sharingPermissions.tsx +++ b/src/web/screens/sharingPermissions.tsx @@ -75,9 +75,9 @@ function SharingPermissions() { SuccessToast( `${ selectedTypes.length === 1 - ? '1 Participant type' - : `${selectedTypes.length} Participant types` - } saved to your Sharing Permissions` + ? '1 participant type' + : `${selectedTypes.length} participant types` + } saved to your sharing permissions.` ); if (!participant?.completedRecommendations) { const updatedParticipant = await CompleteRecommendations(participant!.id); @@ -94,8 +94,8 @@ function SharingPermissions() { await AddSharingParticipants(participant!.id, selectedSiteIds); SuccessToast( `${ - selectedSiteIds.length === 1 ? '1 Participant' : `${selectedSiteIds.length} Participants` - } added to your Sharing Permissions` + selectedSiteIds.length === 1 ? '1 participant' : `${selectedSiteIds.length} participants` + } added to your sharing permissions.` ); reloader.revalidate(); } catch (e) { @@ -109,7 +109,7 @@ function SharingPermissions() { SuccessToast( `${siteIdsToDelete.length} sharing ${ siteIdsToDelete.length > 1 ? 'permissions' : 'permission' - } deleted` + } deleted.` ); reloader.revalidate(); } catch (e) { @@ -139,7 +139,16 @@ function SharingPermissions() { <>

Adding a sharing permission allows the participant you’re sharing with to - decrypt your UID2 tokens. + decrypt your UID2 tokens. For more information, see{' '} + + Sharing Permissions + + .

Note: This only enables the sharing permission. No data is sent. @@ -150,8 +159,7 @@ function SharingPermissions() { As a publisher, you can share with others by granting permission on this page. However, to allow others to share with you, you must ask your UID2 - contact to get the correct permissions added to your account. Note: This - only enables the sharing permission. No data is sent. + contact to get the correct permissions added to your account. )} From 775064efdc7ab1b89885efc43d4968125492ca5f Mon Sep 17 00:00:00 2001 From: Alex Yau Date: Mon, 26 Aug 2024 17:13:25 +1000 Subject: [PATCH 2/2] Fix build --- src/web/components/PortalHeader/PortalHeader.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/web/components/PortalHeader/PortalHeader.tsx b/src/web/components/PortalHeader/PortalHeader.tsx index 58b01956..a5bca5ea 100644 --- a/src/web/components/PortalHeader/PortalHeader.tsx +++ b/src/web/components/PortalHeader/PortalHeader.tsx @@ -1,5 +1,4 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Avatar } from '@radix-ui/react-avatar'; import { DropdownMenu, DropdownMenuArrow, @@ -9,7 +8,6 @@ import { DropdownMenuTrigger, } from '@radix-ui/react-dropdown-menu'; import * as Switch from '@radix-ui/react-switch'; -import MD5 from 'crypto-js/md5'; import { useContext, useEffect, useState } from 'react'; import { Link, useParams } from 'react-router-dom'; @@ -36,7 +34,6 @@ export function PortalHeader({ }: Readonly) { const { participantId } = useParams(); const { LoggedInUser } = useContext(CurrentUserContext); - const emailMd5 = email ? MD5(email).toString() : null; const routes = [ParticipantInformationRoute, TeamMembersRoute, EmailContactsRoute]; const [menuOpen, setMenuOpen] = useState(false);