cozy-sharing 12.3.0 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.storybook/preview.jsx +1 -0
  2. package/CHANGELOG.md +29 -0
  3. package/dist/components/ContactSuggestion.js +7 -3
  4. package/dist/components/ContactSuggestion.spec.js +7 -1
  5. package/dist/components/Recipient/GroupRecipient.js +14 -7
  6. package/dist/components/Recipient/GroupRecipientDetail.js +4 -2
  7. package/dist/components/Recipient/GroupRecipientDetailWithAccess.js +9 -11
  8. package/dist/components/Recipient/GroupRecipientDetailWithoutAccess.js +8 -4
  9. package/dist/components/Recipient/GroupRecipientPermissions.js +3 -6
  10. package/dist/components/Recipient/MemberRecipient.js +1 -2
  11. package/dist/components/Recipient/MemberRecipientPermissions.js +1 -1
  12. package/dist/components/ShareAutosuggest.js +16 -9
  13. package/dist/components/ShareAutosuggest.spec.js +38 -13
  14. package/dist/components/ShareAutosuggest.stories.js +61 -0
  15. package/dist/components/ShareByEmail.js +15 -15
  16. package/dist/components/ShareByEmail.spec.js +0 -6
  17. package/dist/components/ShareDialogCozyToCozy.js +1 -5
  18. package/dist/components/ShareDialogCozyToCozy.spec.js +0 -61
  19. package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +1 -5
  20. package/dist/components/ShareDialogTwoStepsConfirmationContainer.spec.js +0 -61
  21. package/dist/components/ShareModal/EditableSharingModal.js +3 -10
  22. package/dist/components/ShareModal/EditableSharingModal.spec.js +0 -6
  23. package/dist/components/ShareModal.js +1 -8
  24. package/dist/components/ShareRecipientsInput.js +46 -49
  25. package/dist/components/ShareRecipientsInput.spec.js +120 -144
  26. package/dist/helpers/contacts.js +12 -1
  27. package/dist/helpers/recipients.js +16 -9
  28. package/dist/helpers/successMessage.js +58 -16
  29. package/dist/helpers/successMessage.spec.js +122 -57
  30. package/dist/queries/queries.js +37 -5
  31. package/dist/styles/autosuggest.styl +2 -1
  32. package/dist/stylesheet.css +2 -1
  33. package/locales/en.json +23 -10
  34. package/locales/fr.json +23 -8
  35. package/package.json +4 -4
  36. package/src/components/ContactSuggestion.jsx +9 -3
  37. package/src/components/ContactSuggestion.spec.jsx +10 -1
  38. package/src/components/Recipient/GroupRecipient.jsx +17 -10
  39. package/src/components/Recipient/GroupRecipientDetail.jsx +5 -2
  40. package/src/components/Recipient/GroupRecipientDetailWithAccess.jsx +9 -14
  41. package/src/components/Recipient/GroupRecipientDetailWithoutAccess.jsx +8 -3
  42. package/src/components/Recipient/GroupRecipientPermissions.jsx +3 -8
  43. package/src/components/Recipient/MemberRecipient.jsx +4 -3
  44. package/src/components/Recipient/MemberRecipientPermissions.jsx +1 -1
  45. package/src/components/ShareAutosuggest.jsx +16 -11
  46. package/src/components/ShareAutosuggest.spec.jsx +31 -10
  47. package/src/components/ShareAutosuggest.stories.jsx +63 -0
  48. package/src/components/ShareByEmail.jsx +11 -11
  49. package/src/components/ShareByEmail.spec.jsx +0 -4
  50. package/src/components/ShareDialogCozyToCozy.jsx +0 -4
  51. package/src/components/ShareDialogCozyToCozy.spec.jsx +0 -67
  52. package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +0 -4
  53. package/src/components/ShareDialogTwoStepsConfirmationContainer.spec.jsx +0 -67
  54. package/src/components/ShareModal/EditableSharingModal.jsx +3 -21
  55. package/src/components/ShareModal/EditableSharingModal.spec.jsx +0 -2
  56. package/src/components/ShareModal.jsx +1 -7
  57. package/src/components/ShareRecipientsInput.jsx +84 -52
  58. package/src/components/ShareRecipientsInput.spec.jsx +140 -145
  59. package/src/helpers/contacts.js +8 -0
  60. package/src/helpers/recipients.js +24 -15
  61. package/src/helpers/successMessage.js +71 -21
  62. package/src/helpers/successMessage.spec.js +129 -69
  63. package/src/queries/queries.js +36 -5
  64. package/src/styles/autosuggest.styl +2 -1
  65. package/test/AppLike.jsx +6 -3
