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

Fix Mailing Address - Confirm buttons #965

Merged
merged 6 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
19 changes: 17 additions & 2 deletions src/components/Tool/FixMailingAddresses/Contact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { useUpdateCache } from 'src/hooks/useUpdateCache';
import { dateFormatShort } from 'src/lib/intlFormat';
import { contactPartnershipStatus } from 'src/utils/contacts/contactPartnershipStatus';
import theme from '../../../theme';
import { emptyAddress } from './FixMailingAddresses';
import { HandleSingleConfirmProps, emptyAddress } from './FixMailingAddresses';
import { ContactAddressFragment } from './GetInvalidAddresses.generated';

const ContactHeader = styled(CardHeader)(() => ({
dr-bizz marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -117,6 +117,12 @@ interface Props {
openEditAddressModal: (address: ContactAddressFragment, id: string) => void;
openNewAddressModal: (address: ContactAddressFragment, id: string) => void;
setContactFocus: SetContactFocus;
handleSingleConfirm: ({
addresses,
id,
name,
onlyErrorOnce,
}: HandleSingleConfirmProps) => void;
}

const Contact: React.FC<Props> = ({
Expand All @@ -128,6 +134,7 @@ const Contact: React.FC<Props> = ({
openEditAddressModal,
openNewAddressModal,
setContactFocus,
handleSingleConfirm,
}) => {
const { t } = useTranslation();
const locale = useLocale();
Expand Down Expand Up @@ -161,6 +168,10 @@ const Contact: React.FC<Props> = ({
});
};

const handleConfirm = () => {
handleSingleConfirm({ addresses, id, name });
};

const handleContactNameClick = () => {
setContactFocus(id);
};
Expand All @@ -176,7 +187,11 @@ const Contact: React.FC<Props> = ({
/>
}
action={
<Button variant="contained" className={classes.confirmButon}>
<Button
variant="contained"
className={classes.confirmButon}
onClick={handleConfirm}
>
<Icon path={mdiCheckboxMarkedCircle} size={0.8} />
{t('Confirm')}
</Button>
Expand Down
130 changes: 130 additions & 0 deletions src/components/Tool/FixMailingAddresses/FixMailingAddresses.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,134 @@ describe('FixSendNewsletter', () => {
expect(setContactFocus).toHaveBeenCalledWith(contactId);
});
});

describe('handleSingleConfirm()', () => {
it('should fire handleSingleConfirm', async () => {
const { getAllByRole, getByText, queryByTestId } = render(
<Components
mocks={{
InvalidAddresses: {
...mockInvalidAddressesResponse.InvalidAddresses,
},
}}
/>,
);
await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);
userEvent.click(getAllByRole('button', { name: 'Confirm' })[0]);

const name = 'Baggins, Frodo';
await waitFor(() => expect(getByText(name)).toBeInTheDocument());

// TODO: Fix when GraphQL is fixed
await waitFor(() =>
expect(mockEnqueue).toHaveBeenCalledWith(
`${name} - Error while saving addresses. undefined`,
{
variant: 'error',
},
),
);

// await waitFor(() =>
// expect(queryByText(name)).not.toBeInTheDocument(),
// );
});
});

describe('handleBulkConfirm()', () => {
it('should fire handleSingleConfirm', async () => {
process.env.APP_NAME = 'MPDX';
const { getByRole, queryByTestId } = render(
<Components
mocks={{
InvalidAddresses: {
...mockInvalidAddressesResponse.InvalidAddresses,
},
}}
/>,
);
await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);
userEvent.click(getByRole('button', { name: 'Confirm 1 as MPDX' }));

await waitFor(() =>
expect(getByRole('heading', { name: 'Confirm' })).toBeInTheDocument(),
);

userEvent.click(getByRole('button', { name: 'Yes' }));

// TODO: Fix when GraphQL is fixed
const name = 'Baggins, Frodo';
await waitFor(() => {
expect(mockEnqueue).toHaveBeenCalledWith(
`Error updating contact ${name}`,
{
variant: 'error',
autoHideDuration: 7000,
},
);
expect(mockEnqueue).toHaveBeenCalledWith(
`Error when updating 1 contact(s)`,
{
variant: 'error',
},
);
});

// await waitFor(() =>
// expect(queryByText(name)).not.toBeInTheDocument(),
// );
});
});

it('should fire handleSingleConfirm', async () => {
process.env.APP_NAME = 'MPDX';
const { getByRole, queryByTestId } = render(
<Components
mocks={{
InvalidAddresses: {
...mockInvalidAddressesResponse.InvalidAddresses,
},
}}
/>,
);
await waitFor(() =>
expect(queryByTestId('loading')).not.toBeInTheDocument(),
);
const name = 'Baggins, Frodo';
userEvent.click(getByRole('combobox'));
userEvent.click(getByRole('option', { name: 'DataServer' }));

userEvent.click(getByRole('button', { name: 'Confirm 1 as DataServer' }));

await waitFor(() =>
expect(getByRole('heading', { name: 'Confirm' })).toBeInTheDocument(),
);

userEvent.click(getByRole('button', { name: 'Yes' }));

// TODO: Fix when GraphQL is fixed
await waitFor(() => {
expect(mockEnqueue).toHaveBeenCalledWith(
`Error updating contact ${name}`,
{
variant: 'error',
autoHideDuration: 7000,
},
);
expect(mockEnqueue).toHaveBeenCalledWith(
`Error when updating 1 contact(s)`,
{
variant: 'error',
},
);
});

// await waitFor(() =>
// expect(queryByText(name)).not.toBeInTheDocument(),
// );
});
});
143 changes: 143 additions & 0 deletions src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
SelectChangeEvent,
Typography,
} from '@mui/material';
import { useSnackbar } from 'notistack';
import { Trans, useTranslation } from 'react-i18next';
import { makeStyles } from 'tss-react/mui';
import { SetContactFocus } from 'pages/accountLists/[accountListId]/tools/useToolsHelper';
import { DynamicAddAddressModal } from 'src/components/Contacts/ContactDetails/ContactDetailsTab/Mailing/AddAddressModal/DynamicAddAddressModal';
import { DynamicEditContactAddressModal } from 'src/components/Contacts/ContactDetails/ContactDetailsTab/Mailing/EditContactAddressModal/DynamicEditContactAddressModal';
import { Confirmation } from 'src/components/common/Modal/Confirmation/Confirmation';
import theme from '../../../theme';
import NoData from '../NoData';
import Contact from './Contact';
Expand All @@ -26,8 +28,16 @@
InvalidAddressesDocument,
InvalidAddressesQuery,
useInvalidAddressesQuery,
useUpdateContactAddressMutation,
} from './GetInvalidAddresses.generated';

