Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MPDX-7416 - Fix Email Addresses - Confirm All Button #982

Merged
merged 23 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c0148a5
added graphQL mutation
Jul 8, 2024
73a395c
fixed add email functionality
Jun 17, 2024
17b3df4
Fix inline email address editing
wrandall22 Jul 19, 2024
cfdbd7c
Fix part of the caching issue. The way the component is using state o…
Jul 9, 2024
3d89e00
fixed modal close button styling
Jul 11, 2024
a8b6328
added delete functionality and fixed modal issues
wrandall22 Jul 19, 2024
f93cc21
Do a bit of cleanup of the code
wrandall22 Jul 19, 2024
7e3678c
Fix up the tests now that delete is working
wrandall22 Jul 19, 2024
122cd9b
Implement single confirm button
wrandall22 Jul 24, 2024
ad84715
Allow for selection of primary when all email addresses are primary
wrandall22 Jul 24, 2024
aa2b9f9
Implement bulk confirm button
wrandall22 Jul 24, 2024
893af94
Add a confirmation modal for bulk save
wrandall22 Jul 25, 2024
2df85fb
Use the app name instead of hard-coding MPDX for source
wrandall22 Jul 25, 2024
06f2494
Bring over the logic from Angular surrounding bulkSave and the source…
wrandall22 Jul 26, 2024
65d745a
Merge branch 'main' into MPDX-7416-fix-email-addresses-confirm-all
dr-bizz Aug 8, 2024
20e3f47
Fixing tests to check for appName and ensuring all instances of "MPDX…
dr-bizz Aug 8, 2024
13bac5f
Fix test
wrandall22 Aug 8, 2024
5ee1242
Garbage collect the cache after evicting
wrandall22 Aug 9, 2024
cd0f05d
Add TODO for future improvements
wrandall22 Aug 9, 2024
3717840
Make the source dropdown dynamic and styled the same as fix mailing a…
wrandall22 Aug 9, 2024
41b5ab9
Add dynamic source loading for mailing addresses as well
wrandall22 Aug 9, 2024
c6843ce
Add logic to capture bad data, following the example of fix mailing a…
wrandall22 Aug 12, 2024
56503c7
Simplify
wrandall22 Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const EmailValidationForm = ({
emailAddressesMutation({
variables: {
input: {
accountListId: accountListId || '',
accountListId: accountListId ?? '',
attributes: {
id: personId,
emailAddresses: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { makeStyles } from 'tss-react/mui';
import { SetContactFocus } from 'pages/accountLists/[accountListId]/tools/useToolsHelper';
import { useUpdateEmailAddressesMutation } from 'src/components/Tool/FixEmailAddresses/FixEmailAddresses.generated';
import { Confirmation } from 'src/components/common/Modal/Confirmation/Confirmation';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import { useLocale } from 'src/hooks/useLocale';
import { dateFormatShort } from 'src/lib/intlFormat';
import theme from 'src/theme';
Expand Down Expand Up @@ -138,6 +139,7 @@ export const FixEmailAddressPerson: React.FC<FixEmailAddressPersonProps> = ({
handleSingleConfirm,
setContactFocus,
}) => {
const { appName } = useGetAppSettings();
const { t } = useTranslation();
const locale = useLocale();
const { classes } = useStyles();
Expand Down Expand Up @@ -327,10 +329,10 @@ export const FixEmailAddressPerson: React.FC<FixEmailAddressPersonProps> = ({
event: React.ChangeEvent<HTMLInputElement>,
) => handleChange(id, index, event)}
value={email.email}
disabled={email.source !== 'MPDX'}
disabled={email.source !== appName}
/>

{email.source === 'MPDX' ? (
{email.source === appName ? (
<Box
data-testid={`delete-${id}-${index}`}
onClick={() =>
Expand Down Expand Up @@ -360,7 +362,7 @@ export const FixEmailAddressPerson: React.FC<FixEmailAddressPersonProps> = ({
<strong>{t('Source')}: </strong>
</Typography>
</Hidden>
<Typography display="inline">MPDX</Typography>
<Typography display="inline">{appName}</Typography>
</Box>
</Box>
</RowWrapper>
Expand Down
13 changes: 13 additions & 0 deletions src/components/Tool/FixEmailAddresses/FixEmailAddresses.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,16 @@ mutation UpdateEmailAddresses($input: PersonUpdateMutationInput!) {
}
}
}

mutation UpdatePeople($input: PeopleUpdateMutationInput!) {
updatePeople(input: $input) {
people {
emailAddresses {
nodes {
...PersonEmailAddress
validValues
}
}
}
}
}
203 changes: 202 additions & 1 deletion src/components/Tool/FixEmailAddresses/FixEmailAddresses.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import {
GetInvalidEmailAddressesQuery,
UpdateEmailAddressesMutation,
UpdatePeopleMutation,
} from 'src/components/Tool/FixEmailAddresses/FixEmailAddresses.generated';
import useGetAppSettings from 'src/hooks/useGetAppSettings';
import theme from '../../../theme';
import { EmailAddressesMutation } from './AddEmailAddress.generated';
import { FixEmailAddresses } from './FixEmailAddresses';
import {
FixEmailAddresses,
PersonEmailAddresses,
determineBulkDataToSend,
} from './FixEmailAddresses';
import {
contactId,
contactOneEmailAddressNodes,
Expand Down Expand Up @@ -41,6 +47,7 @@ jest.mock('notistack', () => ({
};
},
}));
jest.mock('src/hooks/useGetAppSettings');

const defaultGraphQLMock = {
GetInvalidEmailAddresses: {
Expand All @@ -61,6 +68,7 @@ const Components = ({ mocks = defaultGraphQLMock }: ComponentsProps) => (
GetInvalidEmailAddresses: GetInvalidEmailAddressesQuery;
EmailAddresses: EmailAddressesMutation;
UpdateEmailAddresses: UpdateEmailAddressesMutation;
UpdatePeople: UpdatePeopleMutation;
}>
mocks={mocks}
onCall={mutationSpy}
Expand All @@ -77,6 +85,11 @@ const Components = ({ mocks = defaultGraphQLMock }: ComponentsProps) => (
);

describe('FixEmailAddresses-Home', () => {
beforeEach(() => {
(useGetAppSettings as jest.Mock).mockReturnValue({
appName: 'MPDX',
});
});
it('default with test data', async () => {
const { getByText, getByTestId, queryByTestId } = render(<Components />);

Expand All @@ -97,6 +110,15 @@ describe('FixEmailAddresses-Home', () => {
expect(queryByTestId('no-data')).not.toBeInTheDocument();
});

it('should show the app name as a source value', async () => {
const { getByRole, getByText } = render(<Components />);
await waitFor(() => {
expect(getByText('Fix Email Addresses')).toBeInTheDocument();
expect(getByText('Confirm 2 as MPDX')).toBeInTheDocument();
expect(getByRole('combobox')).toHaveDisplayValue('MPDX');
});
});

describe('handleChangePrimary()', () => {
it('changes primary of first email', async () => {
const { getByTestId, queryByTestId } = render(<Components />);
Expand Down Expand Up @@ -382,4 +404,183 @@ describe('FixEmailAddresses-Home', () => {
});
});
});

describe('handleBulkConfirm', () => {
it('should save all the email changes for all people', async () => {
const noPeopleMessage = 'No people with email addresses need attention';

const { getByRole, getByText, getByTestId, queryByTestId } = render(
<Components />,
);

await waitFor(() => {
expect(queryByTestId('loading')).not.toBeInTheDocument();
expect(getByTestId('starOutlineIcon-testid-1')).toBeInTheDocument();
});
userEvent.click(getByTestId('starOutlineIcon-testid-1'));

const bulkConfirmButton = getByRole('button', {
name: 'Confirm 2 as MPDX',
});
userEvent.click(bulkConfirmButton);
userEvent.click(getByRole('button', { name: 'Yes' }));

await waitFor(() => {
expect(mockEnqueue).toHaveBeenCalledWith(
`Successfully updated email addresses`,
{ variant: 'success' },
);
expect(getByText(noPeopleMessage)).toBeVisible();
});
});

it('should handle errors', async () => {
const personName1 = 'Test Contact';
const personName2 = 'Simba Lion';

const { getByRole, getByText, queryByTestId } = render(
<Components
mocks={{
GetInvalidEmailAddresses: {
people: {
nodes: mockInvalidEmailAddressesResponse,
},
},
UpdatePeople: () => {
throw new Error('Server error');
},
}}
/>,
);

await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);

const bulkConfirmButton = getByRole('button', {
name: 'Confirm 2 as MPDX',
});
userEvent.click(bulkConfirmButton);
userEvent.click(getByRole('button', { name: 'Yes' }));

await waitFor(() => {
expect(mockEnqueue).toHaveBeenCalledWith(
`Error updating email addresses`,
{ variant: 'error', autoHideDuration: 7000 },
);
expect(getByText(personName1)).toBeVisible();
expect(getByText(personName2)).toBeVisible();
});
});

it('should cancel the bulk confirmation', async () => {
const personName1 = 'Test Contact';
const personName2 = 'Simba Lion';

const { getByRole, getByText, queryByTestId } = render(
<Components
mocks={{
GetInvalidEmailAddresses: {
people: {
nodes: mockInvalidEmailAddressesResponse,
},
},
}}
/>,
);

await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);

const bulkConfirmButton = getByRole('button', {
name: 'Confirm 2 as MPDX',
});
userEvent.click(bulkConfirmButton);
userEvent.click(getByRole('button', { name: 'No' }));

await waitFor(() => {
expect(mockEnqueue).not.toHaveBeenCalled();
expect(getByText(personName1)).toBeVisible();
expect(getByText(personName2)).toBeVisible();
});
});

it('should not update if there is no email for the default source', async () => {
const noPrimaryEmailMessage =
'No DataServer primary email address exists to update';

const { getByRole, queryByTestId } = render(<Components />);

await waitFor(() => {
expect(queryByTestId('loading')).not.toBeInTheDocument();
});
userEvent.selectOptions(getByRole('combobox'), 'DataServer');

const bulkConfirmButton = getByRole('button', {
name: 'Confirm 2 as DataServer',
});
userEvent.click(bulkConfirmButton);
userEvent.click(getByRole('button', { name: 'Yes' }));

await waitFor(() => {
expect(mockEnqueue).toHaveBeenCalledWith(noPrimaryEmailMessage, {
variant: 'warning',
autoHideDuration: 7000,
});
expect(bulkConfirmButton).toBeVisible();
});
});
});

describe('determineBulkDataToSend', () => {
it('should set the first email of the given source to primary', () => {
const dataState = {
testid: {
emailAddresses: [
{
...contactOneEmailAddressNodes[0],
primary: false,
},
{
...contactOneEmailAddressNodes[1],
},
{
...contactOneEmailAddressNodes[2],
primary: true,
},
],
},
} as { [key: string]: PersonEmailAddresses };
const defaultSource = 'MPDX';

const dataToSend = determineBulkDataToSend(dataState, defaultSource);

const emails = dataToSend[0].emailAddresses ?? [];
expect(emails[0].primary).toEqual(true);
expect(emails[2].primary).toEqual(false);
});

it('should be empty if there is no email of the given source', () => {
const dataState = {
testid: {
emailAddresses: [
{
...contactOneEmailAddressNodes[0],
},
{
...contactOneEmailAddressNodes[1],
},
{
...contactOneEmailAddressNodes[2],
},
],
},
} as { [key: string]: PersonEmailAddresses };
const defaultSource = 'DataServer';

const dataToSend = determineBulkDataToSend(dataState, defaultSource);
expect(dataToSend.length).toEqual(0);
});
});
});
Loading
Loading