@@ -284,57 +284,6 @@ const deferablePromise = () => {
284
284
 
285
285
  const getMockProps = () => {
286
286
  return {
287
- contacts: {
288
- id: 'contacts',
289
- definition: {
290
- doctype: 'io.cozy.contacts',
291
- selector: {
292
- _id: {
293
- $gt: null
294
- }
295
- },
296
- indexedFields: ['_id'],
297
- partialFilter: {
298
- trashed: {
299
- $or: [
300
- {
301
- $eq: false
302
- },
303
- {
304
- $exists: false
305
- }
306
- ]
307
- },
308
- $or: [
309
- {
310
- cozy: {
311
- $not: {
312
- $size: 0
313
- }
314
- }
315
- },
316
- {
317
- email: {
318
- $not: {
319
- $size: 0
320
- }
321
- }
322
- }
323
- ]
324
- },
325
- limit: 1000
326
- },
327
- fetchStatus: 'pending',
328
- lastFetch: null,
329
- lastUpdate: null,
330
- lastErrorUpdate: null,
331
- lastError: null,
332
- hasMore: false,
333
- count: 0,
334
- data: [],
335
- bookmark: null,
336
- options: null
337
- },
338
287
  document: {
339
288
  id: 'SOME_DOCUMENT_ID',
340
289
  name: 'SOME_DOCUMENT_NAME',
@@ -342,22 +291,6 @@ const getMockProps = () => {
342
291
  _id: 'SOME_DOCUMENT_ID'
343
292
  },
344
293
  documentType: 'Organizations',
345
- contactGroups: {
346
- id: 'groups',
347
- definition: {
348
- doctype: 'io.cozy.contacts.groups'
349
- },
350
- fetchStatus: 'pending',
351
- lastFetch: null,
352
- lastUpdate: null,
353
- lastErrorUpdate: null,
354
- lastError: null,
355
- hasMore: false,
356
- count: 0,
357
- data: [],
358
- bookmark: null,
359
- options: null
360
- },
361
294
  hasSharedParent: null,
362
295
  isOwner: true,
363
296
  link: null,
@@ -1,33 +1,17 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import React from 'react'
3
3
 
4
- import { useClient, useQueryAll } from 'cozy-client'
4
+ import { useClient } from 'cozy-client'
5
5
 
6
6
  import { useFetchDocumentPath } from '../../hooks/useFetchDocumentPath'
7
7
  import { useSharingContext } from '../../hooks/useSharingContext'
8
8
  import { Contact } from '../../models'
9
- import {
10
- buildContactsQuery,
11
- buildContactGroupsQuery
12
- } from '../../queries/queries'
13
- import { default as DumbShareModal } from '../ShareModal'
9
+ import { ShareModal } from '../ShareModal'
14
10
 
15
11
  export const EditableSharingModal = ({ document, ...rest }) => {
16
12
  const client = useClient()
17
13
  const documentPath = useFetchDocumentPath(client, document)
18
14
 
19
- const contactsQuery = buildContactsQuery()
20
- const contactsResult = useQueryAll(
21
- contactsQuery.definition,
22
- contactsQuery.options
23
- )
24
-
25
- const contactGroupsQuery = buildContactGroupsQuery()
26
- const contactGroupsResult = useQueryAll(
27
- contactGroupsQuery.definition,
28
- contactGroupsQuery.options
29
- )
30
-
31
15
  const {
32
16
  documentType,
33
17
  getDocumentPermissions,
@@ -46,9 +30,7 @@ export const EditableSharingModal = ({ document, ...rest }) => {
46
30
  } = useSharingContext()
47
31
 
48
32
  return (
49
- <DumbShareModal
50
- contacts={contactsResult}
51
- contactGroups={contactGroupsResult}
33
+ <ShareModal
52
34
  createContact={contact => client.create(Contact.doctype, contact)}
53
35
  document={document}
54
36
  documentType={documentType}
@@ -32,8 +32,6 @@ describe('EditableSharingModal', () => {
32
32
  <AppWrapper client={client}>
33
33
  <EditableSharingModal
34
34
  client={client}
35
- contacts={{ data: [] }}
36
- contactGroups={{ data: [] }}
37
35
  document={document}
38
36
  t={x => x}
39
37
  onClose={() => {}}
@@ -5,10 +5,8 @@ import flag from 'cozy-flags'
5
5
 
6
6
  import ShareDialogCozyToCozy from './ShareDialogCozyToCozy'
7
7
  import ShareDialogOnlyByLink from './ShareDialogOnlyByLink'
8
- import { contactsResponseType, contactGroupsResponseType } from '../propTypes'
8
+
9
9
  export const ShareModal = ({
10
- contacts,
11
- contactGroups,
12
10
  createContact,
13
11
  document,
14
12
  documentType = 'Document',
@@ -56,8 +54,6 @@ export const ShareModal = ({
56
54
  />
57
55
  ) : (
58
56
  <ShareDialogCozyToCozy
59
- contacts={contacts}
60
- contactGroups={contactGroups}
61
57
  createContact={createContact}
62
58
  document={document}
63
59
  documentType={documentType}
@@ -88,8 +84,6 @@ export const ShareModal = ({
88
84
  export default ShareModal
89
85
 
90
86
  ShareModal.propTypes = {
91
- contacts: contactsResponseType.isRequired,
92
- contactGroups: contactGroupsResponseType.isRequired,
93
87
  createContact: PropTypes.func.isRequired,
94
88
  document: PropTypes.object.isRequired,
95
89
  documentType: PropTypes.string,
@@ -1,75 +1,109 @@
1
- import get from 'lodash/get'
2
1
  import PropTypes from 'prop-types'
3
- import React, { useState, useEffect } from 'react'
2
+ import React from 'react'
3
+
4
+ import { useQueryAll, isQueryLoading } from 'cozy-client'
5
+ import flag from 'cozy-flags'
4
6
 
5
7
  import ShareAutosuggest from './ShareAutosuggest'
6
- import { contactsResponseType, contactGroupsResponseType } from '../propTypes'
8
+ import { getContactsFromGroupId } from '../helpers/contacts'
9
+ import {
10
+ buildReachableContactsQuery,
11
+ buildContactGroupsByIdsQuery,
12
+ buildUnreachableContactsWithGroupsQuery
13
+ } from '../queries/queries'
7
14
 
15
+ /**
16
+ * ShareRecipientsInput is responsible for fetching contacts and groups.
17
+ * We retrieve all the contacts that are reachable and the groups they belong to.
18
+ * In order to display the total number of members in each group, we also retrieve the contacts that are not reachable.
19
+ */
8
20
  const ShareRecipientsInput = ({
9
- contacts,
10
- contactGroups,
11
21
  recipients,
12
22
  placeholder,
13
23
  onPick,
14
24
  onRemove
15
25
  }) => {
16
- const [loading, setLoading] = useState(false)
26
+ const reachableContactsQuery = buildReachableContactsQuery()
27
+ const reachableContactsResult = useQueryAll(
28
+ reachableContactsQuery.definition,
29
+ reachableContactsQuery.options
30
+ )
17
31
 
18
- useEffect(() => {
19
- if (
20
- loading &&
21
- !contacts.hasMore &&
22
- contacts.fetchStatus === 'loaded' &&
23
- !contactGroups.hasMore &&
24
- contactGroups.fetchStatus === 'loaded'
25
- ) {
26
- setLoading(false)
32
+ const unreachableContactsWithGroupsQuery =
33
+ buildUnreachableContactsWithGroupsQuery()
34
+ const unreachableContactsWithGroupsResult = useQueryAll(
35
+ unreachableContactsWithGroupsQuery.definition,
36
+ {
37
+ ...unreachableContactsWithGroupsQuery.options,
38
+ enabled: !!flag('sharing.show-recipient-groups')
27
39
  }
28
- }, [contacts, contactGroups, loading])
40
+ )
29
41
 
30
- const onShareAutosuggestFocus = () => {
31
- if (
32
- contacts.hasMore ||
33
- contacts.fetchStatus === 'loading' ||
34
- contactGroups.hasMore ||
35
- contactGroups.fetchStatus === 'loading'
36
- ) {
37
- setLoading(true)
38
- }
39
- }
42
+ const contactGroupsByIdsQuery = buildContactGroupsByIdsQuery([
43
+ ...new Set(
44
+ (reachableContactsResult.data || []).flatMap(contact => {
45
+ return (contact.relationships?.groups?.data || []).map(
46
+ group => group._id
47
+ )
48
+ })
49
+ )
50
+ ])
51
+ const contactGroupsByIdsResult = useQueryAll(
52
+ contactGroupsByIdsQuery.definition,
53
+ contactGroupsByIdsQuery.options
54
+ )
40
55
 
41
- const getContactsAndGroups = () => {
42
- // we need contacts to be loaded to be able to add all group members to recipients
43
- if (contacts.hasMore || contacts.fetchStatus === 'loading') {
44
- return contacts.data
45
- } else {
46
- const contactGroupsWithCount = contactGroups.data
47
- .map(contactGroup => ({
56
+ const isLoading =
57
+ isQueryLoading(reachableContactsResult) ||
58
+ reachableContactsResult.hasMore ||
59
+ isQueryLoading(contactGroupsByIdsResult) ||
60
+ contactGroupsByIdsResult.hasMore ||
61
+ (flag('sharing.show-recipient-groups') &&
62
+ (isQueryLoading(unreachableContactsWithGroupsResult) ||
63
+ unreachableContactsWithGroupsResult.hasMore))
64
+
65
+ const contactGroups = (contactGroupsByIdsResult.data || []).map(
66
+ contactGroup => {
67
+ const reachableMembers = getContactsFromGroupId(
68
+ reachableContactsResult.data,
69
+ contactGroup.id
70
+ ).map(contact => ({
71
+ ...contact,
72
+ isReachable: true
73
+ }))
74
+
75
+ if (flag('sharing.show-recipient-groups') !== true) {
76
+ return {
48
77
  ...contactGroup,
49
- membersCount: contacts.data.reduce((total, contact) => {
50
- if (
51
- get(contact, 'relationships.groups.data', [])
52
- .map(group => group._id)
53
- .includes(contactGroup._id)
54
- ) {
55
- return total + 1
56
- }
78
+ members: reachableMembers
79
+ }
80
+ }
57
81
 
58
- return total
59
- }, 0)
60
- }))
61
- .filter(contactGroup => contactGroup.membersCount > 0)
82
+ const unreachableMembers = getContactsFromGroupId(
83
+ unreachableContactsWithGroupsResult.data,
84
+ contactGroup.id
85
+ ).map(contact => ({
86
+ ...contact,
87
+ isReachable: false
88
+ }))
62
89
 
63
- return [...contacts.data, ...contactGroupsWithCount]
90
+ return {
91
+ ...contactGroup,
92
+ members: [...reachableMembers, ...unreachableMembers]
93
+ }
64
94
  }
65
- }
95
+ )
96
+
97
+ const contactsAndGroups = [
98
+ ...(reachableContactsResult.data || []),
99
+ ...contactGroups
100
+ ]
66
101
 
67
102
  return (
68
103
  <ShareAutosuggest
69
- loading={loading}
70
- contactsAndGroups={getContactsAndGroups()}
104
+ loading={isLoading}
105
+ contactsAndGroups={contactsAndGroups}
71
106
  recipients={recipients}
72
- onFocus={onShareAutosuggestFocus}
73
107
  onPick={onPick}
74
108
  onRemove={onRemove}
75
109
  placeholder={placeholder}
@@ -78,8 +112,6 @@ const ShareRecipientsInput = ({
78
112
  }
79
113
 
80
114
  ShareRecipientsInput.propTypes = {
81
- contacts: contactsResponseType.isRequired,
82
- contactGroups: contactGroupsResponseType.isRequired,
83
115
  recipients: PropTypes.array,
84
116
  placeholder: PropTypes.string,
85
117
  onPick: PropTypes.func.isRequired,
@@ -1,7 +1,16 @@
1
1
  import { render, screen } from '@testing-library/react'
2
2
  import React from 'react'
3
3
 
4
+ import { createMockClient } from 'cozy-client'
5
+ import flag from 'cozy-flags'
6
+
4
7
  import ShareRecipientsInput from './ShareRecipientsInput'
8
+ import AppLike from './SharingBanner/test/AppLike'
9
+
10
+ jest.mock('cozy-flags', () => ({
11
+ __esModule: true,
12
+ default: jest.fn()
13
+ }))
5
14
 
6
15
  jest.mock('./ShareAutosuggest', () => ({
7
16
  __esModule: true,
@@ -16,7 +25,11 @@ jest.mock('./ShareAutosuggest', () => ({
16
25
  </li>
17
26
  )
18
27
  } else {
19
- return <li key={contactOrGroup.id}>{contactOrGroup.name}</li>
28
+ return (
29
+ <li key={contactOrGroup.id}>
30
+ {contactOrGroup.name} - {contactOrGroup.members.length} members
31
+ </li>
32
+ )
20
33
  }
21
34
  })}
22
35
  </ul>
@@ -25,176 +38,158 @@ jest.mock('./ShareAutosuggest', () => ({
25
38
  }))
26
39
 
27
40
  describe('ShareRecipientsInput component', () => {
28
- const setup = ({ contacts, contactGroups }) => {
41
+ const setup = ({ contacts, contactGroups, unreachableContact }) => {
42
+ const mockClient = createMockClient({
43
+ queries: {
44
+ 'io.cozy.contacts/reachable': {
45
+ doctype: 'io.cozy.contacts',
46
+ data: contacts
47
+ },
48
+ 'io.cozy.contacts.groups/by-ids/fe86af20-c6c5': {
49
+ doctype: 'io.cozy.contacts.groups',
50
+ data: contactGroups
51
+ },
52
+ 'io.cozy.contacts/unreachable-with-groups': {
53
+ doctype: 'io.cozy.contacts',
54
+ data: unreachableContact
55
+ }
56
+ }
57
+ })
29
58
  render(
30
- <ShareRecipientsInput
31
- contacts={contacts}
32
- contactGroups={contactGroups}
33
- onPick={() => {}}
34
- onRemove={() => {}}
35
- placeholder="Enter recipients here"
36
- />
59
+ <AppLike client={mockClient}>
60
+ <ShareRecipientsInput
61
+ onPick={() => {}}
62
+ onRemove={() => {}}
63
+ placeholder="Enter recipients here"
64
+ />
65
+ </AppLike>
37
66
  )
38
67
  }
39
68
 
40
69
  it('should include groups and contacts when are loaded', async () => {
41
- const contacts = {
42
- id: 'contacts',
43
- fetchStatus: 'loaded',
44
- hasMore: false,
45
- data: [
46
- {
47
- id: 'df563cc4-6440',
48
- _id: 'df563cc4-6440',
49
- _type: 'io.cozy.contacts',
50
- name: {
51
- givenName: 'Michale',
52
- familyName: 'Russel'
53
- }
70
+ const contacts = [
71
+ {
72
+ id: 'df563cc4-6440',
73
+ _id: 'df563cc4-6440',
74
+ _type: 'io.cozy.contacts',
75
+ name: {
76
+ givenName: 'Michale',
77
+ familyName: 'Russel'
78
+ }
79
+ },
80
+ {
81
+ id: '5a3b4ccf-c257',
82
+ _id: '5a3b4ccf-c257',
83
+ _type: 'io.cozy.contacts',
84
+ name: {
85
+ givenName: 'Teagan',
86
+ familyName: 'Wolf'
54
87
  },
55
- {
56
- id: '5a3b4ccf-c257',
57
- _id: '5a3b4ccf-c257',
58
- _type: 'io.cozy.contacts',
59
- name: {
60
- givenName: 'Teagan',
61
- familyName: 'Wolf'
62
- },
63
- relationships: {
64
- groups: {
65
- data: [
66
- {
67
- _id: 'fe86af20-c6c5',
68
- _type: 'io.cozy.contacts.groups'
69
- }
70
- ]
71
- }
88
+ relationships: {
89
+ groups: {
90
+ data: [
91
+ {
92
+ _id: 'fe86af20-c6c5',
93
+ _type: 'io.cozy.contacts.groups'
94
+ }
95
+ ]
72
96
  }
73
97
  }
74
- ]
75
- }
76
- const contactGroups = {
77
- id: 'groups',
78
- fetchStatus: 'loaded',
79
- hasMore: false,
80
- data: [
81
- {
82
- id: 'fe86af20-c6c5',
83
- name: "The Night's Watch",
84
- _id: 'fe86af20-c6c5',
85
- _type: 'io.cozy.contacts.groups'
86
- }
87
- ]
88
- }
98
+ }
99
+ ]
100
+
101
+ const contactGroups = [
102
+ {
103
+ id: 'fe86af20-c6c5',
104
+ name: "The Night's Watch",
105
+ _id: 'fe86af20-c6c5',
106
+ _type: 'io.cozy.contacts.groups'
107
+ }
108
+ ]
89
109
 
90
110
  setup({ contacts, contactGroups })
91
111
 
92
112
  expect(screen.getByText('Michale Russel')).toBeInTheDocument()
93
113
  expect(screen.getByText('Teagan Wolf')).toBeInTheDocument()
94
- expect(screen.getByText("The Night's Watch")).toBeInTheDocument()
114
+ expect(
115
+ screen.getByText("The Night's Watch - 1 members")
116
+ ).toBeInTheDocument()
95
117
  })
96
118
 
97
- it('should include groups only if all contacts are loaded', async () => {
98
- const contacts = {
99
- id: 'contacts',
100
- fetchStatus: 'loading',
101
- hasMore: false,
102
- data: [
103
- {
104
- id: 'df563cc4-6440',
105
- _id: 'df563cc4-6440',
106
- _type: 'io.cozy.contacts',
107
- name: {
108
- givenName: 'Michale',
109
- familyName: 'Russel'
110
- }
119
+ it('should include unreachable members when flag sharing.show-recipient-groups is activated', async () => {
120
+ flag.mockReturnValue(true)
121
+
122
+ const contacts = [
123
+ {
124
+ id: 'df563cc4-6440',
125
+ _id: 'df563cc4-6440',
126
+ _type: 'io.cozy.contacts',
127
+ name: {
128
+ givenName: 'Michale',
129
+ familyName: 'Russel'
130
+ }
131
+ },
132
+ {
133
+ id: '5a3b4ccf-c257',
134
+ _id: '5a3b4ccf-c257',
135
+ _type: 'io.cozy.contacts',
136
+ name: {
137
+ givenName: 'Teagan',
138
+ familyName: 'Wolf'
111
139
  },
112
- {
113
- id: '5a3b4ccf-c257',
114
- _id: '5a3b4ccf-c257',
115
- _type: 'io.cozy.contacts',
116
- name: {
117
- givenName: 'Teagan',
118
- familyName: 'Wolf'
119
- },
120
- relationships: {
121
- groups: {
122
- data: [
123
- {
124
- _id: 'fe86af20-c6c5',
125
- _type: 'io.cozy.contacts.groups'
126
- }
127
- ]
128
- }
140
+ relationships: {
141
+ groups: {
142
+ data: [
143
+ {
144
+ _id: 'fe86af20-c6c5',
145
+ _type: 'io.cozy.contacts.groups'
146
+ }
147
+ ]
129
148
  }
130
149
  }
131
- ]
132
- }
133
- const contactGroups = {
134
- id: 'groups',
135
- fetchStatus: 'loaded',
136
- hasMore: false,
137
- data: [
138
- {
139
- id: 'fe86af20-c6c5',
140
- name: "The Night's Watch",
141
- _id: 'fe86af20-c6c5',
142
- _type: 'io.cozy.contacts.groups'
143
- }
144
- ]
145
- }
150
+ }
151
+ ]
146
152
 
147
- setup({ contacts, contactGroups })
153
+ const contactGroups = [
154
+ {
155
+ id: 'fe86af20-c6c5',
156
+ name: "The Night's Watch",
157
+ _id: 'fe86af20-c6c5',
158
+ _type: 'io.cozy.contacts.groups'
159
+ }
160
+ ]
148
161
 
149
- expect(screen.getByText('Michale Russel')).toBeInTheDocument()
150
- expect(screen.getByText('Teagan Wolf')).toBeInTheDocument()
151
- expect(screen.queryByText("The Night's Watch")).toBeNull()
152
- })
153
-
154
- it('should include groups only if they have more than one member', async () => {
155
- const contacts = {
156
- id: 'contacts',
157
- fetchStatus: 'loaded',
158
- hasMore: false,
159
- data: [
160
- {
161
- id: 'df563cc4-6440',
162
- _id: 'df563cc4-6440',
163
- _type: 'io.cozy.contacts',
164
- name: {
165
- givenName: 'Michale',
166
- familyName: 'Russel'
167
- }
162
+ const unreachableContact = [
163
+ {
164
+ id: 'df532cc4-6560',
165
+ _id: 'df532cc4-6560',
166
+ _type: 'io.cozy.contacts',
167
+ name: {
168
+ givenName: 'Tony',
169
+ familyName: 'Stark'
168
170
  },
169
- {
170
- id: '5a3b4ccf-c257',
171
- _id: '5a3b4ccf-c257',
172
- _type: 'io.cozy.contacts',
173
- name: {
174
- givenName: 'Teagan',
175
- familyName: 'Wolf'
171
+ relationships: {
172
+ groups: {
173
+ data: [
174
+ {
175
+ _id: 'fe86af20-c6c5',
176
+ _type: 'io.cozy.contacts.groups'
177
+ }
178
+ ]
176
179
  }
177
180
  }
178
- ]
179
- }
180
- const contactGroups = {
181
- id: 'groups',
182
- fetchStatus: 'loaded',
183
- hasMore: false,
184
- data: [
185
- {
186
- id: 'fe86af20-c6c5',
187
- name: "The Night's Watch",
188
- _id: 'fe86af20-c6c5',
189
- _type: 'io.cozy.contacts.groups'
190
- }
191
- ]
192
- }
181
+ }
182
+ ]
193
183
 
194
- setup({ contacts, contactGroups })
184
+ setup({ contacts, contactGroups, unreachableContact })
195
185
 
196
186
  expect(screen.getByText('Michale Russel')).toBeInTheDocument()
197
187
  expect(screen.getByText('Teagan Wolf')).toBeInTheDocument()
198
- expect(screen.queryByText("The Night's Watch")).toBeNull()
188
+ // 3 members because cozy-client replay the query with the new data
189
+ // so the unreachableContact is added to the reachable contact query
190
+ // TODO: improve createMockClient to handle this case
191
+ expect(
192
+ screen.getByText("The Night's Watch - 3 members")
193
+ ).toBeInTheDocument()
199
194
  })
200
195
  })
@@ -39,3 +39,11 @@ export const getOrCreateFromArray = async (client, contacts, createContact) => {
39
39
  })
40
40
  )
41
41
  }
42
+
43
+ export const getContactsFromGroupId = (contacts = [], groupId) => {
44
+ return contacts.filter(contact => {
45
+ return contact.relationships?.groups?.data?.some(
46
+ group => group._id === groupId
47
+ )
48
+ })
49
+ }