cozy-sharing 12.3.0 → 13.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/.storybook/preview.jsx +1 -0
- package/CHANGELOG.md +29 -0
- package/dist/components/ContactSuggestion.js +7 -3
- package/dist/components/ContactSuggestion.spec.js +7 -1
- package/dist/components/Recipient/GroupRecipient.js +14 -7
- package/dist/components/Recipient/GroupRecipientDetail.js +4 -2
- package/dist/components/Recipient/GroupRecipientDetailWithAccess.js +9 -11
- package/dist/components/Recipient/GroupRecipientDetailWithoutAccess.js +8 -4
- package/dist/components/Recipient/GroupRecipientPermissions.js +3 -6
- package/dist/components/Recipient/MemberRecipient.js +1 -2
- package/dist/components/Recipient/MemberRecipientPermissions.js +1 -1
- package/dist/components/ShareAutosuggest.js +16 -9
- package/dist/components/ShareAutosuggest.spec.js +38 -13
- package/dist/components/ShareAutosuggest.stories.js +61 -0
- package/dist/components/ShareByEmail.js +15 -15
- package/dist/components/ShareByEmail.spec.js +0 -6
- package/dist/components/ShareDialogCozyToCozy.js +1 -5
- package/dist/components/ShareDialogCozyToCozy.spec.js +0 -61
- package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +1 -5
- package/dist/components/ShareDialogTwoStepsConfirmationContainer.spec.js +0 -61
- package/dist/components/ShareModal/EditableSharingModal.js +3 -10
- package/dist/components/ShareModal/EditableSharingModal.spec.js +0 -6
- package/dist/components/ShareModal.js +1 -8
- package/dist/components/ShareRecipientsInput.js +46 -49
- package/dist/components/ShareRecipientsInput.spec.js +120 -144
- package/dist/helpers/contacts.js +12 -1
- package/dist/helpers/recipients.js +16 -9
- package/dist/helpers/successMessage.js +58 -16
- package/dist/helpers/successMessage.spec.js +122 -57
- package/dist/queries/queries.js +37 -5
- package/dist/styles/autosuggest.styl +2 -1
- package/dist/stylesheet.css +2 -1
- package/locales/en.json +23 -10
- package/locales/fr.json +23 -8
- package/package.json +4 -4
- package/src/components/ContactSuggestion.jsx +9 -3
- package/src/components/ContactSuggestion.spec.jsx +10 -1
- package/src/components/Recipient/GroupRecipient.jsx +17 -10
- package/src/components/Recipient/GroupRecipientDetail.jsx +5 -2
- package/src/components/Recipient/GroupRecipientDetailWithAccess.jsx +9 -14
- package/src/components/Recipient/GroupRecipientDetailWithoutAccess.jsx +8 -3
- package/src/components/Recipient/GroupRecipientPermissions.jsx +3 -8
- package/src/components/Recipient/MemberRecipient.jsx +4 -3
- package/src/components/Recipient/MemberRecipientPermissions.jsx +1 -1
- package/src/components/ShareAutosuggest.jsx +16 -11
- package/src/components/ShareAutosuggest.spec.jsx +31 -10
- package/src/components/ShareAutosuggest.stories.jsx +63 -0
- package/src/components/ShareByEmail.jsx +11 -11
- package/src/components/ShareByEmail.spec.jsx +0 -4
- package/src/components/ShareDialogCozyToCozy.jsx +0 -4
- package/src/components/ShareDialogCozyToCozy.spec.jsx +0 -67
- package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +0 -4
- package/src/components/ShareDialogTwoStepsConfirmationContainer.spec.jsx +0 -67
- package/src/components/ShareModal/EditableSharingModal.jsx +3 -21
- package/src/components/ShareModal/EditableSharingModal.spec.jsx +0 -2
- package/src/components/ShareModal.jsx +1 -7
- package/src/components/ShareRecipientsInput.jsx +84 -52
- package/src/components/ShareRecipientsInput.spec.jsx +140 -145
- package/src/helpers/contacts.js +8 -0
- package/src/helpers/recipients.js +24 -15
- package/src/helpers/successMessage.js +71 -21
- package/src/helpers/successMessage.spec.js +129 -69
- package/src/queries/queries.js +36 -5
- package/src/styles/autosuggest.styl +2 -1
- package/test/AppLike.jsx +6 -3
|
@@ -12,11 +12,14 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
|
12
12
|
|
|
13
13
|
import { GroupRecipientDetail } from './GroupRecipientDetail'
|
|
14
14
|
import { GroupRecipientPermissions } from './GroupRecipientPermissions'
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
FADE_IN_DURATION,
|
|
17
|
+
getGroupRecipientSecondaryText
|
|
18
|
+
} from '../../helpers/recipients'
|
|
16
19
|
import { GroupAvatar } from '../Avatar/GroupAvatar'
|
|
17
20
|
|
|
18
21
|
const GroupRecipient = props => {
|
|
19
|
-
const { name, members, fadeIn, owner } = props
|
|
22
|
+
const { name, members, fadeIn, owner, isOwner } = props
|
|
20
23
|
const { t } = useI18n()
|
|
21
24
|
const client = useClient()
|
|
22
25
|
const { isMobile } = useBreakpoints()
|
|
@@ -27,7 +30,7 @@ const GroupRecipient = props => {
|
|
|
27
30
|
const nbMemberReady = members.filter(
|
|
28
31
|
member => !['revoked', 'mail-not-sent'].includes(member.status)
|
|
29
32
|
).length
|
|
30
|
-
const
|
|
33
|
+
const isUserInsideMembers = members.some(
|
|
31
34
|
member => member.instance === client.options.uri
|
|
32
35
|
)
|
|
33
36
|
|
|
@@ -56,20 +59,24 @@ const GroupRecipient = props => {
|
|
|
56
59
|
{name}
|
|
57
60
|
</Typography>
|
|
58
61
|
}
|
|
59
|
-
secondary={
|
|
60
|
-
t
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
62
|
+
secondary={getGroupRecipientSecondaryText({
|
|
63
|
+
t,
|
|
64
|
+
nbMember,
|
|
65
|
+
nbMemberReady,
|
|
66
|
+
isUserInsideMembers
|
|
67
|
+
})}
|
|
65
68
|
/>
|
|
66
69
|
<ListItemSecondaryAction className={isMobile ? 'u-mr-1' : 'u-mr-2'}>
|
|
67
|
-
<GroupRecipientPermissions
|
|
70
|
+
<GroupRecipientPermissions
|
|
71
|
+
isUserInsideMembers={isUserInsideMembers}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
68
74
|
</ListItemSecondaryAction>
|
|
69
75
|
</ListItem>
|
|
70
76
|
</Fade>
|
|
71
77
|
{isDetailOpened ? (
|
|
72
78
|
<GroupRecipientDetail
|
|
79
|
+
isOwner={isOwner}
|
|
73
80
|
owner={owner}
|
|
74
81
|
name={name}
|
|
75
82
|
members={members}
|
|
@@ -7,7 +7,7 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
|
7
7
|
import { GroupRecipientDetailWithAccess } from './GroupRecipientDetailWithAccess'
|
|
8
8
|
import { GroupRecipientDetailWithoutAccess } from './GroupRecipientDetailWithoutAccess'
|
|
9
9
|
|
|
10
|
-
const GroupRecipientDetail = ({ name, owner, members, onClose }) => {
|
|
10
|
+
const GroupRecipientDetail = ({ name, owner, members, onClose, isOwner }) => {
|
|
11
11
|
const { t } = useI18n()
|
|
12
12
|
const withAccess = members.filter(
|
|
13
13
|
member => !['revoked', 'mail-not-sent'].includes(member.status)
|
|
@@ -39,7 +39,10 @@ const GroupRecipientDetail = ({ name, owner, members, onClose }) => {
|
|
|
39
39
|
<GroupRecipientDetailWithAccess withAccess={withAccess} />
|
|
40
40
|
) : null}
|
|
41
41
|
{withoutAccess.length > 0 ? (
|
|
42
|
-
<GroupRecipientDetailWithoutAccess
|
|
42
|
+
<GroupRecipientDetailWithoutAccess
|
|
43
|
+
withoutAccess={withoutAccess}
|
|
44
|
+
isOwner={isOwner}
|
|
45
|
+
/>
|
|
43
46
|
) : null}
|
|
44
47
|
</div>
|
|
45
48
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
|
+
import { useClient } from 'cozy-client'
|
|
3
4
|
import Avatar from 'cozy-ui/transpiled/react/Avatar'
|
|
4
|
-
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
5
|
-
import ToTheCloudIcon from 'cozy-ui/transpiled/react/Icons/ToTheCloud'
|
|
6
5
|
import List from 'cozy-ui/transpiled/react/List'
|
|
7
6
|
import ListItem from 'cozy-ui/transpiled/react/ListItem'
|
|
8
7
|
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
|
|
@@ -10,10 +9,12 @@ import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
|
|
|
10
9
|
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
11
10
|
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
12
11
|
|
|
12
|
+
import MemberRecipientStatus from './MemberRecipientStatus'
|
|
13
13
|
import { getInitials, getDisplayName } from '../../models'
|
|
14
14
|
|
|
15
15
|
const GroupRecipientDetailWithAccess = ({ withAccess }) => {
|
|
16
16
|
const { t } = useI18n()
|
|
17
|
+
const client = useClient()
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
20
|
<div>
|
|
@@ -23,6 +24,7 @@ const GroupRecipientDetailWithAccess = ({ withAccess }) => {
|
|
|
23
24
|
<List>
|
|
24
25
|
{withAccess.map(recipient => {
|
|
25
26
|
const name = getDisplayName(recipient)
|
|
27
|
+
const isMe = recipient.instance === client.options.uri
|
|
26
28
|
|
|
27
29
|
return (
|
|
28
30
|
<ListItem disableGutters key={recipient.index}>
|
|
@@ -32,18 +34,11 @@ const GroupRecipientDetailWithAccess = ({ withAccess }) => {
|
|
|
32
34
|
<ListItemText
|
|
33
35
|
primary={name}
|
|
34
36
|
secondary={
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
style={{
|
|
41
|
-
marginRight: '0.25rem'
|
|
42
|
-
}}
|
|
43
|
-
/>
|
|
44
|
-
{recipient.instance}
|
|
45
|
-
</div>
|
|
46
|
-
) : null
|
|
37
|
+
<MemberRecipientStatus
|
|
38
|
+
status={recipient.status}
|
|
39
|
+
isMe={isMe}
|
|
40
|
+
instance={recipient.instance}
|
|
41
|
+
/>
|
|
47
42
|
}
|
|
48
43
|
/>
|
|
49
44
|
</ListItem>
|
|
@@ -10,9 +10,10 @@ import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
|
|
|
10
10
|
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
11
11
|
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
12
12
|
|
|
13
|
+
import { DEFAULT_DISPLAY_NAME } from '../../helpers/recipients'
|
|
13
14
|
import { getInitials, getDisplayName } from '../../models'
|
|
14
15
|
|
|
15
|
-
const GroupRecipientDetailWithoutAccess = ({ withoutAccess }) => {
|
|
16
|
+
const GroupRecipientDetailWithoutAccess = ({ withoutAccess, isOwner }) => {
|
|
16
17
|
const { t } = useI18n()
|
|
17
18
|
|
|
18
19
|
return (
|
|
@@ -23,10 +24,11 @@ const GroupRecipientDetailWithoutAccess = ({ withoutAccess }) => {
|
|
|
23
24
|
<List>
|
|
24
25
|
{withoutAccess.map(recipient => {
|
|
25
26
|
const icon = recipient.status === 'revoked' ? ForbiddenIcon : null
|
|
26
|
-
const
|
|
27
|
+
const defaultDisplayName = t(DEFAULT_DISPLAY_NAME)
|
|
28
|
+
const name = getDisplayName(recipient, defaultDisplayName)
|
|
27
29
|
|
|
28
30
|
return (
|
|
29
|
-
<ListItem disableGutters key={recipient.index}>
|
|
31
|
+
<ListItem disableGutters key={recipient.index} ellipsis={false}>
|
|
30
32
|
<ListItemIcon>
|
|
31
33
|
<Avatar text={getInitials(recipient)} textId={name} />
|
|
32
34
|
</ListItemIcon>
|
|
@@ -46,6 +48,9 @@ const GroupRecipientDetailWithoutAccess = ({ withoutAccess }) => {
|
|
|
46
48
|
{t(
|
|
47
49
|
`GroupRecipientDetail.withoutAccess.status.${recipient.status}`
|
|
48
50
|
)}
|
|
51
|
+
{isOwner
|
|
52
|
+
? ` - ${t('GroupRecipientDetail.withoutAccess.addEmail')}`
|
|
53
|
+
: null}
|
|
49
54
|
</div>
|
|
50
55
|
}
|
|
51
56
|
/>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef } from 'react'
|
|
2
2
|
|
|
3
|
-
import { useClient } from 'cozy-client'
|
|
4
3
|
import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
|
|
5
4
|
import {
|
|
6
5
|
makeActions,
|
|
@@ -21,24 +20,20 @@ import { GroupAvatar } from '../Avatar/GroupAvatar'
|
|
|
21
20
|
const GroupRecipientPermissions = ({
|
|
22
21
|
name,
|
|
23
22
|
isOwner,
|
|
24
|
-
instance,
|
|
25
23
|
sharingId,
|
|
26
24
|
groupIndex,
|
|
27
25
|
read_only: isReadOnly = false,
|
|
28
|
-
className
|
|
26
|
+
className,
|
|
27
|
+
isUserInsideMembers
|
|
29
28
|
}) => {
|
|
30
29
|
const { t } = useI18n()
|
|
31
30
|
const buttonRef = useRef()
|
|
32
|
-
const client = useClient()
|
|
33
31
|
const { revokeGroup, revokeSelf } = useSharingContext()
|
|
34
32
|
|
|
35
33
|
const [isMenuDisplayed, setMenuDisplayed] = useState(false)
|
|
36
34
|
const [revoking, setRevoking] = useState(false)
|
|
37
35
|
|
|
38
|
-
const
|
|
39
|
-
instance !== undefined && instance === client.options.uri
|
|
40
|
-
const shouldShowMenu =
|
|
41
|
-
!revoking && ((instanceMatchesClient && !isOwner) || isOwner)
|
|
36
|
+
const shouldShowMenu = !revoking && (isOwner || isUserInsideMembers)
|
|
42
37
|
|
|
43
38
|
const toggleMenu = () => setMenuDisplayed(!isMenuDisplayed)
|
|
44
39
|
const hideMenu = () => setMenuDisplayed(false)
|
|
@@ -13,12 +13,13 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
|
13
13
|
import MemberRecipientPermissions from './MemberRecipientPermissions'
|
|
14
14
|
import MemberRecipientStatus from './MemberRecipientStatus'
|
|
15
15
|
import RecipientConfirm from './RecipientConfirm'
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
FADE_IN_DURATION,
|
|
18
|
+
DEFAULT_DISPLAY_NAME
|
|
19
|
+
} from '../../helpers/recipients'
|
|
17
20
|
import { getDisplayName } from '../../models'
|
|
18
21
|
import { MemberAvatar } from '../Avatar/MemberAvatar'
|
|
19
22
|
|
|
20
|
-
const DEFAULT_DISPLAY_NAME = 'Share.contacts.defaultDisplayName'
|
|
21
|
-
|
|
22
23
|
const MemberRecipient = props => {
|
|
23
24
|
const { t } = useI18n()
|
|
24
25
|
const client = useClient()
|
|
@@ -7,9 +7,10 @@ import Chip from 'cozy-ui/transpiled/react/Chips'
|
|
|
7
7
|
import { Spinner } from 'cozy-ui/transpiled/react/Spinner'
|
|
8
8
|
import palette from 'cozy-ui/transpiled/react/palette'
|
|
9
9
|
|
|
10
|
+
import { GroupAvatar } from './Avatar/GroupAvatar'
|
|
10
11
|
import ContactSuggestion from './ContactSuggestion'
|
|
11
12
|
import { extractEmails, validateEmail } from '../helpers/email'
|
|
12
|
-
import { getDisplayName, getInitials, Contact } from '../models'
|
|
13
|
+
import { getDisplayName, getInitials, Contact, Group } from '../models'
|
|
13
14
|
import styles from '../styles/autosuggest.styl'
|
|
14
15
|
import {
|
|
15
16
|
cozyUrlMatch,
|
|
@@ -22,7 +23,6 @@ const ShareAutocomplete = ({
|
|
|
22
23
|
loading,
|
|
23
24
|
contactsAndGroups,
|
|
24
25
|
recipients,
|
|
25
|
-
onFocus,
|
|
26
26
|
onPick,
|
|
27
27
|
onRemove,
|
|
28
28
|
placeholder
|
|
@@ -30,6 +30,7 @@ const ShareAutocomplete = ({
|
|
|
30
30
|
const [inputValue, setInputValue] = useState('')
|
|
31
31
|
const [suggestions, setSuggestions] = useState([])
|
|
32
32
|
const [isPasted, setIsPasted] = useState(false)
|
|
33
|
+
const [isLoadingDisplayed, setLoadingDisplayed] = useState(false)
|
|
33
34
|
|
|
34
35
|
const autosuggestRef = useRef(null)
|
|
35
36
|
|
|
@@ -116,7 +117,8 @@ const ShareAutocomplete = ({
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
const onAutosuggestFocus = () => {
|
|
119
|
-
|
|
120
|
+
// We only show the loading state when the user has focus on the input
|
|
121
|
+
setLoadingDisplayed(true)
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
const onAutosuggestBlur = () => {
|
|
@@ -139,13 +141,20 @@ const ShareAutocomplete = ({
|
|
|
139
141
|
const renderInput = inputProps => (
|
|
140
142
|
<div className={styles['recipientsContainer']}>
|
|
141
143
|
{recipients.map((recipient, idx) => {
|
|
144
|
+
const isContactGroup = recipient._type === Group.doctype
|
|
142
145
|
const avatarText = getInitials(recipient)
|
|
143
146
|
const name = getDisplayName(recipient)
|
|
144
147
|
return (
|
|
145
148
|
<Chip
|
|
146
149
|
id={`recipient_${idx}`}
|
|
147
150
|
key={`key_recipient_${idx}`}
|
|
148
|
-
avatar={
|
|
151
|
+
avatar={
|
|
152
|
+
isContactGroup ? (
|
|
153
|
+
<GroupAvatar size="xsmall" />
|
|
154
|
+
) : (
|
|
155
|
+
<Avatar text={avatarText} size="xsmall" />
|
|
156
|
+
)
|
|
157
|
+
}
|
|
149
158
|
label={name}
|
|
150
159
|
onDelete={() => {
|
|
151
160
|
onAutosuggestRemove(recipient)
|
|
@@ -155,12 +164,9 @@ const ShareAutocomplete = ({
|
|
|
155
164
|
)
|
|
156
165
|
})}
|
|
157
166
|
<input {...inputProps} onKeyPress={onKeyPress} onKeyUp={onKeyUp} />
|
|
158
|
-
{loading && (
|
|
159
|
-
<Spinner
|
|
160
|
-
|
|
161
|
-
className="u-flex u-flex-items-center"
|
|
162
|
-
/>
|
|
163
|
-
)}
|
|
167
|
+
{loading && isLoadingDisplayed ? (
|
|
168
|
+
<Spinner color={palette.dodgerBlue} />
|
|
169
|
+
) : null}
|
|
164
170
|
</div>
|
|
165
171
|
)
|
|
166
172
|
|
|
@@ -196,7 +202,6 @@ ShareAutocomplete.propTypes = {
|
|
|
196
202
|
loading: PropTypes.bool,
|
|
197
203
|
contactsAndGroups: PropTypes.array,
|
|
198
204
|
recipients: PropTypes.array.isRequired,
|
|
199
|
-
onFocus: PropTypes.func.isRequired,
|
|
200
205
|
onPick: PropTypes.func.isRequired,
|
|
201
206
|
onRemove: PropTypes.func.isRequired,
|
|
202
207
|
placeholder: PropTypes.string
|
|
@@ -1,29 +1,36 @@
|
|
|
1
|
-
import { render, fireEvent } from '@testing-library/react'
|
|
1
|
+
import { render, fireEvent, screen } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import ShareAutosuggest from './ShareAutosuggest'
|
|
5
5
|
import AppLike from '../../test/AppLike'
|
|
6
6
|
|
|
7
|
+
jest.mock('cozy-ui/transpiled/react/Spinner', () => ({
|
|
8
|
+
Spinner: () => <div>loading</div>
|
|
9
|
+
}))
|
|
10
|
+
|
|
7
11
|
describe('ShareAutosuggest', () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const onFocus = jest.fn()
|
|
11
|
-
const onRemove = jest.fn()
|
|
12
|
-
const { getByPlaceholderText } = render(
|
|
12
|
+
const setup = ({ onPick, onRemove, loading = false }) => {
|
|
13
|
+
render(
|
|
13
14
|
<AppLike>
|
|
14
15
|
<ShareAutosuggest
|
|
16
|
+
loading={loading}
|
|
15
17
|
contactsAndGroups={[]}
|
|
16
18
|
placeholder="myPlaceHolder"
|
|
17
19
|
onPick={onPick}
|
|
18
|
-
onFocus={onFocus}
|
|
19
20
|
recipients={[]}
|
|
20
21
|
onRemove={onRemove}
|
|
21
22
|
/>
|
|
22
23
|
</AppLike>
|
|
23
24
|
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
it('tests if ShareAutosuggest calls onPick', () => {
|
|
28
|
+
const onPick = jest.fn()
|
|
29
|
+
const onRemove = jest.fn()
|
|
30
|
+
|
|
31
|
+
setup({ onPick, onRemove })
|
|
32
|
+
|
|
33
|
+
const inputNode = screen.getByPlaceholderText('myPlaceHolder')
|
|
27
34
|
// It should not call onPick if the value is not an email
|
|
28
35
|
fireEvent.change(inputNode, { target: { value: 'quentin@qq' } })
|
|
29
36
|
fireEvent.keyPress(inputNode, { key: 'Enter', keyCode: 13, charCode: 13 })
|
|
@@ -43,4 +50,18 @@ describe('ShareAutosuggest', () => {
|
|
|
43
50
|
email: 'quentin.valmori@cozycloud.cc'
|
|
44
51
|
})
|
|
45
52
|
})
|
|
53
|
+
|
|
54
|
+
it('should show loading only after user focus input', () => {
|
|
55
|
+
const onPick = jest.fn()
|
|
56
|
+
const onRemove = jest.fn()
|
|
57
|
+
|
|
58
|
+
setup({ onPick, onRemove, loading: true })
|
|
59
|
+
|
|
60
|
+
const inputNode = screen.getByPlaceholderText('myPlaceHolder')
|
|
61
|
+
|
|
62
|
+
expect(screen.queryByText('loading')).toBeNull()
|
|
63
|
+
fireEvent.focus(inputNode)
|
|
64
|
+
|
|
65
|
+
expect(screen.getByText('loading')).toBeInTheDocument()
|
|
66
|
+
})
|
|
46
67
|
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import ShareAutosuggest from './ShareAutosuggest'
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
component: ShareAutosuggest,
|
|
7
|
+
args: {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default meta
|
|
11
|
+
|
|
12
|
+
const ShareAutosuggestRender = props => {
|
|
13
|
+
const [recipients, setRecipients] = useState([])
|
|
14
|
+
const onPick = contactOrGroup => {
|
|
15
|
+
setRecipients([...recipients, contactOrGroup])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const onRemove = contactOrGroup => {
|
|
19
|
+
setRecipients(recipients.filter(r => r.id !== contactOrGroup.id))
|
|
20
|
+
}
|
|
21
|
+
return (
|
|
22
|
+
<ShareAutosuggest
|
|
23
|
+
{...props}
|
|
24
|
+
recipients={recipients}
|
|
25
|
+
onPick={onPick}
|
|
26
|
+
onRemove={onRemove}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const Default = {
|
|
32
|
+
name: 'Default',
|
|
33
|
+
render: ShareAutosuggestRender,
|
|
34
|
+
args: {
|
|
35
|
+
loading: false,
|
|
36
|
+
contactsAndGroups: [
|
|
37
|
+
{
|
|
38
|
+
id: 'group1',
|
|
39
|
+
name: 'Family',
|
|
40
|
+
_type: 'io.cozy.contacts.groups',
|
|
41
|
+
members: [
|
|
42
|
+
{
|
|
43
|
+
id: 'contact1',
|
|
44
|
+
name: 'John Doe',
|
|
45
|
+
_type: 'io.cozy.contacts'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'contact2',
|
|
49
|
+
name: 'Jane Doe',
|
|
50
|
+
_type: 'io.cozy.contacts'
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'contact3',
|
|
56
|
+
name: 'Alice Wonderland',
|
|
57
|
+
_type: 'io.cozy.contacts',
|
|
58
|
+
email: 'alice@wonder.land'
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
placeholder: 'Type a name or email address'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -4,6 +4,7 @@ import React, { useState } from 'react'
|
|
|
4
4
|
import { useClient } from 'cozy-client'
|
|
5
5
|
import flag from 'cozy-flags'
|
|
6
6
|
import Alerter from 'cozy-ui/transpiled/react/deprecated/Alerter'
|
|
7
|
+
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
7
8
|
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
8
9
|
|
|
9
10
|
import ShareRecipientsInput from './ShareRecipientsInput'
|
|
@@ -17,13 +18,10 @@ import {
|
|
|
17
18
|
hasReachRecipientsLimit
|
|
18
19
|
} from '../helpers/recipients'
|
|
19
20
|
import { getSuccessMessage } from '../helpers/successMessage'
|
|
20
|
-
import { contactsResponseType, contactGroupsResponseType } from '../propTypes'
|
|
21
21
|
import { isReadOnlySharing } from '../state'
|
|
22
22
|
import styles from '../styles/share.styl'
|
|
23
23
|
|
|
24
24
|
export const ShareByEmail = ({
|
|
25
|
-
contacts,
|
|
26
|
-
contactGroups,
|
|
27
25
|
document,
|
|
28
26
|
sharingDesc,
|
|
29
27
|
onShare,
|
|
@@ -34,6 +32,8 @@ export const ShareByEmail = ({
|
|
|
34
32
|
}) => {
|
|
35
33
|
const client = useClient()
|
|
36
34
|
const { t } = useI18n()
|
|
35
|
+
const { showAlert } = useAlert()
|
|
36
|
+
|
|
37
37
|
const [recipients, setRecipients] = useState([])
|
|
38
38
|
const [loading, setLoading] = useState(false)
|
|
39
39
|
const [selectedOption, setSelectedOption] = useState()
|
|
@@ -51,7 +51,7 @@ export const ShareByEmail = ({
|
|
|
51
51
|
const onRecipientPick = recipient => {
|
|
52
52
|
const mergedRecipients = flag('sharing.show-recipient-groups')
|
|
53
53
|
? mergeRecipients(recipients, recipient)
|
|
54
|
-
: spreadGroupAndMergeRecipients(recipients, recipient
|
|
54
|
+
: spreadGroupAndMergeRecipients(recipients, recipient)
|
|
55
55
|
setRecipients(mergedRecipients)
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -96,9 +96,13 @@ export const ShareByEmail = ({
|
|
|
96
96
|
openSharing: readWriteRecipients.length > 0
|
|
97
97
|
})
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
t(
|
|
101
|
-
|
|
99
|
+
showAlert({
|
|
100
|
+
message: t(
|
|
101
|
+
...getSuccessMessage(recipientsBefore, contacts, documentType)
|
|
102
|
+
),
|
|
103
|
+
severity: 'success',
|
|
104
|
+
variant: 'filled'
|
|
105
|
+
})
|
|
102
106
|
reset()
|
|
103
107
|
} catch (err) {
|
|
104
108
|
Alerter.error('Error.generic')
|
|
@@ -139,8 +143,6 @@ export const ShareByEmail = ({
|
|
|
139
143
|
}
|
|
140
144
|
onPick={recipient => onRecipientPick(recipient)}
|
|
141
145
|
onRemove={recipient => onRecipientRemove(recipient)}
|
|
142
|
-
contacts={contacts}
|
|
143
|
-
contactGroups={contactGroups}
|
|
144
146
|
recipients={recipients}
|
|
145
147
|
/>
|
|
146
148
|
</div>
|
|
@@ -167,8 +169,6 @@ export const ShareByEmail = ({
|
|
|
167
169
|
|
|
168
170
|
ShareByEmail.propTypes = {
|
|
169
171
|
currentRecipients: PropTypes.arrayOf(PropTypes.object),
|
|
170
|
-
contacts: contactsResponseType.isRequired,
|
|
171
|
-
contactGroups: contactGroupsResponseType.isRequired,
|
|
172
172
|
document: PropTypes.object.isRequired,
|
|
173
173
|
documentType: PropTypes.string.isRequired,
|
|
174
174
|
sharingDesc: PropTypes.string.isRequired,
|
|
@@ -15,8 +15,6 @@ import styles from '../styles/share.styl'
|
|
|
15
15
|
* Displays the sharing interface that can be used when ShareDialogCozyToCozy is in sharing state
|
|
16
16
|
*/
|
|
17
17
|
const SharingContent = ({
|
|
18
|
-
contacts,
|
|
19
|
-
contactGroups,
|
|
20
18
|
createContact,
|
|
21
19
|
document,
|
|
22
20
|
documentType,
|
|
@@ -68,8 +66,6 @@ const SharingContent = ({
|
|
|
68
66
|
</Typography>
|
|
69
67
|
{showShareByEmail && (
|
|
70
68
|
<DumbShareByEmail
|
|
71
|
-
contacts={contacts}
|
|
72
|
-
contactGroups={contactGroups}
|
|
73
69
|
createContact={createContact}
|
|
74
70
|
currentRecipients={recipients}
|
|
75
71
|
document={document}
|
|
@@ -257,57 +257,6 @@ const deferablePromise = () => {
|
|
|
257
257
|
|
|
258
258
|
const getMockProps = () => {
|
|
259
259
|
return {
|
|
260
|
-
contacts: {
|
|
261
|
-
id: 'contacts',
|
|
262
|
-
definition: {
|
|
263
|
-
doctype: 'io.cozy.contacts',
|
|
264
|
-
selector: {
|
|
265
|
-
_id: {
|
|
266
|
-
$gt: null
|
|
267
|
-
}
|
|
268
|
-
},
|
|
269
|
-
indexedFields: ['_id'],
|
|
270
|
-
partialFilter: {
|
|
271
|
-
trashed: {
|
|
272
|
-
$or: [
|
|
273
|
-
{
|
|
274
|
-
$eq: false
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
$exists: false
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
},
|
|
281
|
-
$or: [
|
|
282
|
-
{
|
|
283
|
-
cozy: {
|
|
284
|
-
$not: {
|
|
285
|
-
$size: 0
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
email: {
|
|
291
|
-
$not: {
|
|
292
|
-
$size: 0
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
]
|
|
297
|
-
},
|
|
298
|
-
limit: 1000
|
|
299
|
-
},
|
|
300
|
-
fetchStatus: 'pending',
|
|
301
|
-
lastFetch: null,
|
|
302
|
-
lastUpdate: null,
|
|
303
|
-
lastErrorUpdate: null,
|
|
304
|
-
lastError: null,
|
|
305
|
-
hasMore: false,
|
|
306
|
-
count: 0,
|
|
307
|
-
data: [],
|
|
308
|
-
bookmark: null,
|
|
309
|
-
options: null
|
|
310
|
-
},
|
|
311
260
|
document: {
|
|
312
261
|
id: 'SOME_DOCUMENT_ID',
|
|
313
262
|
name: 'SOME_DOCUMENT_NAME',
|
|
@@ -315,22 +264,6 @@ const getMockProps = () => {
|
|
|
315
264
|
_id: 'SOME_DOCUMENT_ID'
|
|
316
265
|
},
|
|
317
266
|
documentType: 'Organizations',
|
|
318
|
-
contactGroups: {
|
|
319
|
-
id: 'groups',
|
|
320
|
-
definition: {
|
|
321
|
-
doctype: 'io.cozy.contacts.groups'
|
|
322
|
-
},
|
|
323
|
-
fetchStatus: 'pending',
|
|
324
|
-
lastFetch: null,
|
|
325
|
-
lastUpdate: null,
|
|
326
|
-
lastErrorUpdate: null,
|
|
327
|
-
lastError: null,
|
|
328
|
-
hasMore: false,
|
|
329
|
-
count: 0,
|
|
330
|
-
data: [],
|
|
331
|
-
bookmark: null,
|
|
332
|
-
options: null
|
|
333
|
-
},
|
|
334
267
|
hasSharedParent: null,
|
|
335
268
|
isOwner: true,
|
|
336
269
|
link: null,
|
|
@@ -90,8 +90,6 @@ const RejectRecipientActions = ({ reject, cancel }) => {
|
|
|
90
90
|
* Displays a sharing dialog that allows to share a document between multiple Cozy users
|
|
91
91
|
*/
|
|
92
92
|
const ShareDialogTwoStepsConfirmationContainer = ({
|
|
93
|
-
contacts,
|
|
94
|
-
contactGroups,
|
|
95
93
|
createContact,
|
|
96
94
|
document,
|
|
97
95
|
documentType,
|
|
@@ -210,8 +208,6 @@ const ShareDialogTwoStepsConfirmationContainer = ({
|
|
|
210
208
|
} else if (status === 'sharing') {
|
|
211
209
|
dialogContent = (
|
|
212
210
|
<DialogContentOnShare
|
|
213
|
-
contacts={contacts}
|
|
214
|
-
contactGroups={contactGroups}
|
|
215
211
|
createContact={createContact}
|
|
216
212
|
document={document}
|
|
217
213
|
documentType={documentType}
|