cozy-sharing 8.1.0 → 8.3.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 +22 -0
- package/dist/components/ShareByEmail.js +34 -12
- package/dist/components/ShareByEmail.spec.js +101 -26
- package/dist/components/ShareRecipientsLimitModal.js +38 -0
- package/dist/helpers/recipients.js +30 -1
- package/dist/hooks/useSharingContext.js +8 -0
- package/dist/index.js +1 -0
- package/locales/en.json +5 -0
- package/locales/fr.json +5 -0
- package/package.json +2 -2
- package/src/components/ShareByEmail.jsx +14 -0
- package/src/components/ShareByEmail.spec.jsx +92 -18
- package/src/components/ShareRecipientsLimitModal.jsx +42 -0
- package/src/helpers/recipients.js +26 -0
- package/src/hooks/useSharingContext.jsx +7 -0
- package/src/index.jsx +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
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
|
+
# [8.3.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@8.2.0...cozy-sharing@8.3.0) (2023-07-28)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Limit recipients by document ([f94eaa0](https://github.com/cozy/cozy-libs/commit/f94eaa010e284606dac3fb4f5c599f61e42ccf33))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [8.2.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@8.1.0...cozy-sharing@8.2.0) (2023-07-26)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* Add useSharingContext ([cfe9346](https://github.com/cozy/cozy-libs/commit/cfe93462ce8730973f83d0cf3ef5a69233d67fd6))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# [8.1.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@8.0.1...cozy-sharing@8.1.0) (2023-07-25)
|
|
7
29
|
|
|
8
30
|
|
|
@@ -9,9 +9,11 @@ import { useClient } from 'cozy-client';
|
|
|
9
9
|
import { useI18n } from 'cozy-ui/transpiled/react/I18n';
|
|
10
10
|
import Alerter from 'cozy-ui/transpiled/react/deprecated/Alerter';
|
|
11
11
|
import ShareRecipientsInput from './ShareRecipientsInput';
|
|
12
|
+
import { ShareRecipientsLimitModal } from './ShareRecipientsLimitModal';
|
|
12
13
|
import ShareSubmit from './Sharesubmit';
|
|
13
14
|
import ShareTypeSelect from './Sharetypeselect';
|
|
14
15
|
import { getOrCreateFromArray } from '../helpers/contacts';
|
|
16
|
+
import { hasReachRecipientsLimit } from '../helpers/recipients';
|
|
15
17
|
import { getSuccessMessage } from '../helpers/successMessage';
|
|
16
18
|
import { Group } from '../models';
|
|
17
19
|
import { contactsResponseType, groupsResponseType } from '../propTypes';
|
|
@@ -73,6 +75,11 @@ export var ShareByEmail = function ShareByEmail(_ref) {
|
|
|
73
75
|
selectedOption = _useState6[0],
|
|
74
76
|
setSelectedOption = _useState6[1];
|
|
75
77
|
|
|
78
|
+
var _useState7 = useState(false),
|
|
79
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
80
|
+
showRecipientsLimit = _useState8[0],
|
|
81
|
+
setRecipientsLimit = _useState8[1];
|
|
82
|
+
|
|
76
83
|
var reset = function reset() {
|
|
77
84
|
setRecipients([]);
|
|
78
85
|
setLoading(false);
|
|
@@ -132,12 +139,22 @@ export var ShareByEmail = function ShareByEmail(_ref) {
|
|
|
132
139
|
// we can't use currentRecipients prop in getSuccessMessage because it may use
|
|
133
140
|
// the updated prop to count the new recipients
|
|
134
141
|
recipientsBefore = currentRecipients;
|
|
142
|
+
|
|
143
|
+
if (!hasReachRecipientsLimit(recipientsBefore, recipients)) {
|
|
144
|
+
_context.next = 6;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
setRecipientsLimit(true);
|
|
149
|
+
return _context.abrupt("return");
|
|
150
|
+
|
|
151
|
+
case 6:
|
|
135
152
|
setLoading(true);
|
|
136
|
-
_context.prev =
|
|
137
|
-
_context.next =
|
|
153
|
+
_context.prev = 7;
|
|
154
|
+
_context.next = 10;
|
|
138
155
|
return getOrCreateFromArray(client, recipients, createContact);
|
|
139
156
|
|
|
140
|
-
case
|
|
157
|
+
case 10:
|
|
141
158
|
_contacts = _context.sent;
|
|
142
159
|
readWriteRecipients = [];
|
|
143
160
|
readOnlyRecipients = [];
|
|
@@ -148,7 +165,7 @@ export var ShareByEmail = function ShareByEmail(_ref) {
|
|
|
148
165
|
readWriteRecipients = _contacts;
|
|
149
166
|
}
|
|
150
167
|
|
|
151
|
-
_context.next =
|
|
168
|
+
_context.next = 16;
|
|
152
169
|
return onShare({
|
|
153
170
|
document: document,
|
|
154
171
|
recipients: readWriteRecipients,
|
|
@@ -157,24 +174,24 @@ export var ShareByEmail = function ShareByEmail(_ref) {
|
|
|
157
174
|
openSharing: readWriteRecipients.length > 0
|
|
158
175
|
});
|
|
159
176
|
|
|
160
|
-
case
|
|
177
|
+
case 16:
|
|
161
178
|
Alerter.success(t.apply(void 0, _toConsumableArray(getSuccessMessage(recipientsBefore, _contacts, documentType))));
|
|
162
179
|
reset();
|
|
163
|
-
_context.next =
|
|
180
|
+
_context.next = 25;
|
|
164
181
|
break;
|
|
165
182
|
|
|
166
|
-
case
|
|
167
|
-
_context.prev =
|
|
168
|
-
_context.t0 = _context["catch"](
|
|
183
|
+
case 20:
|
|
184
|
+
_context.prev = 20;
|
|
185
|
+
_context.t0 = _context["catch"](7);
|
|
169
186
|
Alerter.error('Error.generic');
|
|
170
187
|
reset();
|
|
171
188
|
throw _context.t0;
|
|
172
189
|
|
|
173
|
-
case
|
|
190
|
+
case 25:
|
|
174
191
|
case "end":
|
|
175
192
|
return _context.stop();
|
|
176
193
|
}
|
|
177
|
-
}, _callee, null, [[
|
|
194
|
+
}, _callee, null, [[7, 20]]);
|
|
178
195
|
}));
|
|
179
196
|
|
|
180
197
|
return function share() {
|
|
@@ -225,7 +242,12 @@ export var ShareByEmail = function ShareByEmail(_ref) {
|
|
|
225
242
|
onSubmit: share,
|
|
226
243
|
loading: loading,
|
|
227
244
|
disabled: recipients.length === 0
|
|
228
|
-
}))
|
|
245
|
+
})), showRecipientsLimit ? /*#__PURE__*/React.createElement(ShareRecipientsLimitModal, {
|
|
246
|
+
documentName: document.name,
|
|
247
|
+
onConfirm: function onConfirm() {
|
|
248
|
+
return setRecipientsLimit(false);
|
|
249
|
+
}
|
|
250
|
+
}) : null);
|
|
229
251
|
};
|
|
230
252
|
ShareByEmail.propTypes = {
|
|
231
253
|
currentRecipients: PropTypes.arrayOf(PropTypes.object),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
2
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
-
import { render, fireEvent, waitFor } from '@testing-library/react';
|
|
3
|
+
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { act } from 'react-dom/test-utils';
|
|
6
|
+
import flag from 'cozy-flags';
|
|
6
7
|
import { ShareByEmail } from './ShareByEmail';
|
|
7
8
|
import AppLike from '../../test/AppLike';
|
|
8
9
|
jest.mock('../helpers/contacts', function () {
|
|
@@ -12,53 +13,76 @@ jest.mock('../helpers/contacts', function () {
|
|
|
12
13
|
}
|
|
13
14
|
};
|
|
14
15
|
});
|
|
16
|
+
jest.mock('cozy-flags');
|
|
15
17
|
describe('ShareByEmailComponent', function () {
|
|
18
|
+
var defaultDocument = {
|
|
19
|
+
id: 'doc_id',
|
|
20
|
+
name: 'documentName'
|
|
21
|
+
};
|
|
22
|
+
var onShare = jest.fn();
|
|
23
|
+
|
|
24
|
+
var setup = function setup() {
|
|
25
|
+
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
26
|
+
_ref$sharingDesc = _ref.sharingDesc,
|
|
27
|
+
sharingDesc = _ref$sharingDesc === void 0 ? 'test' : _ref$sharingDesc,
|
|
28
|
+
_ref$document = _ref.document,
|
|
29
|
+
document = _ref$document === void 0 ? defaultDocument : _ref$document,
|
|
30
|
+
_ref$currentRecipient = _ref.currentRecipients,
|
|
31
|
+
currentRecipients = _ref$currentRecipient === void 0 ? [] : _ref$currentRecipient;
|
|
32
|
+
|
|
33
|
+
var props = {
|
|
34
|
+
contacts: {
|
|
35
|
+
data: []
|
|
36
|
+
},
|
|
37
|
+
groups: {
|
|
38
|
+
data: []
|
|
39
|
+
},
|
|
40
|
+
documentType: 'Files',
|
|
41
|
+
onShare: onShare,
|
|
42
|
+
document: document,
|
|
43
|
+
sharingDesc: sharingDesc,
|
|
44
|
+
currentRecipients: currentRecipients,
|
|
45
|
+
createContact: jest.fn()
|
|
46
|
+
};
|
|
47
|
+
return render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareByEmail, props)));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
beforeEach(function () {
|
|
51
|
+
jest.clearAllMocks();
|
|
52
|
+
});
|
|
16
53
|
it('shoud call share if submited', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
17
|
-
var
|
|
54
|
+
var sharingDesc;
|
|
18
55
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
19
56
|
while (1) switch (_context.prev = _context.next) {
|
|
20
57
|
case 0:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
groups: {
|
|
27
|
-
data: []
|
|
28
|
-
},
|
|
29
|
-
documentType: 'Files',
|
|
30
|
-
onShare: onShare,
|
|
31
|
-
document: {
|
|
32
|
-
id: 'doc_id'
|
|
33
|
-
},
|
|
34
|
-
sharingDesc: 'test',
|
|
35
|
-
createContact: jest.fn()
|
|
36
|
-
};
|
|
37
|
-
root = render( /*#__PURE__*/React.createElement(AppLike, null, /*#__PURE__*/React.createElement(ShareByEmail, props)));
|
|
58
|
+
sharingDesc = 'test';
|
|
59
|
+
setup({
|
|
60
|
+
sharingDesc: sharingDesc
|
|
61
|
+
});
|
|
38
62
|
act(function () {
|
|
39
|
-
fireEvent.change(
|
|
63
|
+
fireEvent.change(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
40
64
|
target: {
|
|
41
65
|
value: 'quentin@cozycloud.cc'
|
|
42
66
|
}
|
|
43
67
|
});
|
|
44
68
|
});
|
|
45
69
|
act(function () {
|
|
46
|
-
fireEvent.keyPress(
|
|
70
|
+
fireEvent.keyPress(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
47
71
|
key: 'Enter',
|
|
48
72
|
code: 'Enter',
|
|
49
73
|
charCode: 13
|
|
50
74
|
});
|
|
51
75
|
});
|
|
52
76
|
act(function () {
|
|
53
|
-
fireEvent.click(
|
|
77
|
+
fireEvent.click(screen.getByRole('button', {
|
|
54
78
|
name: 'Send'
|
|
55
79
|
}));
|
|
56
80
|
});
|
|
57
|
-
_context.next =
|
|
81
|
+
_context.next = 7;
|
|
58
82
|
return waitFor(function () {
|
|
59
83
|
expect(onShare).toHaveBeenCalledWith({
|
|
60
|
-
description:
|
|
61
|
-
document:
|
|
84
|
+
description: sharingDesc,
|
|
85
|
+
document: defaultDocument,
|
|
62
86
|
openSharing: true,
|
|
63
87
|
readOnlyRecipients: [],
|
|
64
88
|
recipients: [{
|
|
@@ -67,10 +91,61 @@ describe('ShareByEmailComponent', function () {
|
|
|
67
91
|
});
|
|
68
92
|
});
|
|
69
93
|
|
|
70
|
-
case
|
|
94
|
+
case 7:
|
|
71
95
|
case "end":
|
|
72
96
|
return _context.stop();
|
|
73
97
|
}
|
|
74
98
|
}, _callee);
|
|
75
99
|
})));
|
|
100
|
+
it('should alert user when it has reached the recipients limit for a document', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
101
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
102
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
103
|
+
case 0:
|
|
104
|
+
flag.mockReturnValue(2);
|
|
105
|
+
setup({
|
|
106
|
+
currentRecipients: [{
|
|
107
|
+
email: 'alice@gmail.com',
|
|
108
|
+
status: 'pending',
|
|
109
|
+
type: 'two-way'
|
|
110
|
+
}, {
|
|
111
|
+
email: 'bob@gmail.com',
|
|
112
|
+
status: 'pending',
|
|
113
|
+
type: 'two-way'
|
|
114
|
+
}]
|
|
115
|
+
});
|
|
116
|
+
act(function () {
|
|
117
|
+
fireEvent.change(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
118
|
+
target: {
|
|
119
|
+
value: 'john@gmail.com'
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
act(function () {
|
|
124
|
+
fireEvent.keyPress(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
125
|
+
key: 'Enter',
|
|
126
|
+
code: 'Enter',
|
|
127
|
+
charCode: 13
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
act(function () {
|
|
131
|
+
fireEvent.click(screen.getByRole('button', {
|
|
132
|
+
name: 'Send'
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
act(function () {
|
|
136
|
+
fireEvent.click(screen.getByRole('button', {
|
|
137
|
+
name: 'I understand'
|
|
138
|
+
}));
|
|
139
|
+
});
|
|
140
|
+
_context2.next = 8;
|
|
141
|
+
return waitFor(function () {
|
|
142
|
+
expect(onShare).not.toBeCalled();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
case 8:
|
|
146
|
+
case "end":
|
|
147
|
+
return _context2.stop();
|
|
148
|
+
}
|
|
149
|
+
}, _callee2);
|
|
150
|
+
})));
|
|
76
151
|
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import Buttons from 'cozy-ui/transpiled/react/Buttons';
|
|
4
|
+
import { ConfirmDialog } from 'cozy-ui/transpiled/react/CozyDialogs';
|
|
5
|
+
import { useI18n } from 'cozy-ui/transpiled/react/I18n';
|
|
6
|
+
import { computeRecipientsLimit } from '../helpers/recipients';
|
|
7
|
+
/**
|
|
8
|
+
* Alert the user when the number of recipients for sharing a document has reached the limit
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var ShareRecipientsLimitModal = function ShareRecipientsLimitModal(_ref) {
|
|
12
|
+
var documentName = _ref.documentName,
|
|
13
|
+
onConfirm = _ref.onConfirm;
|
|
14
|
+
|
|
15
|
+
var _useI18n = useI18n(),
|
|
16
|
+
t = _useI18n.t;
|
|
17
|
+
|
|
18
|
+
var limit = computeRecipientsLimit();
|
|
19
|
+
return /*#__PURE__*/React.createElement(ConfirmDialog, {
|
|
20
|
+
open: true,
|
|
21
|
+
title: t('ShareRecipientsLimitModal.title'),
|
|
22
|
+
content: t('ShareRecipientsLimitModal.content', {
|
|
23
|
+
documentName: documentName,
|
|
24
|
+
limit: limit
|
|
25
|
+
}),
|
|
26
|
+
actions: /*#__PURE__*/React.createElement(Buttons, {
|
|
27
|
+
label: t('ShareRecipientsLimitModal.confirm'),
|
|
28
|
+
onClick: onConfirm,
|
|
29
|
+
fullWidth: true
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
ShareRecipientsLimitModal.propTypes = {
|
|
35
|
+
/** Name of the document shared */
|
|
36
|
+
documentName: PropTypes.string.isRequired
|
|
37
|
+
};
|
|
38
|
+
export { ShareRecipientsLimitModal };
|
|
@@ -4,6 +4,7 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
4
4
|
|
|
5
5
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
6
6
|
|
|
7
|
+
import flag from 'cozy-flags';
|
|
7
8
|
export var filterAndReworkRecipients = function filterAndReworkRecipients(recipients, previousRecipients) {
|
|
8
9
|
return recipients.filter(function (recipient) {
|
|
9
10
|
return recipient.status !== 'owner';
|
|
@@ -21,4 +22,32 @@ export var filterAndReworkRecipients = function filterAndReworkRecipients(recipi
|
|
|
21
22
|
return recipient;
|
|
22
23
|
});
|
|
23
24
|
};
|
|
24
|
-
export var FADE_IN_DURATION = 600;
|
|
25
|
+
export var FADE_IN_DURATION = 600;
|
|
26
|
+
/**
|
|
27
|
+
* @returns {boolean} the maximum recipients limit by document
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export var computeRecipientsLimit = function computeRecipientsLimit() {
|
|
31
|
+
var flagLimit = flag('sharing.recipients-limit');
|
|
32
|
+
|
|
33
|
+
if (flagLimit !== null) {
|
|
34
|
+
return flagLimit;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return 100;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* @param {object[]} current List of current recipients
|
|
41
|
+
* @param {object[]} next List of next recipients
|
|
42
|
+
* @returns {boolean} whether total number of recipients has reach the limit
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
export var hasReachRecipientsLimit = function hasReachRecipientsLimit(current, next) {
|
|
46
|
+
var limit = computeRecipientsLimit();
|
|
47
|
+
|
|
48
|
+
if (current.length + next.length > limit) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return false;
|
|
53
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import SharingContext from './context';
|
|
|
3
3
|
import withLocales from './withLocales';
|
|
4
4
|
export default SharingProvider;
|
|
5
5
|
export { SharingContext, withLocales };
|
|
6
|
+
export { useSharingContext } from './hooks/useSharingContext';
|
|
6
7
|
export { SharedDocument } from './SharedDocument';
|
|
7
8
|
export { SharedStatus } from './SharedStatus';
|
|
8
9
|
export { SharedBadge } from './SharedBadge';
|
package/locales/en.json
CHANGED
|
@@ -377,5 +377,10 @@
|
|
|
377
377
|
"ConfirmRecipientModal": {
|
|
378
378
|
"title": "%{smart_count} contact waiting for confirmation |||| %{smart_count} contacts waiting for confirmation",
|
|
379
379
|
"intruction": "Verify identity of their Cozy in order to give them access content you shared with them."
|
|
380
|
+
},
|
|
381
|
+
"ShareRecipientsLimitModal": {
|
|
382
|
+
"title": "Problem with your sharing",
|
|
383
|
+
"content": "You cannot share %{documentName} with more than %{limit} members.",
|
|
384
|
+
"confirm": "I understand"
|
|
380
385
|
}
|
|
381
386
|
}
|
package/locales/fr.json
CHANGED
|
@@ -375,5 +375,10 @@
|
|
|
375
375
|
"ConfirmRecipientModal": {
|
|
376
376
|
"title": "%{smart_count} contact en attente de vérification |||| %{smart_count} contacts en attente de vérification",
|
|
377
377
|
"intruction": "Vérifier l'identité de leur Cozy pour leur permettre d'accéder aux éléments que vous avez partagés avec eux."
|
|
378
|
+
},
|
|
379
|
+
"ShareRecipientsLimitModal": {
|
|
380
|
+
"title": "Problème au niveau de votre partage",
|
|
381
|
+
"content": "Vous ne pouvez pas partager %{documentName} à plus de %{limit} membres.",
|
|
382
|
+
"confirm": "J'ai compris"
|
|
378
383
|
}
|
|
379
384
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.0",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"sideEffects": [
|
|
62
62
|
"*.css"
|
|
63
63
|
],
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "fba088d68ddda8b91503ef5ca74e2f7c074b83b7"
|
|
65
65
|
}
|
|
@@ -7,9 +7,11 @@ import { useI18n } from 'cozy-ui/transpiled/react/I18n'
|
|
|
7
7
|
import Alerter from 'cozy-ui/transpiled/react/deprecated/Alerter'
|
|
8
8
|
|
|
9
9
|
import ShareRecipientsInput from './ShareRecipientsInput'
|
|
10
|
+
import { ShareRecipientsLimitModal } from './ShareRecipientsLimitModal'
|
|
10
11
|
import ShareSubmit from './Sharesubmit'
|
|
11
12
|
import ShareTypeSelect from './Sharetypeselect'
|
|
12
13
|
import { getOrCreateFromArray } from '../helpers/contacts'
|
|
14
|
+
import { hasReachRecipientsLimit } from '../helpers/recipients'
|
|
13
15
|
import { getSuccessMessage } from '../helpers/successMessage'
|
|
14
16
|
import { Group } from '../models'
|
|
15
17
|
import { contactsResponseType, groupsResponseType } from '../propTypes'
|
|
@@ -32,6 +34,7 @@ export const ShareByEmail = ({
|
|
|
32
34
|
const [recipients, setRecipients] = useState([])
|
|
33
35
|
const [loading, setLoading] = useState(false)
|
|
34
36
|
const [selectedOption, setSelectedOption] = useState()
|
|
37
|
+
const [showRecipientsLimit, setRecipientsLimit] = useState(false)
|
|
35
38
|
|
|
36
39
|
const reset = () => {
|
|
37
40
|
setRecipients([])
|
|
@@ -84,6 +87,11 @@ export const ShareByEmail = ({
|
|
|
84
87
|
// the updated prop to count the new recipients
|
|
85
88
|
const recipientsBefore = currentRecipients
|
|
86
89
|
|
|
90
|
+
if (hasReachRecipientsLimit(recipientsBefore, recipients)) {
|
|
91
|
+
setRecipientsLimit(true)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
setLoading(true)
|
|
88
96
|
try {
|
|
89
97
|
const contacts = await getOrCreateFromArray(
|
|
@@ -165,6 +173,12 @@ export const ShareByEmail = ({
|
|
|
165
173
|
/>
|
|
166
174
|
</div>
|
|
167
175
|
)}
|
|
176
|
+
{showRecipientsLimit ? (
|
|
177
|
+
<ShareRecipientsLimitModal
|
|
178
|
+
documentName={document.name}
|
|
179
|
+
onConfirm={() => setRecipientsLimit(false)}
|
|
180
|
+
/>
|
|
181
|
+
) : null}
|
|
168
182
|
</div>
|
|
169
183
|
)
|
|
170
184
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { render, fireEvent, waitFor } from '@testing-library/react'
|
|
1
|
+
import { render, fireEvent, waitFor, screen } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { act } from 'react-dom/test-utils'
|
|
4
4
|
|
|
5
|
+
import flag from 'cozy-flags'
|
|
6
|
+
|
|
5
7
|
import { ShareByEmail } from './ShareByEmail'
|
|
6
8
|
import AppLike from '../../test/AppLike'
|
|
7
9
|
|
|
@@ -9,54 +11,126 @@ jest.mock('../helpers/contacts', () => ({
|
|
|
9
11
|
getOrCreateFromArray: (client, recipients) => recipients
|
|
10
12
|
}))
|
|
11
13
|
|
|
14
|
+
jest.mock('cozy-flags')
|
|
15
|
+
|
|
12
16
|
describe('ShareByEmailComponent', () => {
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
const defaultDocument = {
|
|
18
|
+
id: 'doc_id',
|
|
19
|
+
name: 'documentName'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const onShare = jest.fn()
|
|
23
|
+
|
|
24
|
+
const setup = ({
|
|
25
|
+
sharingDesc = 'test',
|
|
26
|
+
document = defaultDocument,
|
|
27
|
+
currentRecipients = []
|
|
28
|
+
} = {}) => {
|
|
15
29
|
const props = {
|
|
16
30
|
contacts: {
|
|
17
31
|
data: []
|
|
18
32
|
},
|
|
19
33
|
groups: { data: [] },
|
|
20
34
|
documentType: 'Files',
|
|
21
|
-
onShare
|
|
22
|
-
document
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
sharingDesc: 'test',
|
|
35
|
+
onShare,
|
|
36
|
+
document,
|
|
37
|
+
sharingDesc,
|
|
38
|
+
currentRecipients,
|
|
26
39
|
createContact: jest.fn()
|
|
27
40
|
}
|
|
28
|
-
|
|
41
|
+
return render(
|
|
29
42
|
<AppLike>
|
|
30
43
|
<ShareByEmail {...props} />
|
|
31
44
|
</AppLike>
|
|
32
45
|
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
jest.clearAllMocks()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('shoud call share if submited', async () => {
|
|
53
|
+
const sharingDesc = 'test'
|
|
54
|
+
|
|
55
|
+
setup({ sharingDesc })
|
|
33
56
|
|
|
34
57
|
act(() => {
|
|
35
|
-
fireEvent.change(
|
|
58
|
+
fireEvent.change(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
36
59
|
target: { value: 'quentin@cozycloud.cc' }
|
|
37
60
|
})
|
|
38
61
|
})
|
|
39
62
|
|
|
40
63
|
act(() => {
|
|
41
|
-
fireEvent.keyPress(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
64
|
+
fireEvent.keyPress(
|
|
65
|
+
screen.getByPlaceholderText('Add contacts or groups'),
|
|
66
|
+
{
|
|
67
|
+
key: 'Enter',
|
|
68
|
+
code: 'Enter',
|
|
69
|
+
charCode: 13
|
|
70
|
+
}
|
|
71
|
+
)
|
|
46
72
|
})
|
|
47
73
|
|
|
48
74
|
act(() => {
|
|
49
|
-
fireEvent.click(
|
|
75
|
+
fireEvent.click(screen.getByRole('button', { name: 'Send' }))
|
|
50
76
|
})
|
|
51
77
|
|
|
52
78
|
await waitFor(() => {
|
|
53
79
|
expect(onShare).toHaveBeenCalledWith({
|
|
54
|
-
description:
|
|
55
|
-
document:
|
|
80
|
+
description: sharingDesc,
|
|
81
|
+
document: defaultDocument,
|
|
56
82
|
openSharing: true,
|
|
57
83
|
readOnlyRecipients: [],
|
|
58
84
|
recipients: [{ email: 'quentin@cozycloud.cc' }]
|
|
59
85
|
})
|
|
60
86
|
})
|
|
61
87
|
})
|
|
88
|
+
|
|
89
|
+
it('should alert user when it has reached the recipients limit for a document', async () => {
|
|
90
|
+
flag.mockReturnValue(2)
|
|
91
|
+
|
|
92
|
+
setup({
|
|
93
|
+
currentRecipients: [
|
|
94
|
+
{
|
|
95
|
+
email: 'alice@gmail.com',
|
|
96
|
+
status: 'pending',
|
|
97
|
+
type: 'two-way'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
email: 'bob@gmail.com',
|
|
101
|
+
status: 'pending',
|
|
102
|
+
type: 'two-way'
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
act(() => {
|
|
108
|
+
fireEvent.change(screen.getByPlaceholderText('Add contacts or groups'), {
|
|
109
|
+
target: { value: 'john@gmail.com' }
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
act(() => {
|
|
114
|
+
fireEvent.keyPress(
|
|
115
|
+
screen.getByPlaceholderText('Add contacts or groups'),
|
|
116
|
+
{
|
|
117
|
+
key: 'Enter',
|
|
118
|
+
code: 'Enter',
|
|
119
|
+
charCode: 13
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
act(() => {
|
|
125
|
+
fireEvent.click(screen.getByRole('button', { name: 'Send' }))
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
act(() => {
|
|
129
|
+
fireEvent.click(screen.getByRole('button', { name: 'I understand' }))
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
await waitFor(() => {
|
|
133
|
+
expect(onShare).not.toBeCalled()
|
|
134
|
+
})
|
|
135
|
+
})
|
|
62
136
|
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import Buttons from 'cozy-ui/transpiled/react/Buttons'
|
|
5
|
+
import { ConfirmDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
|
|
6
|
+
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
|
|
7
|
+
|
|
8
|
+
import { computeRecipientsLimit } from '../helpers/recipients'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Alert the user when the number of recipients for sharing a document has reached the limit
|
|
12
|
+
*/
|
|
13
|
+
const ShareRecipientsLimitModal = ({ documentName, onConfirm }) => {
|
|
14
|
+
const { t } = useI18n()
|
|
15
|
+
|
|
16
|
+
const limit = computeRecipientsLimit()
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<ConfirmDialog
|
|
20
|
+
open
|
|
21
|
+
title={t('ShareRecipientsLimitModal.title')}
|
|
22
|
+
content={t('ShareRecipientsLimitModal.content', {
|
|
23
|
+
documentName,
|
|
24
|
+
limit
|
|
25
|
+
})}
|
|
26
|
+
actions={
|
|
27
|
+
<Buttons
|
|
28
|
+
label={t('ShareRecipientsLimitModal.confirm')}
|
|
29
|
+
onClick={onConfirm}
|
|
30
|
+
fullWidth
|
|
31
|
+
/>
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ShareRecipientsLimitModal.propTypes = {
|
|
38
|
+
/** Name of the document shared */
|
|
39
|
+
documentName: PropTypes.string.isRequired
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { ShareRecipientsLimitModal }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import flag from 'cozy-flags'
|
|
2
|
+
|
|
1
3
|
export const filterAndReworkRecipients = (recipients, previousRecipients) => {
|
|
2
4
|
return recipients
|
|
3
5
|
.filter(recipient => recipient.status !== 'owner')
|
|
@@ -19,3 +21,27 @@ export const filterAndReworkRecipients = (recipients, previousRecipients) => {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export const FADE_IN_DURATION = 600
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @returns {boolean} the maximum recipients limit by document
|
|
27
|
+
*/
|
|
28
|
+
export const computeRecipientsLimit = () => {
|
|
29
|
+
const flagLimit = flag('sharing.recipients-limit')
|
|
30
|
+
if (flagLimit !== null) {
|
|
31
|
+
return flagLimit
|
|
32
|
+
}
|
|
33
|
+
return 100
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {object[]} current List of current recipients
|
|
38
|
+
* @param {object[]} next List of next recipients
|
|
39
|
+
* @returns {boolean} whether total number of recipients has reach the limit
|
|
40
|
+
*/
|
|
41
|
+
export const hasReachRecipientsLimit = (current, next) => {
|
|
42
|
+
const limit = computeRecipientsLimit()
|
|
43
|
+
if (current.length + next.length > limit) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
return false
|
|
47
|
+
}
|
package/src/index.jsx
CHANGED
|
@@ -6,6 +6,7 @@ export default SharingProvider
|
|
|
6
6
|
|
|
7
7
|
export { SharingContext, withLocales }
|
|
8
8
|
|
|
9
|
+
export { useSharingContext } from './hooks/useSharingContext'
|
|
9
10
|
export { SharedDocument } from './SharedDocument'
|
|
10
11
|
export { SharedStatus } from './SharedStatus'
|
|
11
12
|
export { SharedBadge } from './SharedBadge'
|