Skip to content

Commit

Permalink
Sort contacts alphabetically (#11982)
Browse files Browse the repository at this point in the history
* Sort contacts alphabetically

Contacts are grouped together by letter, and the groups are listed
alphabetically, but the contacts in each group are not sorted
alphabetically themselves.

Fixes #10318.

* Improve tests to be less brittle

* Remove this matcher

* Revert this file

* Also don't need this change anymore

* Don't need this data attribute either
  • Loading branch information
mcmire authored Sep 3, 2021
1 parent fe59cbf commit 49e1abc
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 28 deletions.
55 changes: 29 additions & 26 deletions ui/components/app/contact-list/contact-list.component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { sortBy } from 'lodash';
import Button from '../../ui/button';
import RecipientGroup from './recipient-group/recipient-group.component';

Expand Down Expand Up @@ -50,34 +51,36 @@ export default class ContactList extends PureComponent {
}

renderAddressBook() {
const contacts = this.props.searchForContacts();
const unsortedContactsByLetter = this.props
.searchForContacts()
.reduce((obj, contact) => {
const firstLetter = contact.name[0].toUpperCase();
return {
...obj,
[firstLetter]: [...(obj[firstLetter] || []), contact],
};
}, {});

const contactGroups = contacts.reduce((acc, contact) => {
const firstLetter = contact.name.slice(0, 1).toUpperCase();
acc[firstLetter] = acc[firstLetter] || [];
const bucket = acc[firstLetter];
bucket.push(contact);
return acc;
}, {});
const letters = Object.keys(unsortedContactsByLetter).sort();

return Object.entries(contactGroups)
.sort(([letter1], [letter2]) => {
if (letter1 > letter2) {
return 1;
} else if (letter1 === letter2) {
return 0;
}
return -1;
})
.map(([letter, groupItems]) => (
<RecipientGroup
key={`${letter}-contract-group`}
label={letter}
items={groupItems}
onSelect={this.props.selectRecipient}
selectedAddress={this.props.selectedAddress}
/>
));
const sortedContactGroups = letters.map((letter) => {
return [
letter,
sortBy(unsortedContactsByLetter[letter], (contact) => {
return contact.name.toLowerCase();
}),
];
});

return sortedContactGroups.map(([letter, groupItems]) => (
<RecipientGroup
key={`${letter}-contact-group`}
label={letter}
items={groupItems}
onSelect={this.props.selectRecipient}
selectedAddress={this.props.selectedAddress}
/>
));
}

renderMyAccounts() {
Expand Down
58 changes: 58 additions & 0 deletions ui/components/app/contact-list/contact-list.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import { within } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../test/jest/rendering';
import ContactList from '.';

describe('Contact List', () => {
const store = configureMockStore([])({ metamask: {} });

describe('given searchForContacts', () => {
const selectRecipient = () => null;
const selectedAddress = null;

it('sorts contacts by name within each letter group', () => {
const { getAllByTestId } = renderWithProvider(
<ContactList
searchForContacts={() => {
return [
{
name: 'Al',
address: '0x0000000000000000000000000000000000000000',
},
{
name: 'aa',
address: '0x0000000000000000000000000000000000000001',
},
{
name: 'Az',
address: '0x0000000000000000000000000000000000000002',
},
{
name: 'bbb',
address: '0x0000000000000000000000000000000000000003',
},
];
}}
selectRecipient={selectRecipient}
selectedAddress={selectedAddress}
/>,
store,
);

const recipientGroups = getAllByTestId('recipient-group');
expect(within(recipientGroups[0]).getByText('A')).toBeInTheDocument();
const recipientsInA = within(recipientGroups[0]).getAllByTestId(
'recipient',
);
expect(recipientsInA[0]).toHaveTextContent('aa0x0000...0001');
expect(recipientsInA[1]).toHaveTextContent('Al0x0000...0000');
expect(recipientsInA[2]).toHaveTextContent('Az0x0000...0002');
expect(within(recipientGroups[1]).getByText('B')).toBeInTheDocument();
const recipientsInB = within(recipientGroups[1]).getAllByTestId(
'recipient',
);
expect(recipientsInB[0]).toHaveTextContent('bbb0x0000...0003');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export default function RecipientGroup({
}

return (
<div className="send__select-recipient-wrapper__group">
<div
className="send__select-recipient-wrapper__group"
data-testid="recipient-group"
>
{label && (
<div className="send__select-recipient-wrapper__group-label">
{label}
Expand All @@ -41,7 +44,10 @@ export default function RecipientGroup({
})}
>
<Identicon address={address} diameter={28} />
<div className="send__select-recipient-wrapper__group-item__content">
<div
className="send__select-recipient-wrapper__group-item__content"
data-testid="recipient"
>
<div className="send__select-recipient-wrapper__group-item__title">
{name || ellipsify(address)}
</div>
Expand Down

0 comments on commit 49e1abc

Please sign in to comment.