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 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 = 4;
137
- _context.next = 7;
153
+ _context.prev = 7;
154
+ _context.next = 10;
138
155
  return getOrCreateFromArray(client, recipients, createContact);
139
156
 
140
- case 7:
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 = 13;
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 13:
177
+ case 16:
161
178
  Alerter.success(t.apply(void 0, _toConsumableArray(getSuccessMessage(recipientsBefore, _contacts, documentType))));
162
179
  reset();
163
- _context.next = 22;
180
+ _context.next = 25;
164
181
  break;
165
182
 
166
- case 17:
167
- _context.prev = 17;
168
- _context.t0 = _context["catch"](4);
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 22:
190
+ case 25:
174
191
  case "end":
175
192
  return _context.stop();
176
193
  }
177
- }, _callee, null, [[4, 17]]);
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 onShare, props, root;
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
- onShare = jest.fn();
22
- props = {
23
- contacts: {
24
- data: []
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(root.getByPlaceholderText('Add contacts or groups'), {
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(root.getByPlaceholderText('Add contacts or groups'), {
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(root.getByRole('button', {
77
+ fireEvent.click(screen.getByRole('button', {
54
78
  name: 'Send'
55
79
  }));
56
80
  });
57
- _context.next = 8;
81
+ _context.next = 7;
58
82
  return waitFor(function () {
59
83
  expect(onShare).toHaveBeenCalledWith({
60
- description: props.sharingDesc,
61
- document: props.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 8:
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
+ };
@@ -0,0 +1,8 @@
1
+ import { useContext } from 'react';
2
+ import SharingContext from '../context';
3
+
4
+ var useSharingContext = function useSharingContext() {
5
+ return useContext(SharingContext);
6
+ };
7
+
8
+ export { useSharingContext };
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.1.0",
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": "96da95e604fb54d72ce03b220cf91e112f8fb5f1"
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
- it('shoud call share if submited', async () => {
14
- const onShare = jest.fn()
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: onShare,
22
- document: {
23
- id: 'doc_id'
24
- },
25
- sharingDesc: 'test',
35
+ onShare,
36
+ document,
37
+ sharingDesc,
38
+ currentRecipients,
26
39
  createContact: jest.fn()
27
40
  }
28
- const root = render(
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(root.getByPlaceholderText('Add contacts or groups'), {
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(root.getByPlaceholderText('Add contacts or groups'), {
42
- key: 'Enter',
43
- code: 'Enter',
44
- charCode: 13
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(root.getByRole('button', { name: 'Send' }))
75
+ fireEvent.click(screen.getByRole('button', { name: 'Send' }))
50
76
  })
51
77
 
52
78
  await waitFor(() => {
53
79
  expect(onShare).toHaveBeenCalledWith({
54
- description: props.sharingDesc,
55
- document: props.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
+ }
@@ -0,0 +1,7 @@
1
+ import { useContext } from 'react'
2
+
3
+ import SharingContext from '../context'
4
+
5
+ const useSharingContext = () => useContext(SharingContext)
6
+
7
+ export { useSharingContext }
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'