Skip to content

Commit b628571

Browse files
committed
feat(ContactsList): Add makeGroupLabelsAndCounts function
1 parent 234bfe2 commit b628571

File tree

2 files changed

+100
-2
lines changed

2 files changed

+100
-2
lines changed

react/ContactsList/helpers.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import get from 'lodash/get'
2+
13
export function buildLastNameFirst(contact) {
24
const givenName =
35
contact.name && contact.name.givenName
@@ -36,15 +38,39 @@ const makeHeader = (contact, t) => {
3638
return name[0] || t('empty')
3739
}
3840

41+
/**
42+
* Build header for a contact (first letter of indexes.byFamilyNameGivenNameEmailCozyUrl)
43+
* @param {object} contact
44+
* @param {function} t translation function
45+
* @returns {string} header
46+
*/
47+
const makeHeaderForIndexedContacts = (contact, t) => {
48+
if (contact.me) return t('me')
49+
if (contact.cozyMetadata?.favorite) return t('favorite')
50+
51+
const index = get(contact, 'indexes.byFamilyNameGivenNameEmailCozyUrl', '')
52+
const hasIndex = index !== null && index.length > 0
53+
54+
if (hasIndex) {
55+
const firstLetterWithoutAccent = index[0]
56+
.normalize('NFD')
57+
.replace(/\p{Diacritic}/gu, '')
58+
return firstLetterWithoutAccent
59+
}
60+
61+
return t('empty')
62+
}
63+
3964
/**
4065
* @typedef {Object.<string, Object>} CategorizedContactsResult
4166
*/
4267

4368
/**
4469
* Categorize contacts by first letter of last name
70+
* Expl.: all contacts with A as first letter will be in A category
4571
* @param {object[]} contacts io.cozy.contacts documents
4672
* @param {function} t translation function
47-
* @returns {CategorizedContactsResult}
73+
* @returns {CategorizedContactsResult} Categorized contacts
4874
*/
4975
export const categorizeContacts = (contacts, t) =>
5076
contacts.reduce((acc, contact) => {
@@ -81,3 +107,26 @@ export const sortHeaders = (categorized, t) => {
81107

82108
return headersSorted.concat(notEmptyAndMyselfSorted)
83109
}
110+
111+
/**
112+
* Counts how many contacts are categorized by first letter and store it in `groupCounts`
113+
* Expl.: if there is 3 contacts in A and 2 in B, it will return [3,2]
114+
* Also store first letters and store them in `groupLabels`
115+
* @param {array} contacts - Array of io.cozy.contact documents
116+
* @returns {object}
117+
*/
118+
export const makeGroupLabelsAndCounts = (contacts, t) => {
119+
return contacts.reduce(
120+
(acc, contact) => {
121+
const header = makeHeaderForIndexedContacts(contact, t)
122+
if (!acc.groupLabels.includes(header)) {
123+
acc.groupLabels.push(header)
124+
}
125+
const idx = acc.groupLabels.indexOf(header)
126+
const val = acc.groupCounts[idx] || 0
127+
acc.groupCounts[idx] = val + 1
128+
return acc
129+
},
130+
{ groupLabels: [], groupCounts: [] }
131+
)
132+
}

react/ContactsList/helpers.spec.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { sortLastNameFirst, sortHeaders } from './helpers'
1+
import {
2+
sortLastNameFirst,
3+
sortHeaders,
4+
makeGroupLabelsAndCounts
5+
} from './helpers'
6+
7+
const t = x => x
8+
29
describe('Sort contacts', () => {
310
describe('By Last Name', () => {
411
it('should sort contact by last name', () => {
@@ -99,3 +106,45 @@ describe('sortHeaders', () => {
99106
expect(sortedHeaders).toEqual(['me', 'empty', 'B', 'F', 'H'])
100107
})
101108
})
109+
110+
describe('makeGroupLabelsAndCounts', () => {
111+
it('should returns labels and counts', () => {
112+
const contacts = [
113+
{ name: 'Alex', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'A' } },
114+
{ name: 'Alan', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'A' } },
115+
{ name: 'Cleo', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'C' } },
116+
{ name: 'Cloé', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'C' } },
117+
{ name: 'Clotilde', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'C' } },
118+
{ name: 'Constant', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'C' } },
119+
{
120+
name: 'Christophe',
121+
indexes: { byFamilyNameGivenNameEmailCozyUrl: 'C' }
122+
},
123+
{ name: 'Bernard', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'B' } },
124+
{ name: 'Baptiste', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'B' } },
125+
{ name: 'Xavier', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'X' } },
126+
{ name: 'Zorro', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'Z' } },
127+
{ name: '', indexes: { byFamilyNameGivenNameEmailCozyUrl: '' } },
128+
{ name: {}, indexes: { byFamilyNameGivenNameEmailCozyUrl: {} } },
129+
{ name: 'John', indexes: { byFamilyNameGivenNameEmailCozyUrl: null } },
130+
{
131+
name: 'Connor',
132+
indexes: { byFamilyNameGivenNameEmailCozyUrl: undefined }
133+
},
134+
{ name: 'Àlbert', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'À' } },
135+
{
136+
name: 'Alice',
137+
me: true,
138+
indexes: { byFamilyNameGivenNameEmailCozyUrl: 'Alice' }
139+
},
140+
{ name: 'Èllen', indexes: { byFamilyNameGivenNameEmailCozyUrl: 'È' } }
141+
]
142+
143+
const res = makeGroupLabelsAndCounts(contacts, t)
144+
145+
expect(res).toStrictEqual({
146+
groupLabels: ['A', 'C', 'B', 'X', 'Z', 'empty', 'me', 'E'],
147+
groupCounts: [3, 5, 2, 1, 1, 4, 1, 1]
148+
})
149+
})
150+
})

0 commit comments

Comments
 (0)