cozy-sharing 31.1.0 → 32.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/CHANGELOG.md +28 -0
  2. package/dist/components/FederatedFolder/DumbFederatedFolderModal.js +15 -16
  3. package/dist/components/FederatedFolder/FederatedFolderModal.js +78 -103
  4. package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +102 -292
  5. package/dist/components/Recipient/RecipientConfirm.js +0 -5
  6. package/dist/components/ShareAutosuggest.js +9 -4
  7. package/dist/components/ShareByEmail.js +29 -274
  8. package/dist/components/ShareByEmail.spec.js +52 -230
  9. package/dist/components/ShareByLink.js +1 -3
  10. package/dist/components/ShareDialogCozyToCozy.js +169 -35
  11. package/dist/components/ShareDialogCozyToCozy.spec.js +122 -35
  12. package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +13 -3
  13. package/dist/components/ShareModal/SharingDetailsModal.js +0 -5
  14. package/dist/components/ShareRecipientsInput.js +6 -3
  15. package/dist/components/SharedDrive/SharedDriveForm.js +11 -23
  16. package/dist/components/SharedDrive/SharedDriveModal.js +1 -1
  17. package/dist/components/SharedDrive/useSharedDrive.js +33 -57
  18. package/dist/components/SharedDrive/useSharedDrive.spec.js +29 -93
  19. package/dist/components/SharedFolder/DumbBatchSharedFolderModal.js +15 -26
  20. package/dist/components/Sharetypeselect.js +85 -90
  21. package/dist/hooks/usePendingRecipients.js +20 -0
  22. package/dist/hooks/usePendingRecipients.spec.js +30 -0
  23. package/dist/styles/autosuggest.styl +8 -2
  24. package/dist/styles/share.styl +0 -39
  25. package/dist/stylesheet.css +8 -44
  26. package/locales/en.json +5 -9
  27. package/locales/fr.json +5 -9
  28. package/locales/ru.json +5 -9
  29. package/locales/vi.json +5 -9
  30. package/package.json +4 -5
  31. package/src/components/FederatedFolder/DumbFederatedFolderModal.jsx +14 -15
  32. package/src/components/FederatedFolder/FederatedFolderModal.jsx +50 -67
  33. package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +63 -186
  34. package/src/components/ShareAutosuggest.jsx +7 -2
  35. package/src/components/ShareByEmail.jsx +35 -186
  36. package/src/components/ShareByEmail.spec.jsx +22 -173
  37. package/src/components/ShareByLink.jsx +1 -7
  38. package/src/components/ShareDialogCozyToCozy.jsx +171 -38
  39. package/src/components/ShareDialogCozyToCozy.spec.jsx +66 -0
  40. package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +11 -1
  41. package/src/components/ShareRecipientsInput.jsx +5 -2
  42. package/src/components/SharedDrive/SharedDriveForm.jsx +10 -23
  43. package/src/components/SharedDrive/SharedDriveModal.jsx +1 -1
  44. package/src/components/SharedDrive/useSharedDrive.js +24 -50
  45. package/src/components/SharedDrive/useSharedDrive.spec.js +19 -67
  46. package/src/components/SharedFolder/DumbBatchSharedFolderModal.jsx +15 -29
  47. package/src/components/Sharetypeselect.jsx +75 -58
  48. package/src/hooks/usePendingRecipients.js +13 -0
  49. package/src/hooks/usePendingRecipients.spec.js +21 -0
  50. package/src/styles/autosuggest.styl +8 -2
  51. package/src/styles/share.styl +0 -39
  52. package/dist/components/SharedDrive/helpers.js +0 -102
  53. package/dist/components/SharedDrive/helpers.spec.js +0 -227
  54. package/dist/components/SharedStatus.js +0 -61
  55. package/dist/components/SharedStatus.spec.js +0 -44
  56. package/dist/components/Sharesubmit.js +0 -28
  57. package/dist/components/__snapshots__/SharedStatus.spec.js.snap +0 -94
  58. package/dist/propTypes.js +0 -26
  59. package/src/components/SharedDrive/helpers.js +0 -108
  60. package/src/components/SharedDrive/helpers.spec.js +0 -177
  61. package/src/components/SharedStatus.jsx +0 -50
  62. package/src/components/SharedStatus.spec.js +0 -48
  63. package/src/components/Sharesubmit.jsx +0 -31
  64. package/src/components/__snapshots__/SharedStatus.spec.js.snap +0 -94
  65. package/src/propTypes.js +0 -29