export type HandleSingleConfirmProps = {
addresses: ContactAddressFragment[];
id: string;
name: string;
onlyErrorOnce?: boolean;
};

const useStyles = makeStyles()(() => ({
container: {
padding: theme.spacing(3),
Expand Down Expand Up @@ -131,9 +141,124 @@
const [selectedAddress, setSelectedAddress] = useState(emptyAddress);
const [selectedContactId, setSelectedContactId] = useState('');
const [defaultSource, setDefaultSource] = useState(appName);
const [openBulkConfirmModal, setOpenBulkConfirmModal] = useState(false);

const { data, loading } = useInvalidAddressesQuery({
variables: { accountListId },
});
const [updateAddress] = useUpdateContactAddressMutation();
const { enqueueSnackbar } = useSnackbar();

const handleSingleConfirm = async ({
addresses,
id,
name,
onlyErrorOnce = false,
}: HandleSingleConfirmProps) => {
const errors: string[] = [];

for (let idx = 0; idx < addresses.length; idx++) {
const address = addresses[idx];

await updateAddress({
variables: {
accountListId,
attributes: {
id: address.id,
validValues: true,
// TODO: Fix the Graph QL Input
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
primaryMailingAddress: address.primaryMailingAddress,
},
},
update(cache) {

Check warning on line 175 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L175

Added line #L175 was not covered by tests
if (idx === addresses.length - 1 && !errors.length) {
cache.evict({ id: `Contact:${id}` });

Check warning on line 177 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L177

Added line #L177 was not covered by tests
}
},
onError(error) {
errors.push(
`${name} - ${t('Error while saving addresses.')} ${error.cause}`,
);
},
});
}

if (errors.length) {
if (onlyErrorOnce) {
enqueueSnackbar(t(`Error updating contact ${name}`), {
variant: 'error',
autoHideDuration: 7000,
});
} else {
errors.forEach((error) => {
enqueueSnackbar(error, { variant: 'error' });
});
}
return { success: false };
} else {
enqueueSnackbar(t(`Updated contact ${name}`), { variant: 'success' });
return { success: true };

Check warning on line 202 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L200-L202

Added lines #L200 - L202 were not covered by tests
}
};

const handleBulkConfirm = async () => {
try {
const callsByContact: (() => Promise<{ success: boolean }>)[] = [];
data?.contacts?.nodes.forEach((contact) => {
const primaryAddress = contact.addresses.nodes.find(
(address) =>
address.source === defaultSource ||
(defaultSource === appName && address.source === 'MPDX'),
);
if (primaryAddress) {
const addresses: ContactAddressFragment[] = [];
contact.addresses.nodes.forEach((address) => {
addresses.push({
...address,
primaryMailingAddress: address.id === primaryAddress?.id,
});
});
const callContactMutation = () =>
handleSingleConfirm({
addresses,
id: contact.id,
name: contact.name,
onlyErrorOnce: true,
});
callsByContact.push(callContactMutation);
}
});

if (callsByContact.length) {
const results = await Promise.all(callsByContact.map((call) => call()));

const failedUpdates = results.filter(
(result) => !result.success,
).length;
const successfulUpdates = results.length - failedUpdates;

if (successfulUpdates) {
enqueueSnackbar(t(`Updated ${successfulUpdates} contact(s)`), {

Check warning on line 243 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L243

Added line #L243 was not covered by tests
variant: 'success',
});
}
if (failedUpdates) {
enqueueSnackbar(
t(`Error when updating ${failedUpdates} contact(s)`),
{
variant: 'error',
},
);
}
} else {
enqueueSnackbar(t(`No contacts were updated`), { variant: 'warning' });

Check warning on line 256 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L255-L256

Added lines #L255 - L256 were not covered by tests
}
} catch (error) {
enqueueSnackbar(t(`Error updating contacts`), { variant: 'error' });

Check warning on line 259 in src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/Tool/FixMailingAddresses/FixMailingAddresses.tsx#L259

Added line #L259 was not covered by tests
}
};

const handleUpdateCacheForDeleteAddress = useCallback(
(cache: ApolloCache<unknown>, data) => {
Expand Down Expand Up @@ -213,6 +338,10 @@
setDefaultSource(event.target.value);
};

const handleBulkConfirmModalClose = () => {
setOpenBulkConfirmModal(false);
};

const totalContacts = data?.contacts?.nodes?.length || 0;

return (
Expand Down Expand Up @@ -273,6 +402,7 @@
<Button
variant="contained"
className={classes.confirmAllButton}
onClick={() => setOpenBulkConfirmModal(true)}
>
<Icon
path={mdiCheckboxMarkedCircle}
Expand Down Expand Up @@ -303,6 +433,7 @@
handleModalOpen(ModalEnum.New, address, contactId)
}
setContactFocus={setContactFocus}
handleSingleConfirm={handleSingleConfirm}
/>
))}
</Grid>
Expand Down Expand Up @@ -341,6 +472,18 @@
handleUpdateCache={handleUpdateCacheForAddAddress}
/>
)}
{openBulkConfirmModal && (
<Confirmation
isOpen={true}
title={t('Confirm')}
message={t(
`You are updating all contacts visible on this page, setting the first {{source}} address as the primary address. If no such address exists the contact will not be updated. Are you sure you want to do this?`,
{ source: defaultSource },
)}
handleClose={handleBulkConfirmModalClose}
mutation={handleBulkConfirm}
/>
)}
</Box>
);
};
Expand Down
Loading
Loading