Skip to content

Commit

Permalink
Merge pull request #947 from CruGlobal/limit-contact-merge
Browse files Browse the repository at this point in the history
HelpScout - 1154070 - Limit contact merge
  • Loading branch information
dr-bizz authored May 20, 2024
2 parents b53eca5 + c3f4b14 commit 77129da
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,87 @@ describe('MassActionsMergeModal', () => {
expect(deselectAll).toHaveBeenCalled();
});
});

it('should show contact error message if 9 contacts or over', async () => {
const { getByText, queryByText } = render(
<ThemeProvider theme={theme}>
<TestRouter>
<GqlMockedProvider<{
GetContactsForMerging: GetContactsForMergingQuery;
}>
mocks={mocks}
>
<ContactsContext.Provider
value={{ deselectAll: jest.fn() } as unknown as ContactsType}
>
<MassActionsMergeModal
accountListId={accountListId}
ids={[
'contact-1',
'contact-2',
'contact-3',
'contact-4',
'contact-5',
'contact-6',
'contact-7',
'contact-8',
'contact-9',
]}
handleClose={handleClose}
/>
</ContactsContext.Provider>
</GqlMockedProvider>
</TestRouter>
</ThemeProvider>,
);
await waitFor(() => {
expect(
getByText('You can only merge up to 8 contacts at a time.'),
).toBeInTheDocument();

expect(
queryByText('This action cannot be undone!'),
).not.toBeInTheDocument();
});
});