@@ -1,7 +1,11 @@
1
1
  import cx from 'classnames'
2
- import React, { useMemo } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import React, { useCallback, useMemo, useState } from 'react'
3
4
 
5
+ import { useClient } from 'cozy-client'
6
+ import Button from 'cozy-ui/transpiled/react/Buttons'
4
7
  import Typography from 'cozy-ui/transpiled/react/Typography'
8
+ import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
5
9
  import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'
6
10
  import { useI18n } from 'twake-i18n'
7
11
 
@@ -9,31 +13,34 @@ import AntivirusAlert from './AntivirusAlert'
9
13
  import { default as DumbShareByEmail } from './ShareByEmail'
10
14
  import { default as DumbShareByLink } from './ShareByLink'
11
15
  import ShareDialogTwoStepsConfirmationContainer from './ShareDialogTwoStepsConfirmationContainer'
16
+ import { ShareRecipientsLimitModal } from './ShareRecipientsLimitModal'
12
17
  import WhoHasAccess from './WhoHasAccess'
18
+ import { getOrCreateFromArray } from '../helpers/contacts'
19
+ import { hasReachRecipientsLimit } from '../helpers/recipients'
20
+ import { getErrorMessage, getSuccessMessage } from '../helpers/share'
21
+ import { usePendingRecipients } from '../hooks/usePendingRecipients'
13
22
  import styles from '../styles/share.styl'
14
23
 
