cozy-sharing 12.3.0 → 13.1.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 +46 -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 +57 -23
  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 +55 -48
  25. package/dist/components/ShareRecipientsInput.spec.js +122 -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 +32 -10
  34. package/locales/fr.json +30 -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 +54 -17
  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 +95 -53
  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
@@ -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,117 @@
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,
21
+ currentRecipients,
11
22
  recipients,
12
23
  placeholder,
13
24
  onPick,
14
25
  onRemove
15
26
  }) => {
16
- const [loading, setLoading] = useState(false)
27
+ const reachableContactsQuery = buildReachableContactsQuery()
28
+ const reachableContactsResult = useQueryAll(
29
+ reachableContactsQuery.definition,
30
+ reachableContactsQuery.options
31
+ )
17
32
 
18
- useEffect(() => {
19
- if (
20
- loading &&
21
- !contacts.hasMore &&
22
- contacts.fetchStatus === 'loaded' &&
23
- !contactGroups.hasMore &&
24
- contactGroups.fetchStatus === 'loaded'
25
- ) {
26
- setLoading(false)
33
+ const unreachableContactsWithGroupsQuery =
34
+ buildUnreachableContactsWithGroupsQuery()
35
+ const unreachableContactsWithGroupsResult = useQueryAll(
36
+ unreachableContactsWithGroupsQuery.definition,
37
+ {
38
+ ...unreachableContactsWithGroupsQuery.options,
39
+ enabled: !!flag('sharing.show-recipient-groups')
27
40
  }
28
- }, [contacts, contactGroups, loading])
41
+ )
29
42
 
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
- }
43
+ const contactGroupsByIdsQuery = buildContactGroupsByIdsQuery([
44
+ ...new Set(
45
+ (reachableContactsResult.data || []).flatMap(contact => {
46
+ return (contact.relationships?.groups?.data || []).map(
47
+ group => group._id
48
+ )
49
+ })
50
+ )
51
+ ])
52
+ const contactGroupsByIdsResult = useQueryAll(
53
+ contactGroupsByIdsQuery.definition,
54
+ contactGroupsByIdsQuery.options
55
+ )
40
56
 
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 => ({
57
+ const isLoading =
58
+ isQueryLoading(reachableContactsResult) ||
59
+ reachableContactsResult.hasMore ||
60
+ isQueryLoading(contactGroupsByIdsResult) ||
61
+ contactGroupsByIdsResult.hasMore ||
62
+ (flag('sharing.show-recipient-groups') &&
63
+ (isQueryLoading(unreachableContactsWithGroupsResult) ||
64
+ unreachableContactsWithGroupsResult.hasMore))
65
+
66
+ const currentRecipientGroups = currentRecipients
67
+ .map(({ id }) => id)
68
+ .filter(Boolean)
69
+ const contactGroups = (contactGroupsByIdsResult.data || [])
70
+ .filter(
71
+ ({ _id }) =>
72
+ !flag('sharing.show-recipient-groups') ||
73
+ !currentRecipientGroups.includes(_id)
74
+ )
75
+ .map(contactGroup => {
76
+ const reachableMembers = getContactsFromGroupId(
77
+ reachableContactsResult.data,
78
+ contactGroup.id
79
+ ).map(contact => ({
80
+ ...contact,
81
+ isReachable: true
82
+ }))
83
+
84
+ if (flag('sharing.show-recipient-groups') !== true) {
85
+ return {
48
86
  ...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
- }
87
+ members: reachableMembers
88
+ }
89
+ }
57
90
 
58
- return total
59
- }, 0)
60
- }))
61
- .filter(contactGroup => contactGroup.membersCount > 0)
91
+ const unreachableMembers = getContactsFromGroupId(
92
+ unreachableContactsWithGroupsResult.data,
93
+ contactGroup.id
94
+ ).map(contact => ({
95
+ ...contact,
96
+ isReachable: false
97
+ }))
62
98
 
63
- return [...contacts.data, ...contactGroupsWithCount]
64
- }
65
- }
99
+ return {
100
+ ...contactGroup,
101
+ members: [...reachableMembers, ...unreachableMembers]
102
+ }
103
+ })
104
+
105
+ const contactsAndGroups = [
106
+ ...(reachableContactsResult.data || []),
107
+ ...contactGroups
108
+ ]
66
109
 
67
110
  return (
68
111
  <ShareAutosuggest
69
- loading={loading}
70
- contactsAndGroups={getContactsAndGroups()}
112
+ loading={isLoading}
113
+ contactsAndGroups={contactsAndGroups}
71
114
  recipients={recipients}
72
- onFocus={onShareAutosuggestFocus}
73
115
  onPick={onPick}
74
116
  onRemove={onRemove}
75
117
  placeholder={placeholder}
@@ -78,8 +120,7 @@ const ShareRecipientsInput = ({
78
120
  }
79
121
 
80
122
  ShareRecipientsInput.propTypes = {
81
- contacts: contactsResponseType.isRequired,
82
- contactGroups: contactGroupsResponseType.isRequired,
123
+ currentRecipients: PropTypes.array,
83
124
  recipients: PropTypes.array,
84
125
  placeholder: PropTypes.string,
85
126
  onPick: PropTypes.func.isRequired,
@@ -87,6 +128,7 @@ ShareRecipientsInput.propTypes = {
87
128
  }
88
129
 
89
130
  ShareRecipientsInput.defaultProps = {
131
+ currentRecipients: [],
90
132
  recipients: []
91
133
  }
92
134