cozy-sharing 12.2.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 (73) hide show
  1. package/.storybook/preview.jsx +1 -0
  2. package/CHANGELOG.md +40 -0
  3. package/dist/components/Avatar/AvatarList.js +13 -2
  4. package/dist/components/Avatar/AvatarList.spec.js +11 -6
  5. package/dist/components/Avatar/AvatarList.stories.js +13 -1
  6. package/dist/components/Avatar/GroupAvatar.js +4 -2
  7. package/dist/components/ContactSuggestion.js +7 -3
  8. package/dist/components/ContactSuggestion.spec.js +7 -1
  9. package/dist/components/Recipient/GroupRecipient.js +14 -7
  10. package/dist/components/Recipient/GroupRecipientDetail.js +4 -2
  11. package/dist/components/Recipient/GroupRecipientDetailWithAccess.js +9 -11
  12. package/dist/components/Recipient/GroupRecipientDetailWithoutAccess.js +8 -4
  13. package/dist/components/Recipient/GroupRecipientPermissions.js +3 -6
  14. package/dist/components/Recipient/MemberRecipient.js +1 -2
  15. package/dist/components/Recipient/MemberRecipientPermissions.js +1 -1
  16. package/dist/components/ShareAutosuggest.js +16 -9
  17. package/dist/components/ShareAutosuggest.spec.js +38 -13
  18. package/dist/components/ShareAutosuggest.stories.js +61 -0
  19. package/dist/components/ShareByEmail.js +15 -15
  20. package/dist/components/ShareByEmail.spec.js +0 -6
  21. package/dist/components/ShareDialogCozyToCozy.js +1 -5
  22. package/dist/components/ShareDialogCozyToCozy.spec.js +0 -61
  23. package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +1 -5
  24. package/dist/components/ShareDialogTwoStepsConfirmationContainer.spec.js +0 -61
  25. package/dist/components/ShareModal/EditableSharingModal.js +3 -10
  26. package/dist/components/ShareModal/EditableSharingModal.spec.js +0 -6
  27. package/dist/components/ShareModal.js +1 -8
  28. package/dist/components/ShareRecipientsInput.js +46 -49
  29. package/dist/components/ShareRecipientsInput.spec.js +120 -144
  30. package/dist/helpers/contacts.js +12 -1
  31. package/dist/helpers/recipients.js +16 -9
  32. package/dist/helpers/successMessage.js +58 -16
  33. package/dist/helpers/successMessage.spec.js +122 -57
  34. package/dist/queries/queries.js +37 -5
  35. package/dist/styles/autosuggest.styl +2 -1
  36. package/dist/stylesheet.css +2 -1
  37. package/locales/en.json +23 -10
  38. package/locales/fr.json +23 -8
  39. package/package.json +4 -4
  40. package/src/components/Avatar/AvatarList.jsx +33 -14
  41. package/src/components/Avatar/AvatarList.spec.jsx +11 -6
  42. package/src/components/Avatar/AvatarList.stories.jsx +19 -1
  43. package/src/components/Avatar/GroupAvatar.jsx +2 -2
  44. package/src/components/ContactSuggestion.jsx +9 -3
  45. package/src/components/ContactSuggestion.spec.jsx +10 -1
  46. package/src/components/Recipient/GroupRecipient.jsx +17 -10
  47. package/src/components/Recipient/GroupRecipientDetail.jsx +5 -2
  48. package/src/components/Recipient/GroupRecipientDetailWithAccess.jsx +9 -14
  49. package/src/components/Recipient/GroupRecipientDetailWithoutAccess.jsx +8 -3
  50. package/src/components/Recipient/GroupRecipientPermissions.jsx +3 -8
  51. package/src/components/Recipient/MemberRecipient.jsx +4 -3
  52. package/src/components/Recipient/MemberRecipientPermissions.jsx +1 -1
  53. package/src/components/ShareAutosuggest.jsx +16 -11
  54. package/src/components/ShareAutosuggest.spec.jsx +31 -10
  55. package/src/components/ShareAutosuggest.stories.jsx +63 -0
  56. package/src/components/ShareByEmail.jsx +11 -11
  57. package/src/components/ShareByEmail.spec.jsx +0 -4
  58. package/src/components/ShareDialogCozyToCozy.jsx +0 -4
  59. package/src/components/ShareDialogCozyToCozy.spec.jsx +0 -67
  60. package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +0 -4
  61. package/src/components/ShareDialogTwoStepsConfirmationContainer.spec.jsx +0 -67
  62. package/src/components/ShareModal/EditableSharingModal.jsx +3 -21
  63. package/src/components/ShareModal/EditableSharingModal.spec.jsx +0 -2
  64. package/src/components/ShareModal.jsx +1 -7
  65. package/src/components/ShareRecipientsInput.jsx +84 -52
  66. package/src/components/ShareRecipientsInput.spec.jsx +140 -145
  67. package/src/helpers/contacts.js +8 -0
  68. package/src/helpers/recipients.js +24 -15
  69. package/src/helpers/successMessage.js +71 -21
  70. package/src/helpers/successMessage.spec.js +129 -69
  71. package/src/queries/queries.js +36 -5
  72. package/src/styles/autosuggest.styl +2 -1
  73. package/test/AppLike.jsx +6 -3
