cozy-sharing 32.3.2 → 33.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [33.0.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@32.3.2...cozy-sharing@33.0.0) (2026-06-02)
7
+
8
+ ### Bug Fixes
9
+
10
+ - Avoid adding an already added recipients in EditSharedDriveModal ([d24e01c](https://github.com/cozy/cozy-libs/commit/d24e01c999a2c09fe87e59a0c7a26c3555c96557))
11
+ - Hide owner in EditSharedDriveModal ([9c2b060](https://github.com/cozy/cozy-libs/commit/9c2b060fc3f55c44cf35831298879d3fe0a7a403))
12
+
13
+ ### Features
14
+
15
+ - Add spinner to create shared drive form ([4112e7c](https://github.com/cozy/cozy-libs/commit/4112e7c7f592115ed2689ded3f45d876ee12f9dc))
16
+ - Add spinner to edit shared drive form ([f135ff5](https://github.com/cozy/cozy-libs/commit/f135ff5bae8e9fbe6b510a3114af363159ced7af))
17
+
18
+ ### BREAKING CHANGES
19
+
20
+ - You need cozy-ui >= 139.0.2
21
+
6
22
  ## [32.3.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@32.3.1...cozy-sharing@32.3.2) (2026-05-26)
7
23
 
8
24
  ### Bug Fixes
@@ -14,7 +14,7 @@ import Button from 'cozy-ui/transpiled/react/Buttons';
14
14
  import { FixedDialog } from 'cozy-ui/transpiled/react/CozyDialogs';
15
15
  import TextField from 'cozy-ui/transpiled/react/TextField';
16
16
  import Typography from 'cozy-ui/transpiled/react/Typography';
17
- import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert';
17
+ import { useSubmitWithLoader } from 'cozy-ui/transpiled/react/hooks/useSubmitWithLoader';
18
18
  import { useI18n } from 'twake-i18n';
19
19
  import SharedDriveHeader from './SharedDriveHeader';
20
20
  import { getOrCreateFromArray } from '../../helpers/contacts';
@@ -36,51 +36,37 @@ export var EditSharedDriveModal = withLocales(function (_ref) {
36
36
  getRecipients = _useSharingContext.getRecipients,
37
37
  revoke = _useSharingContext.revoke;
38
38
 
39
- var _useAlert = useAlert(),
40
- showAlert = _useAlert.showAlert;
41
-
42
39
  var _usePendingRecipients = usePendingRecipients(),
43
40
  pendingRecipients = _usePendingRecipients.pendingRecipients,
44
41
  setPendingRecipients = _usePendingRecipients.setPendingRecipients,
45
42
  selectedOption = _usePendingRecipients.selectedOption,
46
43
  setSelectedOption = _usePendingRecipients.setSelectedOption;
47
44
 
45
+ var _useSubmitWithLoader = useSubmitWithLoader(),
46
+ onSubmit = _useSubmitWithLoader.onSubmit,
47
+ isLoading = _useSubmitWithLoader.isLoading;
48
+
48
49
  var _useState = useState(document.name),
49
50
  _useState2 = _slicedToArray(_useState, 2),
50
51
  driveName = _useState2[0],
51
52
  setDriveName = _useState2[1];
52
53
 
53
- var _useState3 = useState(false),
54
- _useState4 = _slicedToArray(_useState3, 2),
55
- isSaving = _useState4[0],
56
- setIsSaving = _useState4[1];
57
-
58
54
  var onSave = /*#__PURE__*/function () {
59
55
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
60
56
  var contacts, readWriteRecipients, readOnlyRecipients;
61
57
  return _regeneratorRuntime.wrap(function _callee$(_context) {
62
58
  while (1) switch (_context.prev = _context.next) {
63
59
  case 0:
64
- if (!isSaving) {
65
- _context.next = 2;
66
- break;
67
- }
68
-
69
- return _context.abrupt("return");
70
-
71
- case 2:
72
- setIsSaving(true);
73
- _context.prev = 3;
74
- _context.next = 6;
60
+ _context.next = 2;
75
61
  return getOrCreateFromArray(client, pendingRecipients, function (contact) {
76
62
  return client.create('io.cozy.contacts', contact);
77
63
  });
78
64
 
79
- case 6:
65
+ case 2:
80
66
  contacts = _context.sent;
81
67
  readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts;
82
68
  readOnlyRecipients = selectedOption === 'readOnly' ? contacts : [];
83
- _context.next = 11;
69
+ _context.next = 7;
84
70
  return share({
85
71
  document: document,
86
72
  recipients: readWriteRecipients,
@@ -89,47 +75,23 @@ export var EditSharedDriveModal = withLocales(function (_ref) {
89
75
  openSharing: false
90
76
  });
91
77
 
92
- case 11:
78
+ case 7:
93
79
  if (!((document === null || document === void 0 ? void 0 : document.name) !== driveName)) {
94
- _context.next = 14;
80
+ _context.next = 10;
95
81
  break;
96
82
  }
97
83
 
98
- _context.next = 14;
84
+ _context.next = 10;
99
85
  return client.collection('io.cozy.files').update(_objectSpread(_objectSpread({}, document), {}, {
100
86
  name: driveName,
101
87
  _rev: document._rev || document.meta.rev
102
88
  }));
103
89
 
104
- case 14:
105
- showAlert({
106
- message: t('SharedDrive.editSharedDriveModal.successNotification'),
107
- severity: 'success',
108
- variant: 'filled'
109
- });
110
- onClose();
111
- _context.next = 21;
112
- break;
113
-
114
- case 18:
115
- _context.prev = 18;
116
- _context.t0 = _context["catch"](3);
117
- showAlert({
118
- message: t('SharedDrive.editSharedDriveModal.errorNotification'),
119
- severity: 'error',
120
- variant: 'filled'
121
- });
122
-
123
- case 21:
124
- _context.prev = 21;
125
- setIsSaving(false);
126
- return _context.finish(21);
127
-
128
- case 24:
90
+ case 10:
129
91
  case "end":
130
92
  return _context.stop();
131
93
  }
132
- }, _callee, null, [[3, 18, 21, 24]]);
94
+ }, _callee);
133
95
  }));
134
96
 
135
97
  return function onSave() {
@@ -168,8 +130,8 @@ export var EditSharedDriveModal = withLocales(function (_ref) {
168
130
  variant: "h6",
169
131
  className: "u-mb-half"
170
132
  }, t('Share.contacts.addUsers')), /*#__PURE__*/React.createElement(DumbShareByEmail, {
171
- currentRecipients: [],
172
133
  documentType: "Files",
134
+ currentRecipients: existingRecipients,
173
135
  pendingRecipients: pendingRecipients,
174
136
  onPendingRecipientsChange: setPendingRecipients,
175
137
  selectedOption: selectedOption,
@@ -177,6 +139,7 @@ export var EditSharedDriveModal = withLocales(function (_ref) {
177
139
  })), /*#__PURE__*/React.createElement(WhoHasAccess, {
178
140
  isOwner: true,
179
141
  isSharedDrive: true,
142
+ showOwner: false,
180
143
  recipients: existingRecipients,
181
144
  document: document,
182
145
  documentType: "Files",
@@ -189,14 +152,28 @@ export var EditSharedDriveModal = withLocales(function (_ref) {
189
152
  label: t('SharedDrive.sharedDriveModal.cancel'),
190
153
  className: "u-w-100 u-m-1",
191
154
  size: "large",
192
- onClick: onClose
155
+ onClick: onClose,
156
+ disabled: isLoading
193
157
  }), /*#__PURE__*/React.createElement(Button, {
194
158
  variant: "primary",
195
159
  label: t('SharedDrive.sharedDriveModal.save'),
196
160
  className: "u-w-100 u-m-1",
197
161
  size: "large",
198
- disabled: isSaving,
199
- onClick: onSave
162
+ onClick: function onClick() {
163
+ return onSubmit({
164
+ submit: onSave,
165
+ success: {
166
+ action: onClose,
167
+ message: t('SharedDrive.editSharedDriveModal.successNotification')
168
+ },
169
+ error: {
170
+ message: function message() {
171
+ return t('SharedDrive.editSharedDriveModal.errorNotification');
172
+ }
173
+ }
174
+ });
175
+ },
176
+ busy: isLoading
200
177
  })))
201
178
  });
202
179
  });
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import Button from 'cozy-ui/transpiled/react/Buttons';
4
4
  import TextField from 'cozy-ui/transpiled/react/TextField';
5
5
  import Typography from 'cozy-ui/transpiled/react/Typography';
6
+ import { useSubmitWithLoader } from 'cozy-ui/transpiled/react/hooks/useSubmitWithLoader';
6
7
  import { useI18n } from 'twake-i18n';
7
8
  import withLocales from '../../hoc/withLocales';
8
9
  import { default as DumbShareByEmail } from '../ShareByEmail';
@@ -15,9 +16,7 @@ export var SharedDriveForm = withLocales(function (_ref) {
15
16
  var _useI18n = useI18n(),
16
17
  t = _useI18n.t;
17
18
 
18
- var _useSharedDrive = useSharedDrive({
19
- onSuccess: onSuccess
20
- }),
19
+ var _useSharedDrive = useSharedDrive(),
21
20
  sharedDriveName = _useSharedDrive.sharedDriveName,
22
21
  handleSharedDriveNameChange = _useSharedDrive.handleSharedDriveNameChange,
23
22
  pendingRecipients = _useSharedDrive.pendingRecipients,
@@ -26,6 +25,10 @@ export var SharedDriveForm = withLocales(function (_ref) {
26
25
  setSelectedOption = _useSharedDrive.setSelectedOption,
27
26
  onCreate = _useSharedDrive.onCreate;
28
27
 
28
+ var _useSubmitWithLoader = useSubmitWithLoader(),
29
+ onSubmit = _useSubmitWithLoader.onSubmit,
30
+ isLoading = _useSubmitWithLoader.isLoading;
31
+
29
32
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
30
33
  className: "u-ph-2"
31
34
  }, /*#__PURE__*/React.createElement(SharedDriveHeader, {
@@ -55,13 +58,28 @@ export var SharedDriveForm = withLocales(function (_ref) {
55
58
  label: t('SharedDrive.sharedDriveModal.cancel'),
56
59
  className: "u-w-100 u-m-1",
57
60
  size: "large",
58
- onClick: onCancel
61
+ onClick: onCancel,
62
+ disabled: isLoading
59
63
  }), /*#__PURE__*/React.createElement(Button, {
60
64
  variant: "primary",
61
65
  label: t('SharedDrive.sharedDriveModal.create'),
62
66
  className: "u-w-100 u-m-1",
63
67
  size: "large",
64
- onClick: onCreate
68
+ onClick: function onClick() {
69
+ return onSubmit({
70
+ submit: onCreate,
71
+ success: {
72
+ action: onSuccess,
73
+ message: t('SharedDrive.sharedDriveModal.successNotification')
74
+ },
75
+ error: {
76
+ message: function message() {
77
+ return t('SharedDrive.sharedDriveModal.errorNotification');
78
+ }
79
+ }
80
+ });
81
+ },
82
+ busy: isLoading
65
83
  })));
66
84
  });
67
85
  SharedDriveForm.propTypes = {
@@ -3,21 +3,12 @@ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import _regeneratorRuntime from "@babel/runtime/regenerator";
4
4
  import { useState } from 'react';
5
5
  import { useClient } from 'cozy-client';
6
- import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert';
7
- import { useI18n } from 'twake-i18n';
8
6
  import { getOrCreateFromArray } from '../../helpers/contacts';
9
7
  import { usePendingRecipients } from '../../hooks/usePendingRecipients';
10
8
  import { Contact } from '../../models';
11
- export var useSharedDrive = function useSharedDrive(_ref) {
12
- var onSuccess = _ref.onSuccess;
9
+ export var useSharedDrive = function useSharedDrive() {
13
10
  var client = useClient();
14
11
 
15
- var _useI18n = useI18n(),
16
- t = _useI18n.t;
17
-
18
- var _useAlert = useAlert(),
19
- showAlert = _useAlert.showAlert;
20
-
21
12
  var _useState = useState(''),
22
13
  _useState2 = _slicedToArray(_useState, 2),
23
14
  sharedDriveName = _useState2[0],
@@ -38,20 +29,19 @@ export var useSharedDrive = function useSharedDrive(_ref) {
38
29
  };
39
30
 
40
31
  var onCreate = /*#__PURE__*/function () {
41
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
32
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
42
33
  var contacts, readWriteRecipients, readOnlyRecipients;
43
34
  return _regeneratorRuntime.wrap(function _callee$(_context) {
44
35
  while (1) switch (_context.prev = _context.next) {
45
36
  case 0:
46
- _context.prev = 0;
47
- _context.next = 3;
37
+ _context.next = 2;
48
38
  return getOrCreateFromArray(client, pendingRecipients, createContact);
49
39
 
50
- case 3:
40
+ case 2:
51
41
  contacts = _context.sent;
52
42
  readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts;
53
43
  readOnlyRecipients = selectedOption === 'readOnly' ? contacts : [];
54
- _context.next = 8;
44
+ _context.next = 7;
55
45
  return client.collection('io.cozy.sharings').createSharedDrive({
56
46
  name: sharedDriveName,
57
47
  description: sharedDriveName,
@@ -59,34 +49,15 @@ export var useSharedDrive = function useSharedDrive(_ref) {
59
49
  readOnlyRecipients: readOnlyRecipients
60
50
  });
61
51
 
62
- case 8:
63
- showAlert({
64
- message: t('SharedDrive.sharedDriveModal.successNotification'),
65
- severity: 'success',
66
- variant: 'filled'
67
- });
68
- onSuccess();
69
- _context.next = 15;
70
- break;
71
-
72
- case 12:
73
- _context.prev = 12;
74
- _context.t0 = _context["catch"](0);
75
- showAlert({
76
- message: t('SharedDrive.sharedDriveModal.errorNotification'),
77
- severity: 'error',
78
- variant: 'filled'
79
- });
80
-
81
- case 15:
52
+ case 7:
82
53
  case "end":
83
54
  return _context.stop();
84
55
  }
85
- }, _callee, null, [[0, 12]]);
56
+ }, _callee);
86
57
  }));
87
58
 
88
59
  return function onCreate() {
89
- return _ref2.apply(this, arguments);
60
+ return _ref.apply(this, arguments);
90
61
  };
91
62
  }();
92
63
 
@@ -2,16 +2,12 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  import { renderHook, act } from '@testing-library/react-hooks';
4
4
  import { useSharedDrive } from './useSharedDrive';
5
- var mockShowAlert = jest.fn();
6
5
  var mockCreateSharedDrive = jest.fn();
7
6
  var mockCollection = jest.fn(function () {
8
7
  return {
9
8
  createSharedDrive: mockCreateSharedDrive
10
9
  };
11
10
  });
12
- var mockT = jest.fn(function (key) {
13
- return key;
14
- });
15
11
  jest.mock('cozy-client', function () {
16
12
  return {
17
13
  useClient: jest.fn(function () {
@@ -22,24 +18,6 @@ jest.mock('cozy-client', function () {
22
18
  })
23
19
  };
24
20
  });
25
- jest.mock('cozy-ui/transpiled/react/providers/Alert', function () {
26
- return {
27
- useAlert: jest.fn(function () {
28
- return {
29
- showAlert: mockShowAlert
30
- };
31
- })
32
- };
33
- });
34
- jest.mock('twake-i18n', function () {
35
- return {
36
- useI18n: jest.fn(function () {
37
- return {
38
- t: mockT
39
- };
40
- })
41
- };
42
- });
43
21
  jest.mock('../../models', function () {
44
22
  return {
45
23
  Contact: {
@@ -60,9 +38,7 @@ describe('useSharedDrive', function () {
60
38
  });
61
39
  it('returns empty initial state', function () {
62
40
  var _renderHook = renderHook(function () {
63
- return useSharedDrive({
64
- onSuccess: jest.fn()
65
- });
41
+ return useSharedDrive();
66
42
  }),
67
43
  result = _renderHook.result;
68
44
 
@@ -72,9 +48,7 @@ describe('useSharedDrive', function () {
72
48
  });
73
49
  it('handleSharedDriveNameChange updates the name', function () {
74
50
  var _renderHook2 = renderHook(function () {
75
- return useSharedDrive({
76
- onSuccess: jest.fn()
77
- });
51
+ return useSharedDrive();
78
52
  }),
79
53
  result = _renderHook2.result;
80
54
 
@@ -87,18 +61,15 @@ describe('useSharedDrive', function () {
87
61
  });
88
62
  expect(result.current.sharedDriveName).toBe('My Drive');
89
63
  });
90
- it('onCreate calls createSharedDrive and onSuccess', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
91
- var onSuccess, _renderHook3, result;
64
+ it('onCreate calls createSharedDrive', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
65
+ var _renderHook3, result;
92
66
 
93
67
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
94
68
  while (1) switch (_context2.prev = _context2.next) {
95
69
  case 0:
96
- onSuccess = jest.fn();
97
70
  mockCreateSharedDrive.mockResolvedValue({});
98
71
  _renderHook3 = renderHook(function () {
99
- return useSharedDrive({
100
- onSuccess: onSuccess
101
- });
72
+ return useSharedDrive();
102
73
  }), result = _renderHook3.result;
103
74
  act(function () {
104
75
  result.current.handleSharedDriveNameChange({
@@ -110,7 +81,7 @@ describe('useSharedDrive', function () {
110
81
  email: 'a@b.c'
111
82
  }]);
112
83
  });
113
- _context2.next = 6;
84
+ _context2.next = 5;
114
85
  return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
115
86
  return _regeneratorRuntime.wrap(function _callee$(_context) {
116
87
  while (1) switch (_context.prev = _context.next) {
@@ -125,7 +96,7 @@ describe('useSharedDrive', function () {
125
96
  }, _callee);
126
97
  })));
127
98
 
128
- case 6:
99
+ case 5:
129
100
  expect(mockCreateSharedDrive).toHaveBeenCalledWith({
130
101
  name: 'My Drive',
131
102
  description: 'My Drive',
@@ -134,55 +105,11 @@ describe('useSharedDrive', function () {
134
105
  }],
135
106
  readOnlyRecipients: []
136
107
  });
137
- expect(mockShowAlert).toHaveBeenCalledWith(expect.objectContaining({
138
- severity: 'success'
139
- }));
140
- expect(onSuccess).toHaveBeenCalledTimes(1);
141
108
 
142
- case 9:
109
+ case 6:
143
110
  case "end":
144
111
  return _context2.stop();
145
112
  }
146
113
  }, _callee2);
147
114
  })));
148
- it('onCreate shows error alert and does not call onSuccess on failure', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
149
- var onSuccess, _renderHook4, result;
150
-
151
- return _regeneratorRuntime.wrap(function _callee4$(_context4) {
152
- while (1) switch (_context4.prev = _context4.next) {
153
- case 0:
154
- onSuccess = jest.fn();
155
- mockCreateSharedDrive.mockRejectedValue(new Error('network error'));
156
- _renderHook4 = renderHook(function () {
157
- return useSharedDrive({
158
- onSuccess: onSuccess
159
- });
160
- }), result = _renderHook4.result;
161
- _context4.next = 5;
162
- return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
163
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
164
- while (1) switch (_context3.prev = _context3.next) {
165
- case 0:
166
- _context3.next = 2;
167
- return result.current.onCreate();
168
-
169
- case 2:
170
- case "end":
171
- return _context3.stop();
172
- }
173
- }, _callee3);
174
- })));
175
-
176
- case 5:
177
- expect(mockShowAlert).toHaveBeenCalledWith(expect.objectContaining({
178
- severity: 'error'
179
- }));
180
- expect(onSuccess).not.toHaveBeenCalled();
181
-
182
- case 7:
183
- case "end":
184
- return _context4.stop();
185
- }
186
- }, _callee4);
187
- })));
188
115
  });