15
- /**
16
- * Displays the sharing interface that can be used when ShareDialogCozyToCozy is in sharing state
17
- */
18
24
  const SharingContent = ({
19
- createContact,
20
25
  document,
21
26
  documentType,
22
27
  hasSharedParent,
23
28
  isOwner,
24
29
  onRevoke,
25
30
  onRevokeSelf,
26
- onShare,
27
31
  recipients,
28
32
  sharing,
29
- sharingDesc,
30
33
  showShareByEmail,
31
34
  showShareOnlyByLink,
32
35
  showWhoHasAccess,
33
36
  recipientsToBeConfirmed,
34
37
  verifyRecipient,
35
38
  link,
36
- permissions
39
+ permissions,
40
+ pendingRecipients,
41
+ onPendingRecipientsChange,
42
+ selectedOption,
43
+ onSelectedOptionChange
37
44
  }) => {
38
45
  const { t } = useI18n()
39
46
  const { isMobile } = useBreakpoints()
@@ -64,13 +71,14 @@ const SharingContent = ({
64
71
  </Typography>
65
72
  {showShareByEmail && (
66
73
  <DumbShareByEmail
67
- createContact={createContact}
68
74
  currentRecipients={recipients}
69
75
  document={document}
70
76
  documentType={documentType}
71
- onShare={onShare}
72
77
  sharing={sharing}
73
- sharingDesc={sharingDesc}
78
+ pendingRecipients={pendingRecipients}
79
+ onPendingRecipientsChange={onPendingRecipientsChange}
80
+ selectedOption={selectedOption}
81
+ onSelectedOptionChange={onSelectedOptionChange}
74
82
  />
75
83
  )}
76
84
  </div>
@@ -92,55 +100,180 @@ const SharingContent = ({
92
100
  )
93
101
  }
94
102
 
95
- /**
96
- * Displays the dialog's title that can be used when ShareDialogCozyToCozy is in sharing state
97
- */
98
103
  const SharingTitleFunction = ({ documentType, document }) =>
99
104
  function SharingTitle() {
100
105
  const { t } = useI18n()
101
-
102
106
  const title = t(`${documentType}.share.title`, {
103
107
  name: document.name || document.attributes?.name
104
108
  })
105
-
106
109
  return title
107
110
  }
108
111
 
109
- /**
110
- * Displays a sharing dialog that allows to share a document between multiple Cozy users
111
- */
112
112
  const ShareDialogCozyToCozy = ({
113
113
  showShareByLink,
114
114
  showGenerateLinkButton,
115
115
  autoOpenShareRestriction,
116
116
  documentType,
117
117
  document,
118
+ onShare,
119
+ recipients,
120
+ sharingDesc,
121
+ createContact,
122
+ onClose,
118
123
  ...props
119
124
  }) => {
125
+ const { t } = useI18n()
126
+ const client = useClient()
127
+ const { showAlert } = useAlert()
128
+
129
+ const {
130
+ pendingRecipients,
131
+ setPendingRecipients,
132
+ selectedOption,
133
+ setSelectedOption
134
+ } = usePendingRecipients()
135
+
136
+ const [submitting, setSubmitting] = useState(false)
137
+ const [showRecipientsLimit, setShowRecipientsLimit] = useState(false)
138
+
139
+ const handleShare = useCallback(async () => {
140
+ if (pendingRecipients.length === 0) {
141
+ onClose()
142
+ return
143
+ }
144
+
145
+ if (hasReachRecipientsLimit(recipients, pendingRecipients)) {
146
+ setShowRecipientsLimit(true)
147
+ return
148
+ }
149
+
150
+ setSubmitting(true)
151
+ try {
152
+ const contacts = await getOrCreateFromArray(
153
+ client,
154
+ pendingRecipients,
155
+ createContact
156
+ )
157
+ const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
158
+ const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
159
+
160
+ await onShare({
161
+ document,
162
+ recipients: readWriteRecipients,
163
+ readOnlyRecipients,
164
+ description: sharingDesc,
165
+ openSharing: readWriteRecipients.length > 0
166
+ })
167
+
168
+ showAlert({
169
+ message: t(...getSuccessMessage(recipients, contacts, documentType)),
170
+ severity: 'success',
171
+ variant: 'filled'
172
+ })
173
+ onClose()
174
+ } catch (err) {
175
+ showAlert({
176
+ message: t(
177
+ ...getErrorMessage({
178
+ t,
179
+ err,
180
+ documentType,
181
+ recipients: pendingRecipients,
182
+ selectedOption
183
+ })
184
+ ),
185
+ severity: 'error',
186
+ variant: 'filled'
187
+ })
188
+ } finally {
189
+ setSubmitting(false)
190
+ }
191
+ }, [
192
+ pendingRecipients,
193
+ selectedOption,
194
+ client,
195
+ showAlert,
196
+ t,
197
+ recipients,
198
+ onShare,
199
+ onClose,
200
+ createContact,
201
+ document,
202
+ documentType,
203
+ sharingDesc
204
+ ])
205
+
120
206
  const dialogActionsOnShare = useMemo(() => {
121
- if (!showShareByLink) return null
122
- const BoundShareByLink = dialogActionProps => (
123
- <DumbShareByLink
124
- {...dialogActionProps}
125
- showGenerateLinkButton={showGenerateLinkButton}
126
- autoOpenShareRestriction={autoOpenShareRestriction}
127
- />
207
+ const Actions = dialogActionProps => (
208
+ <>
209
+ {showShareByLink && (
210
+ <DumbShareByLink
211
+ {...dialogActionProps}
212
+ showGenerateLinkButton={showGenerateLinkButton}
213
+ autoOpenShareRestriction={autoOpenShareRestriction}
214
+ />
215
+ )}
216
+ <Button
217
+ variant="primary"
218
+ label={t(`${documentType}.share.shareByEmail.send`)}
219
+ busy={submitting}
220
+ onClick={handleShare}
221
+ />
222
+ </>
128
223
  )
129
- BoundShareByLink.displayName = 'BoundShareByLink'
130
- return BoundShareByLink
131
- }, [showShareByLink, showGenerateLinkButton, autoOpenShareRestriction])
224
+ Actions.displayName = 'ShareDialogCozyToCozyActions'
225
+ return Actions
226
+ }, [
227
+ handleShare,
228
+ submitting,
229
+ t,
230
+ documentType,
231
+ showShareByLink,
232
+ showGenerateLinkButton,
233
+ autoOpenShareRestriction
234
+ ])
132
235
 
133
236
  return (
134
- <ShareDialogTwoStepsConfirmationContainer
135
- {...props}
136
- documentType={documentType}
137
- document={document}
138
- dialogContentOnShare={SharingContent}
139
- dialogActionsOnShare={dialogActionsOnShare}
140
- dialogTitleOnShare={SharingTitleFunction({ documentType, document })}
141
- disableGutters
142
- />
237
+ <>
238
+ <ShareDialogTwoStepsConfirmationContainer
239
+ {...props}
240
+ documentType={documentType}
241
+ document={document}
242
+ recipients={recipients}
243
+ sharingDesc={sharingDesc}
244
+ createContact={createContact}
245
+ onShare={onShare}
246
+ onClose={onClose}
247
+ dialogContentOnShare={SharingContent}
248
+ dialogActionsOnShare={dialogActionsOnShare}
249
+ dialogTitleOnShare={SharingTitleFunction({ documentType, document })}
250
+ disableGutters
251
+ pendingRecipients={pendingRecipients}
252
+ onPendingRecipientsChange={setPendingRecipients}
253
+ selectedOption={selectedOption}
254
+ onSelectedOptionChange={setSelectedOption}
255
+ />
256
+ {showRecipientsLimit && (
257
+ <ShareRecipientsLimitModal
258
+ documentName={document?.name}
259
+ onConfirm={() => setShowRecipientsLimit(false)}
260
+ />
261
+ )}
262
+ </>
143
263
  )
144
264
  }
145
265
 
266
+ ShareDialogCozyToCozy.propTypes = {
267
+ showShareByLink: PropTypes.bool,
268
+ showGenerateLinkButton: PropTypes.bool,
269
+ autoOpenShareRestriction: PropTypes.bool,
270
+ documentType: PropTypes.string.isRequired,
271
+ document: PropTypes.object.isRequired,
272
+ onShare: PropTypes.func.isRequired,
273
+ recipients: PropTypes.array.isRequired,
274
+ sharingDesc: PropTypes.string,
275
+ createContact: PropTypes.func.isRequired,
276
+ onClose: PropTypes.func.isRequired
277
+ }
278
+
146
279
  export default ShareDialogCozyToCozy
@@ -20,6 +20,12 @@ jest.mock('../hooks/useSharingContext', () => ({
20
20
  })
21
21
  }))