it('should not show contact error message if 8 contacts', async () => {
const { getByText, queryByText } = render(
<ThemeProvider theme={theme}>
<TestRouter>
<GqlMockedProvider<{
GetContactsForMerging: GetContactsForMergingQuery;
}>
mocks={mocks}
>
<ContactsContext.Provider
value={{ deselectAll: jest.fn() } as unknown as ContactsType}
>
<MassActionsMergeModal
accountListId={accountListId}
ids={[
'contact-1',
'contact-2',
'contact-3',
'contact-4',
'contact-5',
'contact-6',
'contact-7',
'contact-8',
]}
handleClose={handleClose}
/>
</ContactsContext.Provider>
</GqlMockedProvider>
</TestRouter>
</ThemeProvider>,
);
await waitFor(() => {
expect(
queryByText('You can only merge up to 8 contacts at a time.'),
).not.toBeInTheDocument();

expect(getByText('This action cannot be undone!')).toBeInTheDocument();
});
});
});
179 changes: 101 additions & 78 deletions src/components/Contacts/MassActions/Merge/MassActionsMergeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,96 +85,119 @@ export const MassActionsMergeModal: React.FC<MassActionsMergeModalProps> = ({
handleClose();
};

const contactLimitExceeded = ids.length > 8;

return (
<Modal title={t('Merge Contacts')} isOpen={true} handleClose={handleClose}>
<DialogContent data-testid="MergeModal">
<Alert
severity="warning"
sx={(theme) => ({
marginBottom: theme.spacing(2),
})}
>
{t('This action cannot be undone!')}
</Alert>
<Typography variant="subtitle1">
{t('Are you sure you want to merge the selected contacts?')}
</Typography>
<Typography variant="subtitle1">
{t(
' Data from the "losers" will get copied to the "winner". Select the winner below. No data will be lost by merging.',
)}
</Typography>
{data?.contacts.nodes.map((contact) => (
<Box
my={2}
p={2}
key={contact.id}
onClick={() => setPrimaryContactId(contact.id)}
aria-selected={primaryContactId === contact.id}
{contactLimitExceeded && (
<Alert
severity="warning"
sx={(theme) => ({
display: 'flex',
gap: theme.spacing(2),
cursor: 'pointer',
borderWidth: 3,
borderStyle: 'solid',
borderColor:
primaryContactId === contact.id
? theme.palette.mpdxGreen.main
: theme.palette.cruGrayLight.main,
marginBottom: theme.spacing(2),
})}
data-testid="MassActionsMergeModalContact"
>
<Avatar
src={contact.avatar}
alt={`${contact.name} avatar}`}
style={{
width: theme.spacing(6),
height: theme.spacing(6),
}}
/>
<Box sx={{ flex: 1 }}>
<Typography variant="subtitle1">{contact.name}</Typography>
<Typography variant="subtitle2">
{t('Status')}: {getLocalizedContactStatus(t, contact.status)}
<br />
{contact.primaryAddress && (
<>
{contact.primaryAddress.street}
<br />
{contact.primaryAddress.city},{' '}
{contact.primaryAddress.state}{' '}
{contact.primaryAddress.postalCode}
{t('You can only merge up to 8 contacts at a time.')}
</Alert>
)}
{!contactLimitExceeded && (
<>
<Alert
severity="warning"
sx={(theme) => ({
marginBottom: theme.spacing(2),
})}
>
{t('This action cannot be undone!')}
</Alert>
<Typography variant="subtitle1">
{t('Are you sure you want to merge the selected contacts?')}
</Typography>
<Typography variant="subtitle1">
{t(
' Data from the "losers" will get copied to the "winner". Select the winner below. No data will be lost by merging.',
)}
</Typography>
{data?.contacts.nodes.map((contact) => (
<Box
my={2}
p={2}
key={contact.id}
onClick={() => setPrimaryContactId(contact.id)}
aria-selected={primaryContactId === contact.id}
sx={(theme) => ({
display: 'flex',
gap: theme.spacing(2),
cursor: 'pointer',
borderWidth: 3,
borderStyle: 'solid',
borderColor:
primaryContactId === contact.id
? theme.palette.mpdxGreen.main
: theme.palette.cruGrayLight.main,
})}
data-testid="MassActionsMergeModalContact"
>
<Avatar
src={contact.avatar}
alt={`${contact.name} avatar}`}
style={{
width: theme.spacing(6),
height: theme.spacing(6),
}}
/>
<Box sx={{ flex: 1 }}>
<Typography variant="subtitle1">{contact.name}</Typography>
<Typography variant="subtitle2">
{t('Status')}:{' '}
{getLocalizedContactStatus(t, contact.status)}
<br />
{t('From')}: {contact.primaryAddress.source}
<br />
</>
{contact.primaryAddress && (
<>
{contact.primaryAddress.street}
<br />
{contact.primaryAddress.city},{' '}
{contact.primaryAddress.state}{' '}
{contact.primaryAddress.postalCode}
<br />
{t('From')}: {contact.primaryAddress.source}
<br />
</>
)}
{t('On')}:{' '}
{dateFormatShort(
DateTime.fromISO(contact.createdAt),
locale,
)}
</Typography>
</Box>
{primaryContactId === contact.id && (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography
sx={(theme) => ({
backgroundColor: theme.palette.mpdxGreen.main,
color: 'white',
padding: theme.spacing(0.5),
margin: theme.spacing(-2),
})}
variant="subtitle2"
>
{t('Use This One')}
</Typography>
<Box sx={{ flex: 1 }} />
</Box>
)}
{t('On')}:{' '}
{dateFormatShort(DateTime.fromISO(contact.createdAt), locale)}
</Typography>
</Box>
{primaryContactId === contact.id && (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography
sx={(theme) => ({
backgroundColor: theme.palette.mpdxGreen.main,
color: 'white',
padding: theme.spacing(0.5),
margin: theme.spacing(-2),
})}
variant="subtitle2"
>
{t('Use This One')}
</Typography>
<Box sx={{ flex: 1 }} />
</Box>
)}
</Box>
)) ?? <LoadingIndicator size={20} />}
)) ?? <LoadingIndicator size={20} />}
</>
)}
</DialogContent>
<DialogActions>
<CancelButton onClick={handleClose} disabled={loading || updating} />
<SubmitButton onClick={mergeContacts} disabled={loading || updating}>
<SubmitButton
onClick={mergeContacts}
disabled={loading || updating || contactLimitExceeded}
>
{updating && <CircularProgress color="primary" size={20} />}
{t('Merge')}
</SubmitButton>
Expand Down

0 comments on commit 77129da

Please sign in to comment.