@@ -32,6 +32,8 @@ var WhoHasAccess = function WhoHasAccess(_ref2) {
32
32
  isOwner = _ref2$isOwner === void 0 ? false : _ref2$isOwner,
33
33
  _ref2$isSharedDrive = _ref2.isSharedDrive,
34
34
  isSharedDrive = _ref2$isSharedDrive === void 0 ? false : _ref2$isSharedDrive,
35
+ _ref2$showOwner = _ref2.showOwner,
36
+ showOwner = _ref2$showOwner === void 0 ? true : _ref2$showOwner,
35
37
  recipients = _ref2.recipients,
36
38
  _ref2$recipientsToBeC = _ref2.recipientsToBeConfirmed,
37
39
  recipientsToBeConfirmed = _ref2$recipientsToBeC === void 0 ? [] : _ref2$recipientsToBeC,
@@ -57,7 +59,7 @@ var WhoHasAccess = function WhoHasAccess(_ref2) {
57
59
  onRevokeSelf: onRevokeSelf,
58
60
  permissions: permissions,
59
61
  fadeIn: linkHasBeenJustCreated
60
- }), /*#__PURE__*/React.createElement(OwnerRecipient, {
62
+ }), showOwner && /*#__PURE__*/React.createElement(OwnerRecipient, {
61
63
  recipients: recipients
62
64
  }), /*#__PURE__*/React.createElement(RecipientList, {
63
65
  recipients: recipients,
@@ -75,6 +77,7 @@ var WhoHasAccess = function WhoHasAccess(_ref2) {
75
77
 
76
78
  WhoHasAccess.propTypes = {
77
79
  isOwner: PropTypes.bool,
80
+ showOwner: PropTypes.bool,
78
81
  recipients: PropTypes.array.isRequired,
79
82
  recipientsToBeConfirmed: PropTypes.arrayOf(PropTypes.shape({
80
83
  email: PropTypes.string.isRequired
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-sharing",
3
- "version": "32.3.2",
3
+ "version": "33.0.0",
4
4
  "description": "Provides sharing login for React applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -57,7 +57,7 @@
57
57
  "cozy-device-helper": "^4.0.0",
58
58
  "cozy-intent": "^2.31.1",
59
59
  "cozy-minilog": "^3.10.1",
60
- "cozy-ui": "^138.1.0",
60
+ "cozy-ui": "^139.0.2",
61
61
  "cozy-ui-plus": "^8.0.1",
62
62
  "jest": "30.3.0",
63
63
  "jest-environment-jsdom": "30.3.0",
@@ -73,7 +73,7 @@
73
73
  "cozy-flags": ">=4.8.1",
74
74
  "cozy-intent": ">=2.29.1",
75
75
  "cozy-minilog": ">=3.9.1",
76
- "cozy-ui": ">=138.1.0",
76
+ "cozy-ui": ">=139.0.2",
77
77
  "cozy-ui-plus": ">=6.0.0",
78
78
  "prop-types": ">=15.7.2",
79
79
  "react": ">=16.12.0",
@@ -83,5 +83,5 @@
83
83
  "sideEffects": [
84
84
  "*.css"
85
85
  ],
86
- "gitHead": "5fd20886ef0dfec91783b81bce0ae59d210a0cfa"
86
+ "gitHead": "6276bf5263e77e71944feb505a0aad085e770166"
87
87
  }
@@ -6,7 +6,7 @@ import Button from 'cozy-ui/transpiled/react/Buttons'
6
6
  import { FixedDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
7
7
  import TextField from 'cozy-ui/transpiled/react/TextField'
8
8
  import Typography from 'cozy-ui/transpiled/react/Typography'
9
- import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
9
+ import { useSubmitWithLoader } from 'cozy-ui/transpiled/react/hooks/useSubmitWithLoader'
10
10
  import { useI18n } from 'twake-i18n'
11
11
 
12
12
  import SharedDriveHeader from './SharedDriveHeader'
@@ -21,62 +21,41 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
21
21
  const client = useClient()
22
22
  const { t } = useI18n()
23
23
  const { share, getRecipients, revoke } = useSharingContext()
24
- const { showAlert } = useAlert()
25
24
  const {
26
25
  pendingRecipients,
27
26
  setPendingRecipients,
28
27
  selectedOption,
29
28
  setSelectedOption
30
29
  } = usePendingRecipients()
30
+ const { onSubmit, isLoading } = useSubmitWithLoader()
31
31
 
32
32
  const [driveName, setDriveName] = useState(document.name)
33
- const [isSaving, setIsSaving] = useState(false)
34
33
 
35
34
  const onSave = async () => {
36
- if (isSaving) return
37
- setIsSaving(true)
38
- try {
39
- // We add contacts
40
- const contacts = await getOrCreateFromArray(
41
- client,
42
- pendingRecipients,
43
- contact => client.create('io.cozy.contacts', contact)
44
- )
45
- const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
46
- const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
35
+ // We add contacts
36
+ const contacts = await getOrCreateFromArray(
37
+ client,
38
+ pendingRecipients,
39
+ contact => client.create('io.cozy.contacts', contact)
40
+ )
41
+ const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
42
+ const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
47
43
 
48
- await share({
49
- document: document,
50
- recipients: readWriteRecipients,
51
- readOnlyRecipients,
52
- sharedDrive: true,
53
- openSharing: false
54
- })
55
-
56
- // We rename the shared drive
57
- if (document?.name !== driveName) {
58
- await client.collection('io.cozy.files').update({
59
- ...document,
60
- name: driveName,
61
- _rev: document._rev || document.meta.rev
62
- })
63
- }
64
-
65
- showAlert({
66
- message: t('SharedDrive.editSharedDriveModal.successNotification'),
67
- severity: 'success',
68
- variant: 'filled'
69
- })
44
+ await share({
45
+ document: document,
46
+ recipients: readWriteRecipients,
47
+ readOnlyRecipients,
48
+ sharedDrive: true,
49
+ openSharing: false
50
+ })
70
51
 
71
- onClose()
72
- } catch (_err) {
73
- showAlert({
74
- message: t('SharedDrive.editSharedDriveModal.errorNotification'),
75
- severity: 'error',
76
- variant: 'filled'
52
+ // We rename the shared drive
53
+ if (document?.name !== driveName) {
54
+ await client.collection('io.cozy.files').update({
55
+ ...document,
56
+ name: driveName,
57
+ _rev: document._rev || document.meta.rev
77
58
  })
78
- } finally {
79
- setIsSaving(false)
80
59
  }
81
60
  }
82
61
 
@@ -110,8 +89,8 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
110
89
  {t('Share.contacts.addUsers')}
111
90
  </Typography>
112
91
  <DumbShareByEmail
113
- currentRecipients={[]}
114
92
  documentType="Files"
93
+ currentRecipients={existingRecipients}
115
94
  pendingRecipients={pendingRecipients}
116
95
  onPendingRecipientsChange={setPendingRecipients}
117
96
  selectedOption={selectedOption}
@@ -121,6 +100,7 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
121
100
  <WhoHasAccess
122
101
  isOwner
123
102
  isSharedDrive
103
+ showOwner={false}
124
104
  recipients={existingRecipients}
125
105
  document={document}
126
106
  documentType="Files"
@@ -134,14 +114,29 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
134
114
  className="u-w-100 u-m-1"
135
115
  size="large"
136
116
  onClick={onClose}
117
+ disabled={isLoading}
137
118
  />
138
119
  <Button
139
120
  variant="primary"
140
121
  label={t('SharedDrive.sharedDriveModal.save')}
141
122
  className="u-w-100 u-m-1"
142
123
  size="large"
143
- disabled={isSaving}
144
- onClick={onSave}
124
+ onClick={() =>
125
+ onSubmit({
126
+ submit: onSave,
127
+ success: {
128
+ action: onClose,
129
+ message: t(
130
+ 'SharedDrive.editSharedDriveModal.successNotification'
131
+ )
132
+ },
133
+ error: {
134
+ message: () =>
135
+ t('SharedDrive.editSharedDriveModal.errorNotification')
136
+ }
137
+ })
138
+ }
139
+ busy={isLoading}
145
140
  />
146
141
  </div>
147
142
  </div>
@@ -4,6 +4,7 @@ import React from 'react'
4
4
  import Button from 'cozy-ui/transpiled/react/Buttons'
5
5
  import TextField from 'cozy-ui/transpiled/react/TextField'
6
6
  import Typography from 'cozy-ui/transpiled/react/Typography'
7
+ import { useSubmitWithLoader } from 'cozy-ui/transpiled/react/hooks/useSubmitWithLoader'
7
8
  import { useI18n } from 'twake-i18n'
8
9
 
9
10
  import withLocales from '../../hoc/withLocales'
@@ -21,7 +22,8 @@ export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
21
22
  selectedOption,
22
23
  setSelectedOption,
23
24
  onCreate
24
- } = useSharedDrive({ onSuccess })
25
+ } = useSharedDrive()
26
+ const { onSubmit, isLoading } = useSubmitWithLoader()
25
27
 
26
28
  return (
27
29
  <div>
@@ -55,13 +57,27 @@ export const SharedDriveForm = withLocales(({ onSuccess, onCancel }) => {
55
57
  className="u-w-100 u-m-1"
56
58
  size="large"
57
59
  onClick={onCancel}
60
+ disabled={isLoading}
58
61
  />
59
62
  <Button
60
63
  variant="primary"
61
64
  label={t('SharedDrive.sharedDriveModal.create')}
62
65
  className="u-w-100 u-m-1"
63
66
  size="large"
64
- onClick={onCreate}
67
+ onClick={() =>
68
+ onSubmit({
69
+ submit: onCreate,
70
+ success: {
71
+ action: onSuccess,
72
+ message: t('SharedDrive.sharedDriveModal.successNotification')
73
+ },
74
+ error: {
75
+ message: () =>
76
+ t('SharedDrive.sharedDriveModal.errorNotification')
77
+ }
78
+ })
79
+ }
80
+ busy={isLoading}
65
81
  />
66
82
  </div>
67
83
  </div>
@@ -1,17 +1,13 @@
1
1
  import { useState } from 'react'
2
2
 
3
3
  import { useClient } from 'cozy-client'
4
- import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
5
- import { useI18n } from 'twake-i18n'
6
4
 
7
5
  import { getOrCreateFromArray } from '../../helpers/contacts'
8
6
  import { usePendingRecipients } from '../../hooks/usePendingRecipients'
9
7
  import { Contact } from '../../models'
10
8
 
11
- export const useSharedDrive = ({ onSuccess }) => {
9
+ export const useSharedDrive = () => {
12
10
  const client = useClient()
13
- const { t } = useI18n()
14
- const { showAlert } = useAlert()
15
11
 
16
12
  const [sharedDriveName, setSharedDriveName] = useState('')
17
13
  const {
@@ -28,36 +24,20 @@ export const useSharedDrive = ({ onSuccess }) => {
28
24
  const createContact = contact => client.create(Contact.doctype, contact)
29
25
 
30
26
  const onCreate = async () => {
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
-
40
- await client.collection('io.cozy.sharings').createSharedDrive({
41
- name: sharedDriveName,
42
- description: sharedDriveName,
43
- recipients: readWriteRecipients,
44
- readOnlyRecipients
45
- })
46
-
47
- showAlert({
48
- message: t('SharedDrive.sharedDriveModal.successNotification'),
49
- severity: 'success',
50
- variant: 'filled'
51
- })
52
-
53
- onSuccess()
54
- } catch (_err) {
55
- showAlert({
56
- message: t('SharedDrive.sharedDriveModal.errorNotification'),
57
- severity: 'error',
58
- variant: 'filled'
59
- })
60
- }
27
+ const contacts = await getOrCreateFromArray(
28
+ client,
29
+ pendingRecipients,
30
+ createContact
31
+ )
32
+ const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
33
+ const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
34
+
35
+ await client.collection('io.cozy.sharings').createSharedDrive({
36
+ name: sharedDriveName,
37
+ description: sharedDriveName,
38
+ recipients: readWriteRecipients,
39
+ readOnlyRecipients
40
+ })
61
41
  }
62
42
 
63
43
  return {
@@ -2,12 +2,10 @@ import { renderHook, act } from '@testing-library/react-hooks'
2
2
 
3
3
  import { useSharedDrive } from './useSharedDrive'
4
4
 
5
- const mockShowAlert = jest.fn()
6
5
  const mockCreateSharedDrive = jest.fn()
7
6
  const mockCollection = jest.fn(() => ({
8
7
  createSharedDrive: mockCreateSharedDrive
9
8
  }))
10
- const mockT = jest.fn(key => key)
11
9
 
12
10
  jest.mock('cozy-client', () => ({
13
11
  useClient: jest.fn(() => ({
@@ -16,14 +14,6 @@ jest.mock('cozy-client', () => ({
16
14
  }))
17
15
  }))
18
16
 
19
- jest.mock('cozy-ui/transpiled/react/providers/Alert', () => ({
20
- useAlert: jest.fn(() => ({ showAlert: mockShowAlert }))
21
- }))
22
-
23
- jest.mock('twake-i18n', () => ({
24
- useI18n: jest.fn(() => ({ t: mockT }))
25
- }))
26
-
27
17
  jest.mock('../../models', () => ({
28
18
  Contact: { doctype: 'io.cozy.contacts' }
29
19
  }))
@@ -40,18 +30,14 @@ describe('useSharedDrive', () => {
40
30
  })
41
31
 
42
32
  it('returns empty initial state', () => {
43
- const { result } = renderHook(() =>
44
- useSharedDrive({ onSuccess: jest.fn() })
45
- )
33
+ const { result } = renderHook(() => useSharedDrive())
46
34
  expect(result.current.sharedDriveName).toBe('')
47
35
  expect(result.current.pendingRecipients).toEqual([])
48
36
  expect(result.current.selectedOption).toBe('readWrite')
49
37
  })
50
38
 
51
39
  it('handleSharedDriveNameChange updates the name', () => {
52
- const { result } = renderHook(() =>
53
- useSharedDrive({ onSuccess: jest.fn() })
54
- )
40
+ const { result } = renderHook(() => useSharedDrive())
55
41
  act(() => {
56
42
  result.current.handleSharedDriveNameChange({
57
43
  target: { value: 'My Drive' }
@@ -60,11 +46,10 @@ describe('useSharedDrive', () => {
60
46
  expect(result.current.sharedDriveName).toBe('My Drive')
61
47
  })
62
48
 
63
- it('onCreate calls createSharedDrive and onSuccess', async () => {
64
- const onSuccess = jest.fn()
49
+ it('onCreate calls createSharedDrive', async () => {
65
50
  mockCreateSharedDrive.mockResolvedValue({})
66
51
 
67
- const { result } = renderHook(() => useSharedDrive({ onSuccess }))
52
+ const { result } = renderHook(() => useSharedDrive())
68
53
 
69
54
  act(() => {
70
55
  result.current.handleSharedDriveNameChange({
@@ -83,25 +68,5 @@ describe('useSharedDrive', () => {
83
68
  recipients: [{ email: 'a@b.c' }],
84
69
  readOnlyRecipients: []
85
70
  })
86
- expect(mockShowAlert).toHaveBeenCalledWith(
87
- expect.objectContaining({ severity: 'success' })
88
- )
89
- expect(onSuccess).toHaveBeenCalledTimes(1)
90
- })
91
-
92
- it('onCreate shows error alert and does not call onSuccess on failure', async () => {
93
- const onSuccess = jest.fn()
94
- mockCreateSharedDrive.mockRejectedValue(new Error('network error'))
95
-
96
- const { result } = renderHook(() => useSharedDrive({ onSuccess }))
97
-
98
- await act(async () => {
99
- await result.current.onCreate()
100
- })
101
-
102
- expect(mockShowAlert).toHaveBeenCalledWith(
103
- expect.objectContaining({ severity: 'error' })
104
- )
105
- expect(onSuccess).not.toHaveBeenCalled()
106
71
  })
107
72
  })
@@ -29,6 +29,7 @@ const RecipientWaitingForConfirmationAlert = ({ recipientsToBeConfirmed }) => {
29
29
  const WhoHasAccess = ({
30
30
  isOwner = false,
31
31
  isSharedDrive = false,
32
+ showOwner = true,
32
33
  recipients,
33
34
  recipientsToBeConfirmed = [],
34
35
  document,
@@ -61,7 +62,7 @@ const WhoHasAccess = ({
61
62
  />
62
63
  )}
63
64
 
64
- <OwnerRecipient recipients={recipients} />
65
+ {showOwner && <OwnerRecipient recipients={recipients} />}
65
66
 
66
67
  <RecipientList
67
68
  recipients={recipients}
@@ -82,6 +83,7 @@ const WhoHasAccess = ({
82
83
 
83
84
  WhoHasAccess.propTypes = {
84
85
  isOwner: PropTypes.bool,
86
+ showOwner: PropTypes.bool,
85
87
  recipients: PropTypes.array.isRequired,
86
88
  recipientsToBeConfirmed: PropTypes.arrayOf(
87
89
  PropTypes.shape({