22
22
 
23
+ jest.mock('../helpers/contacts', () => ({
24
+ getOrCreateFromArray: jest.fn((client, recipients) =>
25
+ Promise.resolve(recipients)
26
+ )
27
+ }))
28
+
23
29
  describe('ShareDialogCozyToCozy', () => {
24
30
  const client = createMockClient({})
25
31
  client.options = {
@@ -163,6 +169,65 @@ describe('ShareDialogCozyToCozy', () => {
163
169
  ).not.toBeInTheDocument()
164
170
  })
165
171
 
172
+ it('main Share button calls onClose when there are no pending chips', () => {
173
+ const onClose = jest.fn()
174
+ const onShare = jest.fn()
175
+ const props = { ...getMockProps(), onClose, onShare }
176
+
177
+ const { getByRole } = setup(props)
178
+
179
+ fireEvent.click(getByRole('button', { name: 'Share' }))
180
+
181
+ expect(onShare).not.toHaveBeenCalled()
182
+ expect(onClose).toHaveBeenCalledTimes(1)
183
+ })
184
+
185
+ it('main Share button calls onShare with chips then closes', async () => {
186
+ const onClose = jest.fn()
187
+ const onShare = jest.fn().mockResolvedValue(undefined)
188
+ const props = { ...getMockProps(), onClose, onShare }
189
+
190
+ const { getByPlaceholderText, getByRole } = setup(props)
191
+
192
+ act(() => {
193
+ fireEvent.change(
194
+ getByPlaceholderText(
195
+ 'Enter the email address or name of the recipient'
196
+ ),
197
+ {
198
+ target: { value: 'new@cozycloud.cc' }
199
+ }
200
+ )
201
+ })
202
+ act(() => {
203
+ fireEvent.keyPress(
204
+ getByPlaceholderText(
205
+ 'Enter the email address or name of the recipient'
206
+ ),
207
+ {
208
+ key: 'Enter',
209
+ code: 'Enter',
210
+ charCode: 13
211
+ }
212
+ )
213
+ })
214
+
215
+ await act(async () => {
216
+ fireEvent.click(getByRole('button', { name: 'Share' }))
217
+ })
218
+
219
+ expect(onShare).toHaveBeenCalledWith(
220
+ expect.objectContaining({
221
+ document: props.document,
222
+ recipients: [{ email: 'new@cozycloud.cc' }],
223
+ readOnlyRecipients: [],
224
+ description: props.sharingDesc,
225
+ openSharing: true
226
+ })
227
+ )
228
+ expect(onClose).toHaveBeenCalledTimes(1)
229
+ })
230
+
166
231
  it(`should display confirmation of 'contact rejection' when user click on the 'reject' button`, async () => {
167
232
  const { promise, resolve } = deferablePromise()
168
233
 
@@ -372,6 +437,7 @@ const getMockProps = () => {
372
437
  showWhoHasAccess: true,
373
438
  onRevoke: jest.fn(),
374
439
  onShare: jest.fn(),
440
+ onClose: jest.fn(),
375
441
  createContact: jest.fn()
376
442
  }
377
443
  }
@@ -108,7 +108,11 @@ const ShareDialogTwoStepsConfirmationContainer = ({
108
108
  twoStepsConfirmationMethods = {},
109
109
  dialogContentOnShare: DialogContentOnShare,
110
110
  dialogActionsOnShare: DialogActionsOnShare,
111
- dialogTitleOnShare: DialogTitleOnShare
111
+ dialogTitleOnShare: DialogTitleOnShare,
112
+ pendingRecipients,
113
+ onPendingRecipientsChange,
114
+ selectedOption,
115
+ onSelectedOptionChange
112
116
  }) => {
113
117
  const { t } = useI18n()
114
118
 
@@ -222,6 +226,10 @@ const ShareDialogTwoStepsConfirmationContainer = ({
222
226
  permissions={permissions}
223
227
  onUpdateShareLinkPermissions={onUpdateShareLinkPermissions}
224
228
  onRevokeLink={onRevokeLink}
229
+ pendingRecipients={pendingRecipients}
230
+ onPendingRecipientsChange={onPendingRecipientsChange}
231
+ selectedOption={selectedOption}
232
+ onSelectedOptionChange={onSelectedOptionChange}
225
233
  />
226
234
  )
227
235
 
@@ -230,6 +238,8 @@ const ShareDialogTwoStepsConfirmationContainer = ({
230
238
  link={link}
231
239
  document={document}
232
240
  documentType={documentType}
241
+ pendingRecipients={pendingRecipients}
242
+ selectedOption={selectedOption}
233
243
  />
234
244
  ) : null
235
245
  } else if (status === 'confirmingRecipient') {
@@ -23,7 +23,8 @@ const ShareRecipientsInput = ({
23
23
  placeholder,
24
24
  onPick,
25
25
  onRemove,
26
- disabled
26
+ disabled,
27
+ endAdornment
27
28
  }) => {
28
29
  const reachableContactsQuery = buildReachableContactsQuery()
29
30
  const reachableContactsResult = useQueryAll(
@@ -109,6 +110,7 @@ const ShareRecipientsInput = ({
109
110
  onPick={onPick}
110
111
  onRemove={onRemove}
111
112
  placeholder={placeholder}
113
+ endAdornment={endAdornment}
112
114
  />
113
115
  )
114
116
  }
@@ -119,7 +121,8 @@ ShareRecipientsInput.propTypes = {
119
121
  placeholder: PropTypes.string,
120
122
  onPick: PropTypes.func.isRequired,
121
123
  onRemove: PropTypes.func.isRequired,
122
- disabled: PropTypes.bool
124
+ disabled: PropTypes.bool,
125
+ endAdornment: PropTypes.node
123
126
  }
124
127
 
125
128
  ShareRecipientsInput.defaultProps = {
@@ -8,20 +8,18 @@ import { useI18n } from 'twake-i18n'
8
8
 
9
9
  import withLocales from '../../hoc/withLocales'
10
10
  import { default as DumbShareByEmail } from '../ShareByEmail'
11
- import WhoHasAccess from '../WhoHasAccess'
12
11
  import { useSharedDrive } from './useSharedDrive'
13
12
 
14
13
  export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
15
14
  const { t } = useI18n()
16
15
  const {
17
16
  sharedDriveName,
18
- recipients,
19
17
  handleSharedDriveNameChange,
20
- onShare,
21
- onCreate,
22
- onSetType,
23
- onRevoke,
24
- createContact
18
+ pendingRecipients,
19
+ setPendingRecipients,
20
+ selectedOption,
21
+ setSelectedOption,
22
+ onCreate
25
23
  } = useSharedDrive({ onSuccess })
26
24
 
27
25
  return (
@@ -40,25 +38,14 @@ export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
40
38
  {t('SharedDrive.sharedDriveModal.addPeople')}
41
39
  </Typography>
42
40
  <DumbShareByEmail
43
- createContact={createContact}
44
- currentRecipients={recipients}
41
+ currentRecipients={[]}
45
42
  documentType="Files"
46
- sharedDrive
47
- onShare={onShare}
48
- submitLabel={t('SharedDrive.sharedDriveModal.add')}
49
- showNotifications={false}
50
- sharingDesc=""
43
+ pendingRecipients={pendingRecipients}
44
+ onPendingRecipientsChange={setPendingRecipients}
45
+ selectedOption={selectedOption}
46
+ onSelectedOptionChange={setSelectedOption}
51
47
  />
52
48
  </div>
53
- <WhoHasAccess
54
- isOwner
55
- isSharedDrive
56
- recipients={recipients}
57
- documentType="Files"
58
- className="u-w-100"
59
- onRevoke={onRevoke}
60
- onSetType={onSetType}
61
- />
62
49
  <div className="u-flex u-ph-2 u-pv-1">
63
50
  <Button
64
51
  variant="text"
@@ -4,8 +4,8 @@ import React from 'react'
4
4
  import { FixedDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
5
5
  import { useI18n } from 'twake-i18n'
6
6
 
7
- import withLocales from '../../hoc/withLocales'
8
7
  import { SharedDriveForm } from './SharedDriveForm'
8
+ import withLocales from '../../hoc/withLocales'
9
9
 
10
10
  export const SharedDriveModal = withLocales(({ onClose }) => {
11
11
  const { t } = useI18n()
@@ -4,13 +4,8 @@ import { useClient } from 'cozy-client'
4
4
  import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
5
5
  import { useI18n } from 'twake-i18n'
6
6
 
7
- import {
8
- RECIPIENT_INDEX_PREFIX,
9
- formatRecipients,
10
- mergeAndDeduplicateRecipients,
11
- moveRecipientToReadOnly,
12
- moveRecipientToReadWrite
13
- } from './helpers'
7
+ import { getOrCreateFromArray } from '../../helpers/contacts'
8
+ import { usePendingRecipients } from '../../hooks/usePendingRecipients'
14
9
  import { Contact } from '../../models'
15
10
 
16
11
  export const useSharedDrive = ({ onSuccess }) => {
@@ -18,36 +13,35 @@ export const useSharedDrive = ({ onSuccess }) => {
18
13
  const { t } = useI18n()
19
14
  const { showAlert } = useAlert()
20
15
 
21
- const [sharedDriveRecipients, setSharedDriveRecipients] = useState({
22
- recipients: [],
23
- readOnlyRecipients: []
24
- })
25
16
  const [sharedDriveName, setSharedDriveName] = useState('')
17
+ const {
18
+ pendingRecipients,
19
+ setPendingRecipients,
20
+ selectedOption,
21
+ setSelectedOption
22
+ } = usePendingRecipients()
26
23
 
27
24
  const handleSharedDriveNameChange = event => {
28
25
  setSharedDriveName(event.target.value)
29
26
  }
30
27
 
31
- const onShare = params => {
32
- setSharedDriveRecipients(prev => ({
33
- recipients: mergeAndDeduplicateRecipients([
34
- prev.recipients,
35
- params.recipients
36
- ]),
37
- readOnlyRecipients: mergeAndDeduplicateRecipients([
38
- prev.readOnlyRecipients,
39
- params.readOnlyRecipients
40
- ])
41
- }))
42
- }
28
+ const createContact = contact => client.create(Contact.doctype, contact)
43
29
 
44
30
  const onCreate = async () => {
45
31
  try {
32
+ const contacts = await getOrCreateFromArray(
33
+ client,
34
+ pendingRecipients,
35
+ createContact
36
+ )
37
+ const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
38
+ const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
39
+
46
40
  await client.collection('io.cozy.sharings').createSharedDrive({
47
41
  name: sharedDriveName,
48
42
  description: sharedDriveName,
49
- recipients: sharedDriveRecipients.recipients,
50
- readOnlyRecipients: sharedDriveRecipients.readOnlyRecipients
43
+ recipients: readWriteRecipients,
44
+ readOnlyRecipients
51
45
  })
52
46
 
53
47
  showAlert({
@@ -66,33 +60,13 @@ export const useSharedDrive = ({ onSuccess }) => {
66
60
  }
67
61
  }
68
62
 
69
- const onSetType = (index, newType) => {
70
- const _id = index.split(RECIPIENT_INDEX_PREFIX)[1]
71
- setSharedDriveRecipients(prev =>
72
- newType === 'two-way'
73
- ? moveRecipientToReadWrite(prev, _id)
74
- : moveRecipientToReadOnly(prev, _id)
75
- )
76
- }
77
-
78
- const onRevoke = index => {
79
- const _id = index.split(RECIPIENT_INDEX_PREFIX)[1]
80
- setSharedDriveRecipients(prev => ({
81
- recipients: prev.recipients.filter(r => r._id !== _id),
82
- readOnlyRecipients: prev.readOnlyRecipients.filter(r => r._id !== _id)
83
- }))
84
- }
85
-
86
- const createContact = contact => client.create(Contact.doctype, contact)
87
-
88
63
  return {
89
64
  sharedDriveName,
90
- recipients: formatRecipients(sharedDriveRecipients),
91
65
  handleSharedDriveNameChange,
92
- onShare,
93
- onCreate,
94
- onSetType,
95
- onRevoke,
96
- createContact
66
+ pendingRecipients,
67
+ setPendingRecipients,
68
+ selectedOption,
69
+ setSelectedOption,
70
+ onCreate
97
71
  }
98
72
  }