@@ -257,57 +257,6 @@ const deferablePromise = () => {
257
257
 
258
258
  const getMockProps = () => {
259
259
  return {
260
- contacts: {
261
- id: 'contacts',
262
- definition: {
263
- doctype: 'io.cozy.contacts',
264
- selector: {
265
- _id: {
266
- $gt: null
267
- }
268
- },
269
- indexedFields: ['_id'],
270
- partialFilter: {
271
- trashed: {
272
- $or: [
273
- {
274
- $eq: false
275
- },
276
- {
277
- $exists: false
278
- }
279
- ]
280
- },
281
- $or: [
282
- {
283
- cozy: {
284
- $not: {
285
- $size: 0
286
- }
287
- }
288
- },
289
- {
290
- email: {
291
- $not: {
292
- $size: 0
293
- }
294
- }
295
- }
296
- ]
297
- },
298
- limit: 1000
299
- },
300
- fetchStatus: 'pending',
301
- lastFetch: null,
302
- lastUpdate: null,
303
- lastErrorUpdate: null,
304
- lastError: null,
305
- hasMore: false,
306
- count: 0,
307
- data: [],
308
- bookmark: null,
309
- options: null
310
- },
311
260
  document: {
312
261
  id: 'SOME_DOCUMENT_ID',
313
262
  name: 'SOME_DOCUMENT_NAME',
@@ -315,22 +264,6 @@ const getMockProps = () => {
315
264
  _id: 'SOME_DOCUMENT_ID'
316
265
  },
317
266
  documentType: 'Organizations',
318
- contactGroups: {
319
- id: 'groups',
320
- definition: {
321
- doctype: 'io.cozy.contacts.groups'
322
- },
323
- fetchStatus: 'pending',
324
- lastFetch: null,
325
- lastUpdate: null,
326
- lastErrorUpdate: null,
327
- lastError: null,
328
- hasMore: false,
329
- count: 0,
330
- data: [],
331
- bookmark: null,
332
- options: null
333
- },
334
267
  hasSharedParent: null,
335
268
  isOwner: true,
336
269
  link: null,
@@ -90,8 +90,6 @@ const RejectRecipientActions = ({ reject, cancel }) => {
90
90
  * Displays a sharing dialog that allows to share a document between multiple Cozy users
91
91
  */
92
92
  const ShareDialogTwoStepsConfirmationContainer = ({
93
- contacts,
94
- contactGroups,
95
93
  createContact,
96
94
  document,
97
95
  documentType,
@@ -210,8 +208,6 @@ const ShareDialogTwoStepsConfirmationContainer = ({
210
208
  } else if (status === 'sharing') {
211
209
  dialogContent = (
212
210
  <DialogContentOnShare
213
- contacts={contacts}
214
- contactGroups={contactGroups}
215
211
  createContact={createContact}
216
212
  document={document}
217
213
  documentType={documentType}
@@ -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,