cozy-sharing 31.0.2 → 31.2.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 +30 -0
- package/dist/components/FederatedFolder/DumbFederatedFolderModal.js +15 -16
- package/dist/components/FederatedFolder/FederatedFolderModal.js +78 -103
- package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +102 -292
- package/dist/components/Recipient/GroupRecipientPermissions.js +15 -11
- package/dist/components/Recipient/LinkRecipient.js +15 -11
- package/dist/components/Recipient/LinkRecipientLite.js +1 -1
- package/dist/components/Recipient/LinkRecipientPermissions.js +2 -1
- package/dist/components/Recipient/MemberRecipient.spec.js +8 -10
- package/dist/components/Recipient/MemberRecipientLite.js +1 -1
- package/dist/components/Recipient/MemberRecipientPermissions.js +16 -12
- package/dist/components/Recipient/MemberRecipientPermissions.spec.js +62 -50
- package/dist/components/Recipient/RecipientConfirm.js +0 -5
- package/dist/components/ShareAutosuggest.js +9 -4
- package/dist/components/ShareByEmail.js +29 -274
- package/dist/components/ShareByEmail.spec.js +52 -230
- package/dist/components/ShareByLink.js +1 -3
- package/dist/components/ShareDialogCozyToCozy.js +169 -35
- package/dist/components/ShareDialogCozyToCozy.spec.js +123 -36
- package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +13 -3
- package/dist/components/ShareModal/SharingDetailsModal.js +0 -5
- package/dist/components/ShareRecipientsInput.js +6 -3
- package/dist/components/SharedDrive/SharedDriveForm.js +17 -25
- package/dist/components/SharedDrive/SharedDriveModal.js +1 -1
- package/dist/components/SharedDrive/SharedDriveRecipientPermissions.js +15 -10
- package/dist/components/SharedDrive/useSharedDrive.js +33 -57
- package/dist/components/SharedDrive/useSharedDrive.spec.js +29 -93
- package/dist/components/SharedFolder/DumbBatchSharedFolderModal.js +15 -26
- package/dist/components/Sharetypeselect.js +85 -90
- package/dist/hooks/usePendingRecipients.js +20 -0
- package/dist/hooks/usePendingRecipients.spec.js +30 -0
- package/dist/styles/autosuggest.styl +8 -2
- package/dist/styles/share.styl +0 -39
- package/dist/stylesheet.css +8 -36
- package/locales/en.json +14 -44
- package/locales/fr.json +14 -44
- package/locales/ru.json +14 -44
- package/locales/vi.json +14 -42
- package/package.json +2 -2
- package/src/components/FederatedFolder/DumbFederatedFolderModal.jsx +14 -15
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +50 -67
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +63 -186
- package/src/components/Recipient/GroupRecipientPermissions.jsx +15 -13
- package/src/components/Recipient/LinkRecipient.jsx +9 -9
- package/src/components/Recipient/LinkRecipientLite.jsx +1 -3
- package/src/components/Recipient/LinkRecipientPermissions.jsx +2 -1
- package/src/components/Recipient/MemberRecipient.spec.jsx +4 -6
- package/src/components/Recipient/MemberRecipientLite.jsx +2 -2
- package/src/components/Recipient/MemberRecipientPermissions.jsx +16 -21
- package/src/components/Recipient/MemberRecipientPermissions.spec.jsx +21 -23
- package/src/components/ShareAutosuggest.jsx +7 -2
- package/src/components/ShareByEmail.jsx +35 -186
- package/src/components/ShareByEmail.spec.jsx +22 -173
- package/src/components/ShareByLink.jsx +1 -7
- package/src/components/ShareDialogCozyToCozy.jsx +171 -38
- package/src/components/ShareDialogCozyToCozy.spec.jsx +67 -1
- package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +11 -1
- package/src/components/ShareRecipientsInput.jsx +5 -2
- package/src/components/SharedDrive/SharedDriveForm.jsx +16 -25
- package/src/components/SharedDrive/SharedDriveModal.jsx +1 -1
- package/src/components/SharedDrive/SharedDriveRecipientPermissions.jsx +15 -17
- package/src/components/SharedDrive/useSharedDrive.js +24 -50
- package/src/components/SharedDrive/useSharedDrive.spec.js +19 -67
- package/src/components/SharedFolder/DumbBatchSharedFolderModal.jsx +15 -29
- package/src/components/Sharetypeselect.jsx +75 -58
- package/src/hooks/usePendingRecipients.js +13 -0
- package/src/hooks/usePendingRecipients.spec.js +21 -0
- package/src/styles/autosuggest.styl +8 -2
- package/src/styles/share.styl +0 -39
- package/dist/components/Recipient/actions/revokeGroup.js +0 -42
- package/dist/components/Recipient/actions/revokeMember.js +0 -42
- package/dist/components/Recipient/actions/revokeSharedDriveMember.js +0 -41
- package/dist/components/SharedDrive/helpers.js +0 -102
- package/dist/components/SharedDrive/helpers.spec.js +0 -227
- package/dist/components/Sharesubmit.js +0 -28
- package/src/components/Recipient/actions/revokeGroup.js +0 -42
- package/src/components/Recipient/actions/revokeMember.js +0 -42
- package/src/components/Recipient/actions/revokeSharedDriveMember.js +0 -41
- package/src/components/SharedDrive/helpers.js +0 -108
- package/src/components/SharedDrive/helpers.spec.js +0 -177
- package/src/components/Sharesubmit.jsx +0 -31
|
@@ -73,7 +73,7 @@ describe('MemberRecipient component', () => {
|
|
|
73
73
|
const onRevoke = jest.fn()
|
|
74
74
|
const onRevokeSelf = jest.fn()
|
|
75
75
|
|
|
76
|
-
const {
|
|
76
|
+
const { getByLabelText } = setup({
|
|
77
77
|
instance: 'foo.mycozy.cloud',
|
|
78
78
|
status: 'ready',
|
|
79
79
|
type: 'two-way',
|
|
@@ -82,8 +82,7 @@ describe('MemberRecipient component', () => {
|
|
|
82
82
|
onRevokeSelf
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
fireEvent.click(
|
|
86
|
-
fireEvent.click(getByText('Remove me from sharing'))
|
|
85
|
+
fireEvent.click(getByLabelText('Remove from sharing'))
|
|
87
86
|
expect(onRevoke).not.toHaveBeenCalled()
|
|
88
87
|
expect(onRevokeSelf).toHaveBeenCalled()
|
|
89
88
|
})
|
|
@@ -92,7 +91,7 @@ describe('MemberRecipient component', () => {
|
|
|
92
91
|
const onRevoke = jest.fn()
|
|
93
92
|
const onRevokeSelf = jest.fn()
|
|
94
93
|
|
|
95
|
-
const {
|
|
94
|
+
const { getByLabelText } = setup({
|
|
96
95
|
instance: 'foo.mycozy.cloud',
|
|
97
96
|
status: 'ready',
|
|
98
97
|
type: 'two-way',
|
|
@@ -102,8 +101,7 @@ describe('MemberRecipient component', () => {
|
|
|
102
101
|
onRevokeSelf
|
|
103
102
|
})
|
|
104
103
|
|
|
105
|
-
fireEvent.click(
|
|
106
|
-
fireEvent.click(getByText('Remove from sharing'))
|
|
104
|
+
fireEvent.click(getByLabelText('Remove from sharing'))
|
|
107
105
|
expect(onRevoke).toHaveBeenCalled()
|
|
108
106
|
expect(onRevokeSelf).not.toHaveBeenCalled()
|
|
109
107
|
})
|
|
@@ -44,8 +44,8 @@ const MemberRecipientLite = ({ recipient, isOwner, ...props }) => {
|
|
|
44
44
|
/>
|
|
45
45
|
<Typography className="u-flex-shrink-0" variant="body2">
|
|
46
46
|
{recipientOwner
|
|
47
|
-
? t(`Share.status.${recipient.status}`)
|
|
48
|
-
: t(`Share.type.${recipient.type ?? 'one-way'}`)
|
|
47
|
+
? t(`Share.status.${recipient.status}`)
|
|
48
|
+
: t(`Share.type.${recipient.type ?? 'one-way'}`)}
|
|
49
49
|
</Typography>
|
|
50
50
|
</ListItem>
|
|
51
51
|
)
|
|
@@ -3,17 +3,16 @@ import React, { useState, useRef, useCallback } from 'react'
|
|
|
3
3
|
import { useClient } from 'cozy-client'
|
|
4
4
|
import minilog from 'cozy-minilog'
|
|
5
5
|
import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
|
|
6
|
-
import {
|
|
7
|
-
makeActions,
|
|
8
|
-
divider
|
|
9
|
-
} from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
|
|
6
|
+
import { makeActions } from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
|
|
10
7
|
import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
|
|
8
|
+
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
9
|
+
import IconButton from 'cozy-ui/transpiled/react/IconButton'
|
|
10
|
+
import CrossCircleOutlineIcon from 'cozy-ui/transpiled/react/Icons/CrossCircleOutline'
|
|
11
11
|
import Spinner from 'cozy-ui/transpiled/react/Spinner'
|
|
12
12
|
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
13
13
|
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
14
14
|
import { useI18n } from 'twake-i18n'
|
|
15
15
|
|
|
16
|
-
import { revokeMember } from './actions/revokeMember'
|
|
17
16
|
import { setReadOnlySharedPermission } from './actions/setReadOnlySharedPermission'
|
|
18
17
|
import { setReadWriteSharedPermission } from './actions/setReadWriteSharedPermission'
|
|
19
18
|
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
@@ -22,7 +21,6 @@ const log = minilog('MemberRecipientPermissions')
|
|
|
22
21
|
|
|
23
22
|
const MemberRecipientPermissions = ({
|
|
24
23
|
isOwner,
|
|
25
|
-
isSharedDrive,
|
|
26
24
|
status,
|
|
27
25
|
instance,
|
|
28
26
|
type,
|
|
@@ -100,20 +98,11 @@ const MemberRecipientPermissions = ({
|
|
|
100
98
|
)
|
|
101
99
|
|
|
102
100
|
const actions = makeActions(
|
|
103
|
-
[
|
|
104
|
-
setReadOnlySharedPermission,
|
|
105
|
-
setReadWriteSharedPermission,
|
|
106
|
-
divider,
|
|
107
|
-
revokeMember
|
|
108
|
-
],
|
|
101
|
+
[setReadOnlySharedPermission, setReadWriteSharedPermission],
|
|
109
102
|
{
|
|
110
|
-
client,
|
|
111
103
|
t,
|
|
112
104
|
type: type ?? 'one-way',
|
|
113
|
-
|
|
114
|
-
isSharedDrive,
|
|
115
|
-
setType,
|
|
116
|
-
handleRevocation
|
|
105
|
+
setType
|
|
117
106
|
}
|
|
118
107
|
)
|
|
119
108
|
|
|
@@ -121,9 +110,7 @@ const MemberRecipientPermissions = ({
|
|
|
121
110
|
<div className={className}>
|
|
122
111
|
{revoking && <Spinner />}
|
|
123
112
|
{!shouldShowMenu && !revoking && (
|
|
124
|
-
<Typography variant="body2">
|
|
125
|
-
{t(`Share.status.${status}`).toLowerCase()}
|
|
126
|
-
</Typography>
|
|
113
|
+
<Typography variant="body2">{t(`Share.status.${status}`)}</Typography>
|
|
127
114
|
)}
|
|
128
115
|
{shouldShowMenu && (
|
|
129
116
|
<>
|
|
@@ -134,7 +121,7 @@ const MemberRecipientPermissions = ({
|
|
|
134
121
|
onClick={toggleMenu}
|
|
135
122
|
textVariant="body2"
|
|
136
123
|
>
|
|
137
|
-
{t(`Share.type.${type}`)
|
|
124
|
+
{t(`Share.type.${type}`)}
|
|
138
125
|
</DropdownButton>
|
|
139
126
|
<ActionsMenu
|
|
140
127
|
ref={buttonRef}
|
|
@@ -143,6 +130,14 @@ const MemberRecipientPermissions = ({
|
|
|
143
130
|
autoClose
|
|
144
131
|
onClose={hideMenu}
|
|
145
132
|
/>
|
|
133
|
+
<IconButton
|
|
134
|
+
onClick={handleRevocation}
|
|
135
|
+
size="small"
|
|
136
|
+
className="u-ml-half"
|
|
137
|
+
aria-label={t('Share.members.revoke')}
|
|
138
|
+
>
|
|
139
|
+
<Icon icon={CrossCircleOutlineIcon} />
|
|
140
|
+
</IconButton>
|
|
146
141
|
</>
|
|
147
142
|
)}
|
|
148
143
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, fireEvent, screen,
|
|
1
|
+
import { render, fireEvent, screen, waitFor } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import { createMockClient } from 'cozy-client'
|
|
@@ -74,16 +74,16 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
74
74
|
|
|
75
75
|
it('should render the current permission type', () => {
|
|
76
76
|
setup()
|
|
77
|
-
expect(screen.
|
|
77
|
+
expect(screen.getByRole('button', { name: 'Editor' })).toBeInTheDocument()
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
it('should call updateSharingMemberType when changing to one-way', async () => {
|
|
81
81
|
mockUpdateSharingMemberType.mockResolvedValue(undefined)
|
|
82
82
|
|
|
83
|
-
const {
|
|
83
|
+
const { getByRole } = setup({ type: 'two-way' })
|
|
84
84
|
|
|
85
|
-
fireEvent.click(
|
|
86
|
-
fireEvent.click(
|
|
85
|
+
fireEvent.click(getByRole('button', { name: 'Editor' }))
|
|
86
|
+
fireEvent.click(getByRole('menuitem', { name: 'Viewer' }))
|
|
87
87
|
|
|
88
88
|
expect(mockUpdateSharingMemberType).toHaveBeenCalledWith(
|
|
89
89
|
'sharing-123',
|
|
@@ -95,10 +95,10 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
95
95
|
it('should call updateSharingMemberType when changing to two-way', async () => {
|
|
96
96
|
mockUpdateSharingMemberType.mockResolvedValue(undefined)
|
|
97
97
|
|
|
98
|
-
const {
|
|
98
|
+
const { getByRole } = setup({ type: 'one-way' })
|
|
99
99
|
|
|
100
|
-
fireEvent.click(
|
|
101
|
-
fireEvent.click(
|
|
100
|
+
fireEvent.click(getByRole('button', { name: 'Viewer' }))
|
|
101
|
+
fireEvent.click(getByRole('menuitem', { name: 'Editor' }))
|
|
102
102
|
|
|
103
103
|
expect(mockUpdateSharingMemberType).toHaveBeenCalledWith(
|
|
104
104
|
'sharing-123',
|
|
@@ -110,12 +110,10 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
110
110
|
it('should show error alert when updateSharingMemberType fails', async () => {
|
|
111
111
|
mockUpdateSharingMemberType.mockRejectedValue(new Error('Network error'))
|
|
112
112
|
|
|
113
|
-
const {
|
|
113
|
+
const { getByRole } = setup({ type: 'two-way' })
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
fireEvent.click(getByText('Can view'))
|
|
118
|
-
})
|
|
115
|
+
fireEvent.click(getByRole('button', { name: 'Editor' }))
|
|
116
|
+
fireEvent.click(getByRole('menuitem', { name: 'Viewer' }))
|
|
119
117
|
|
|
120
118
|
await waitFor(() => {
|
|
121
119
|
expect(mockShowAlert).toHaveBeenCalledWith({
|
|
@@ -130,36 +128,36 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
130
128
|
it('should not call updateSharingMemberType when selecting same type', async () => {
|
|
131
129
|
mockUpdateSharingMemberType.mockResolvedValue(undefined)
|
|
132
130
|
|
|
133
|
-
const {
|
|
131
|
+
const { getByRole } = setup({ type: 'two-way' })
|
|
134
132
|
|
|
135
|
-
fireEvent.click(
|
|
136
|
-
fireEvent.click(
|
|
133
|
+
fireEvent.click(getByRole('button', { name: 'Editor' }))
|
|
134
|
+
fireEvent.click(getByRole('menuitem', { name: 'Editor' }))
|
|
137
135
|
|
|
138
136
|
expect(mockUpdateSharingMemberType).not.toHaveBeenCalled()
|
|
139
137
|
})
|
|
140
138
|
|
|
141
139
|
it('should not render menu when user is not owner and not the shared drive contact', () => {
|
|
142
|
-
const {
|
|
140
|
+
const { queryByRole } = setup({
|
|
143
141
|
isOwner: false,
|
|
144
142
|
instance: 'http://other-cozy.local:8080'
|
|
145
143
|
})
|
|
146
144
|
|
|
147
|
-
expect(
|
|
148
|
-
expect(
|
|
145
|
+
expect(queryByRole('button', { name: 'Editor' })).not.toBeInTheDocument()
|
|
146
|
+
expect(queryByRole('button', { name: 'Viewer' })).not.toBeInTheDocument()
|
|
149
147
|
})
|
|
150
148
|
|
|
151
149
|
it('should render menu for owner', () => {
|
|
152
|
-
const {
|
|
150
|
+
const { getByRole } = setup({ isOwner: true })
|
|
153
151
|
|
|
154
|
-
expect(
|
|
152
|
+
expect(getByRole('button', { name: 'Editor' })).toBeInTheDocument()
|
|
155
153
|
})
|
|
156
154
|
|
|
157
155
|
it('should render menu for the user themselves', () => {
|
|
158
|
-
const {
|
|
156
|
+
const { getByRole } = setup({
|
|
159
157
|
isOwner: false,
|
|
160
158
|
instance: 'http://cozy.local:8080'
|
|
161
159
|
})
|
|
162
160
|
|
|
163
|
-
expect(
|
|
161
|
+
expect(getByRole('button', { name: 'Editor' })).toBeInTheDocument()
|
|
164
162
|
})
|
|
165
163
|
})
|
|
@@ -25,7 +25,8 @@ const ShareAutocomplete = ({
|
|
|
25
25
|
recipients,
|
|
26
26
|
onPick,
|
|
27
27
|
onRemove,
|
|
28
|
-
placeholder
|
|
28
|
+
placeholder,
|
|
29
|
+
endAdornment
|
|
29
30
|
}) => {
|
|
30
31
|
const [inputValue, setInputValue] = useState('')
|
|
31
32
|
const [suggestions, setSuggestions] = useState([])
|
|
@@ -180,6 +181,9 @@ const ShareAutocomplete = ({
|
|
|
180
181
|
{loading && isLoadingDisplayed ? (
|
|
181
182
|
<Spinner color="var(--primaryColor)" />
|
|
182
183
|
) : null}
|
|
184
|
+
{endAdornment ? (
|
|
185
|
+
<div className={styles['endAdornment']}>{endAdornment}</div>
|
|
186
|
+
) : null}
|
|
183
187
|
</div>
|
|
184
188
|
)
|
|
185
189
|
|
|
@@ -223,7 +227,8 @@ ShareAutocomplete.propTypes = {
|
|
|
223
227
|
recipients: PropTypes.array.isRequired,
|
|
224
228
|
onPick: PropTypes.func.isRequired,
|
|
225
229
|
onRemove: PropTypes.func.isRequired,
|
|
226
|
-
placeholder: PropTypes.string
|
|
230
|
+
placeholder: PropTypes.string,
|
|
231
|
+
endAdornment: PropTypes.node
|
|
227
232
|
}
|
|
228
233
|
|
|
229
234
|
export default ShareAutocomplete
|
|
@@ -1,167 +1,43 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React
|
|
2
|
+
import React from 'react'
|
|
3
3
|
|
|
4
|
-
import { useClient } from 'cozy-client'
|
|
5
4
|
import flag from 'cozy-flags'
|
|
6
|
-
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
7
5
|
import { useI18n } from 'twake-i18n'
|
|
8
6
|
|
|
9
7
|
import ShareRecipientsInput from './ShareRecipientsInput'
|
|
10
|
-
import { ShareRecipientsLimitModal } from './ShareRecipientsLimitModal'
|
|
11
|
-
import ShareSubmit from './Sharesubmit'
|
|
12
8
|
import ShareTypeSelect from './Sharetypeselect'
|
|
13
|
-
import { getOrCreateFromArray } from '../helpers/contacts'
|
|
14
9
|
import {
|
|
15
10
|
mergeRecipients,
|
|
16
|
-
spreadGroupAndMergeRecipients
|
|
17
|
-
hasReachRecipientsLimit
|
|
11
|
+
spreadGroupAndMergeRecipients
|
|
18
12
|
} from '../helpers/recipients'
|
|
19
|
-
import { getSuccessMessage, getErrorMessage } from '../helpers/share'
|
|
20
13
|
import { isReadOnlySharing } from '../state'
|
|
21
14
|
import styles from '../styles/share.styl'
|
|
22
15
|
|
|
23
16
|
export const ShareByEmail = ({
|
|
24
17
|
document,
|
|
25
|
-
sharingDesc,
|
|
26
|
-
onShare,
|
|
27
|
-
createContact,
|
|
28
18
|
documentType,
|
|
29
19
|
currentRecipients,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
20
|
+
pendingRecipients,
|
|
21
|
+
onPendingRecipientsChange,
|
|
22
|
+
selectedOption,
|
|
23
|
+
onSelectedOptionChange,
|
|
24
|
+
sharing
|
|
34
25
|
}) => {
|
|
35
|
-
const client = useClient()
|
|
36
26
|
const { t } = useI18n()
|
|
37
|
-
const { showAlert } = useAlert()
|
|
38
27
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const [showRecipientsLimit, setRecipientsLimit] = useState(false)
|
|
45
|
-
|
|
46
|
-
const reset = () => {
|
|
47
|
-
setSelectedOption('readWrite')
|
|
48
|
-
setRecipients([])
|
|
49
|
-
setLoading(false)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const onChange = value => {
|
|
53
|
-
setSelectedOption(value)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const onRecipientPick = async recipient => {
|
|
57
|
-
// In federated mode, directly share with the recipient with readWrite access
|
|
58
|
-
if (isFederatedMode) {
|
|
59
|
-
setLoading(true)
|
|
60
|
-
try {
|
|
61
|
-
const contacts = await getOrCreateFromArray(
|
|
62
|
-
client,
|
|
63
|
-
[recipient],
|
|
64
|
-
createContact
|
|
65
|
-
)
|
|
66
|
-
await onShare({
|
|
67
|
-
document,
|
|
68
|
-
recipients: contacts,
|
|
69
|
-
readOnlyRecipients: [],
|
|
70
|
-
description: sharingDesc,
|
|
71
|
-
openSharing: false,
|
|
72
|
-
sharedDrive: true
|
|
73
|
-
})
|
|
74
|
-
} catch (_err) {
|
|
75
|
-
if (showNotifications) {
|
|
76
|
-
showAlert({
|
|
77
|
-
message: t('Share.shareByEmail.error.addingRecipient'),
|
|
78
|
-
severity: 'error',
|
|
79
|
-
variant: 'filled'
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
} finally {
|
|
83
|
-
reset()
|
|
84
|
-
}
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Normal mode: just add to the list
|
|
89
|
-
const mergedRecipients = flag('sharing.show-recipient-groups')
|
|
90
|
-
? mergeRecipients(recipients, recipient)
|
|
91
|
-
: spreadGroupAndMergeRecipients(recipients, recipient)
|
|
92
|
-
setRecipients(mergedRecipients)
|
|
28
|
+
const onRecipientPick = recipient => {
|
|
29
|
+
const merged = flag('sharing.show-recipient-groups')
|
|
30
|
+
? mergeRecipients(pendingRecipients, recipient)
|
|
31
|
+
: spreadGroupAndMergeRecipients(pendingRecipients, recipient)
|
|
32
|
+
onPendingRecipientsChange(merged)
|
|
93
33
|
}
|
|
94
34
|
|
|
95
35
|
const onRecipientRemove = recipient => {
|
|
96
|
-
const idx =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (recipients.length === 0) {
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// we can't use currentRecipients prop in getSuccessMessage because it may use
|
|
106
|
-
// the updated prop to count the new recipients
|
|
107
|
-
const recipientsBefore = currentRecipients
|
|
108
|
-
|
|
109
|
-
if (hasReachRecipientsLimit(recipientsBefore, recipients)) {
|
|
110
|
-
setRecipientsLimit(true)
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
setLoading(true)
|
|
115
|
-
try {
|
|
116
|
-
const contacts = await getOrCreateFromArray(
|
|
117
|
-
client,
|
|
118
|
-
recipients,
|
|
119
|
-
createContact
|
|
120
|
-
)
|
|
121
|
-
let readWriteRecipients = []
|
|
122
|
-
let readOnlyRecipients = []
|
|
123
|
-
if (selectedOption === 'readOnly') {
|
|
124
|
-
readOnlyRecipients = contacts
|
|
125
|
-
} else {
|
|
126
|
-
readWriteRecipients = contacts
|
|
127
|
-
}
|
|
128
|
-
await onShare({
|
|
129
|
-
document,
|
|
130
|
-
recipients: readWriteRecipients,
|
|
131
|
-
readOnlyRecipients,
|
|
132
|
-
description: sharingDesc,
|
|
133
|
-
openSharing: readWriteRecipients.length > 0,
|
|
134
|
-
sharedDrive
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
if (showNotifications) {
|
|
138
|
-
showAlert({
|
|
139
|
-
message: t(
|
|
140
|
-
...getSuccessMessage(recipientsBefore, contacts, documentType)
|
|
141
|
-
),
|
|
142
|
-
severity: 'success',
|
|
143
|
-
variant: 'filled'
|
|
144
|
-
})
|
|
145
|
-
}
|
|
146
|
-
} catch (err) {
|
|
147
|
-
if (showNotifications) {
|
|
148
|
-
showAlert({
|
|
149
|
-
message: t(
|
|
150
|
-
...getErrorMessage({
|
|
151
|
-
t,
|
|
152
|
-
err,
|
|
153
|
-
documentType,
|
|
154
|
-
recipients,
|
|
155
|
-
selectedOption
|
|
156
|
-
})
|
|
157
|
-
),
|
|
158
|
-
severity: 'error',
|
|
159
|
-
variant: 'filled'
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
} finally {
|
|
163
|
-
reset()
|
|
164
|
-
}
|
|
36
|
+
const idx = pendingRecipients.findIndex(r => r === recipient)
|
|
37
|
+
onPendingRecipientsChange([
|
|
38
|
+
...pendingRecipients.slice(0, idx),
|
|
39
|
+
...pendingRecipients.slice(idx + 1)
|
|
40
|
+
])
|
|
165
41
|
}
|
|
166
42
|
|
|
167
43
|
const getSharingOptions = () => {
|
|
@@ -170,58 +46,37 @@ export const ShareByEmail = ({
|
|
|
170
46
|
: false
|
|
171
47
|
const readWrite = {
|
|
172
48
|
value: 'readWrite',
|
|
173
|
-
label: t('Share.type.two-way')
|
|
174
|
-
desc: t('Share.type.desc.two-way'),
|
|
175
|
-
disabled: false
|
|
49
|
+
label: t('Share.type.two-way')
|
|
176
50
|
}
|
|
177
51
|
const readOnly = {
|
|
178
52
|
value: 'readOnly',
|
|
179
|
-
label: t('Share.type.one-way')
|
|
180
|
-
desc: t('Share.type.desc.one-way'),
|
|
181
|
-
disabled: false
|
|
53
|
+
label: t('Share.type.one-way')
|
|
182
54
|
}
|
|
183
55
|
return isSharingReadOnly ? [readOnly] : [readWrite, readOnly]
|
|
184
56
|
}
|
|
185
57
|
|
|
186
|
-
const showShareControl = recipients.length > 0
|
|
187
|
-
|
|
188
58
|
return (
|
|
189
59
|
<div className={styles['coz-form-group']}>
|
|
190
60
|
<div className={styles['coz-form']}>
|
|
191
61
|
<ShareRecipientsInput
|
|
192
62
|
placeholder={
|
|
193
|
-
|
|
63
|
+
pendingRecipients.length === 0
|
|
194
64
|
? t(`${documentType}.share.shareByEmail.emailPlaceholder`)
|
|
195
65
|
: ''
|
|
196
66
|
}
|
|
197
|
-
onPick={
|
|
198
|
-
onRemove={
|
|
67
|
+
onPick={onRecipientPick}
|
|
68
|
+
onRemove={onRecipientRemove}
|
|
199
69
|
currentRecipients={currentRecipients}
|
|
200
|
-
recipients={
|
|
201
|
-
|
|
70
|
+
recipients={pendingRecipients}
|
|
71
|
+
endAdornment={
|
|
72
|
+
<ShareTypeSelect
|
|
73
|
+
value={selectedOption}
|
|
74
|
+
options={getSharingOptions()}
|
|
75
|
+
onChange={onSelectedOptionChange}
|
|
76
|
+
/>
|
|
77
|
+
}
|
|
202
78
|
/>
|
|
203
79
|
</div>
|
|
204
|
-
{!isFederatedMode && showShareControl && (
|
|
205
|
-
<div className={styles['share-type-control']}>
|
|
206
|
-
<ShareTypeSelect
|
|
207
|
-
value={selectedOption}
|
|
208
|
-
options={getSharingOptions()}
|
|
209
|
-
onChange={onChange}
|
|
210
|
-
/>
|
|
211
|
-
<ShareSubmit
|
|
212
|
-
label={submitLabel || t(`${documentType}.share.shareByEmail.send`)}
|
|
213
|
-
onSubmit={share}
|
|
214
|
-
loading={loading}
|
|
215
|
-
disabled={recipients.length === 0}
|
|
216
|
-
/>
|
|
217
|
-
</div>
|
|
218
|
-
)}
|
|
219
|
-
{showRecipientsLimit ? (
|
|
220
|
-
<ShareRecipientsLimitModal
|
|
221
|
-
documentName={document?.name}
|
|
222
|
-
onConfirm={() => setRecipientsLimit(false)}
|
|
223
|
-
/>
|
|
224
|
-
) : null}
|
|
225
80
|
</div>
|
|
226
81
|
)
|
|
227
82
|
}
|
|
@@ -230,17 +85,11 @@ ShareByEmail.propTypes = {
|
|
|
230
85
|
currentRecipients: PropTypes.arrayOf(PropTypes.object),
|
|
231
86
|
document: PropTypes.object,
|
|
232
87
|
documentType: PropTypes.string.isRequired,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
sharing: PropTypes.object
|
|
238
|
-
// Customize the label of the button that submit contacts
|
|
239
|
-
submitLabel: PropTypes.string,
|
|
240
|
-
// Display success or error notifications
|
|
241
|
-
showNotifications: PropTypes.bool,
|
|
242
|
-
// Set to true for shared drive context
|
|
243
|
-
sharedDrive: PropTypes.bool
|
|
88
|
+
pendingRecipients: PropTypes.array.isRequired,
|
|
89
|
+
onPendingRecipientsChange: PropTypes.func.isRequired,
|
|
90
|
+
selectedOption: PropTypes.oneOf(['readWrite', 'readOnly']).isRequired,
|
|
91
|
+
onSelectedOptionChange: PropTypes.func.isRequired,
|
|
92
|
+
sharing: PropTypes.object
|
|
244
93
|
}
|
|
245
94
|
|
|
246
95
|
export default ShareByEmail
|