cozy-ui 67.0.2 → 68.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/package.json +1 -1
  3. package/react/Buttons/index.jsx +20 -6
  4. package/react/CozyDialogs/ConfirmDialog.jsx +7 -1
  5. package/react/CozyDialogs/Dialog.jsx +7 -1
  6. package/react/CozyDialogs/IllustrationDialog.jsx +7 -1
  7. package/react/CozyDialogs/Readme.md +122 -99
  8. package/react/MuiCozyTheme/makeOverrides.js +13 -1
  9. package/react/Viewer/Footer/DownloadButton.jsx +1 -1
  10. package/react/Viewer/Footer/FooterActionButtons.jsx +20 -0
  11. package/react/Viewer/Footer/FooterActionButtons.spec.jsx +30 -0
  12. package/react/Viewer/Footer/FooterContent.jsx +26 -41
  13. package/react/Viewer/Footer/ForwardOrDownloadButton.jsx +24 -0
  14. package/react/Viewer/Footer/Sharing.jsx +1 -1
  15. package/react/Viewer/Footer/helpers.js +16 -0
  16. package/react/Viewer/Footer/useReferencedContactName.jsx +32 -0
  17. package/react/Viewer/Footer.jsx +5 -3
  18. package/react/Viewer/Panel/getPanelBlocks.spec.jsx +60 -0
  19. package/react/Viewer/Readme.md +25 -3
  20. package/react/Viewer/ViewerContainer.jsx +5 -12
  21. package/react/Viewer/ViewerInformationsWrapper.jsx +10 -9
  22. package/react/Viewer/ViewerInformationsWrapper.spec.jsx +63 -0
  23. package/react/Viewer/helpers.js +10 -0
  24. package/react/__snapshots__/examples.spec.jsx.snap +21 -21
  25. package/transpiled/react/Buttons/index.js +14 -6
  26. package/transpiled/react/CozyDialogs/ConfirmDialog.js +5 -1
  27. package/transpiled/react/CozyDialogs/Dialog.js +5 -1
  28. package/transpiled/react/CozyDialogs/IllustrationDialog.js +5 -1
  29. package/transpiled/react/MuiCozyTheme/makeOverrides.js +13 -1
  30. package/transpiled/react/Viewer/Footer/DownloadButton.js +1 -1
  31. package/transpiled/react/Viewer/Footer/FooterActionButtons.js +20 -0
  32. package/transpiled/react/Viewer/Footer/FooterContent.js +20 -42
  33. package/transpiled/react/Viewer/Footer/ForwardOrDownloadButton.js +20 -0
  34. package/transpiled/react/Viewer/Footer/Sharing.js +1 -1
  35. package/transpiled/react/Viewer/Footer/helpers.js +16 -1
  36. package/transpiled/react/Viewer/Footer/useReferencedContactName.js +35 -0
  37. package/transpiled/react/Viewer/Footer.js +7 -4
  38. package/transpiled/react/Viewer/ViewerContainer.js +4 -8
  39. package/transpiled/react/Viewer/ViewerInformationsWrapper.js +6 -7
  40. package/transpiled/react/Viewer/helpers.js +11 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,55 @@
1
+ # [68.0.0](https://github.com/cozy/cozy-ui/compare/v67.0.4...v68.0.0) (2022-05-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Warning of proptypes ([7b2c464](https://github.com/cozy/cozy-ui/commit/7b2c464))
7
+
8
+
9
+ ### Features
10
+
11
+ * Add FooterActionButtons component ([1c3efc1](https://github.com/cozy/cozy-ui/commit/1c3efc1))
12
+ * Refactor the viewer to let the app handle the action buttons ([60084d6](https://github.com/cozy/cozy-ui/commit/60084d6))
13
+
14
+
15
+ ### BREAKING CHANGES
16
+
17
+ * The management of action buttons
18
+ should now be handled on the application side
19
+ via the `FooterActionButtons` component.
20
+ The `disableSharing` prop has also been removed, as it is no longer needed.
21
+
22
+ Example:
23
+ ```
24
+ <Viewer {...props}>
25
+ <FooterActionButtons>
26
+ <SharingButton />
27
+ <ForwardOrDownloadButton />
28
+ </FooterActionButtons>
29
+ </Viewer>
30
+ ```
31
+ You can use a codemods `transform-viewer.js` to automatically handle this breaking change.
32
+ [See the codemods documentation](https://github.com/cozy/cozy-libs/tree/master/packages/cozy-codemods).
33
+ Using linter js auto-correction can be a good idea after that.
34
+ Here a common example (don't forget to change `src` value):
35
+ ```
36
+ jscodeshift -t $(yarn global dir)/node_modules/@cozy/codemods/src/transforms/transform-viewer.js src --parser babel --extensions js,jsx && yarn lint:js --fix
37
+ ```
38
+
39
+ ## [67.0.4](https://github.com/cozy/cozy-ui/compare/v67.0.3...v67.0.4) (2022-05-20)
40
+
41
+
42
+ ### Bug Fixes
43
+
44
+ * **Buttons:** Classname when using ghost variant ([c070c0c](https://github.com/cozy/cozy-ui/commit/c070c0c))
45
+
46
+ ## [67.0.3](https://github.com/cozy/cozy-ui/compare/v67.0.2...v67.0.3) (2022-05-20)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * Action buttons at the bottom of Dialog/IllustrationDialog on mobile ([b924001](https://github.com/cozy/cozy-ui/commit/b924001))
52
+
1
53
  ## [67.0.2](https://github.com/cozy/cozy-ui/compare/v67.0.1...v67.0.2) (2022-05-12)
2
54
 
3
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "67.0.2",
3
+ "version": "68.0.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -37,12 +37,12 @@ DefaultButton.defaultProps = {
37
37
  color: 'primary'
38
38
  }
39
39
 
40
- const Buttons = forwardRef(({ variant, ...props }, ref) => {
40
+ const Buttons = forwardRef(({ variant, className = '', ...props }, ref) => {
41
41
  switch (variant) {
42
42
  case 'ghost':
43
43
  return (
44
44
  <DefaultButton
45
- className="ghost"
45
+ className={`ghost ${className}`}
46
46
  variant="outlined"
47
47
  {...props}
48
48
  ref={ref}
@@ -50,16 +50,30 @@ const Buttons = forwardRef(({ variant, ...props }, ref) => {
50
50
  )
51
51
 
52
52
  case 'secondary':
53
- return <DefaultButton variant="outlined" {...props} ref={ref} />
53
+ return (
54
+ <DefaultButton
55
+ variant="outlined"
56
+ className={className}
57
+ {...props}
58
+ ref={ref}
59
+ />
60
+ )
54
61
 
55
62
  case 'text':
56
- return <DefaultButton variant="text" {...props} ref={ref} />
63
+ return (
64
+ <DefaultButton
65
+ variant="text"
66
+ className={className}
67
+ {...props}
68
+ ref={ref}
69
+ />
70
+ )
57
71
 
58
72
  case 'primary':
59
- return <DefaultButton {...props} ref={ref} />
73
+ return <DefaultButton className={className} {...props} ref={ref} />
60
74
 
61
75
  default:
62
- return <DefaultButton {...props} ref={ref} />
76
+ return <DefaultButton className={className} {...props} ref={ref} />
63
77
  }
64
78
  })
65
79
  Buttons.displayName = 'Buttons'
@@ -48,7 +48,13 @@ const ConfirmDialog = props => {
48
48
  <DialogTitle {...dialogTitleProps}>{title}</DialogTitle>
49
49
  </div>
50
50
  )}
51
- {content}
51
+ <div
52
+ className={cx('dialogContentWrapper', {
53
+ withActions: Boolean(actions)
54
+ })}
55
+ >
56
+ {content}
57
+ </div>
52
58
  {actions && (
53
59
  <DialogActions
54
60
  {...dialogActionsProps}
@@ -50,7 +50,13 @@ const Dialog = props => {
50
50
  )}
51
51
  <DialogContent {...dialogContentProps}>
52
52
  <div className="dialogContentInner withFluidActions">
53
- {content}
53
+ <div
54
+ className={cx('dialogContentWrapper', {
55
+ withActions: Boolean(actions)
56
+ })}
57
+ >
58
+ {content}
59
+ </div>
54
60
  {actions && (
55
61
  <DialogActions
56
62
  {...dialogActionsProps}
@@ -48,7 +48,13 @@ const IllustrationDialog = props => {
48
48
  <div className="u-flex u-flex-justify-center">{title}</div>
49
49
  </DialogTitle>
50
50
  )}
51
- {content}
51
+ <div
52
+ className={cx('dialogContentWrapper', {
53
+ withActions: Boolean(actions)
54
+ })}
55
+ >
56
+ {content}
57
+ </div>
52
58
  {actions && (
53
59
  <DialogActions
54
60
  {...dialogActionsProps}
@@ -46,10 +46,16 @@ import {
46
46
 
47
47
  import { BreakpointsProvider } from 'cozy-ui/transpiled/react/hooks/useBreakpoints'
48
48
 
49
- import Button from 'cozy-ui/transpiled/react/Button'
49
+ import Button from 'cozy-ui/transpiled/react/Buttons'
50
50
  import Alerter from 'cozy-ui/transpiled/react/Alerter'
51
51
  import Icon from 'cozy-ui/transpiled/react/Icon'
52
52
  import Typography from 'cozy-ui/transpiled/react/Typography'
53
+ import Variants from 'cozy-ui/docs/components/Variants'
54
+ import FormControlLabel from 'cozy-ui/transpiled/react/FormControlLabel'
55
+ import RadioGroup from 'cozy-ui/transpiled/react/RadioGroup'
56
+ import Radio from 'cozy-ui/transpiled/react/Radios'
57
+ import FormControl from 'cozy-ui/transpiled/react/FormControl'
58
+ import FormLabel from 'cozy-ui/transpiled/react/FormLabel'
53
59
 
54
60
  import CloudIcon from "cozy-ui/transpiled/react/Icons/Cloud"
55
61
 
@@ -65,12 +71,12 @@ const ExampleDialogActions = () => {
65
71
  return (
66
72
  <>
67
73
  <Button
68
- theme="secondary"
69
- onClick={handleClose}
74
+ variant="secondary"
70
75
  label={'Close Modal'}
76
+ onClick={handleClose}
71
77
  />
72
78
  <Button
73
- theme="primary"
79
+ variant="primary"
74
80
  label='Do something'
75
81
  onClick={() => alert('click')}
76
82
  />
@@ -82,12 +88,12 @@ const ConfirmDialogActions = () => {
82
88
  return (
83
89
  <>
84
90
  <Button
85
- theme="secondary"
86
- onClick={handleClose}
91
+ variant="secondary"
87
92
  label={'Close Modal'}
93
+ onClick={handleClose}
88
94
  />
89
95
  <Button
90
- theme="danger"
96
+ color="error"
91
97
  label='Do something destructive'
92
98
  onClick={() => alert('click')}
93
99
  />
@@ -148,105 +154,122 @@ initialState = {
148
154
  modalOpened: isTesting(),
149
155
  modal: Dialog,
150
156
  size: 'medium',
151
- actionsLayout: 'row',
152
- title: 'short',
157
+ content: 'default',
158
+ theme: 'normal',
159
+ }
160
+
161
+ const initialVariants = [{
162
+ actionsLayoutColumn: false,
163
+ titleLong: false,
153
164
  disableTitleAutoPadding: false,
154
165
  withCloseButton: true,
155
166
  withBackButton: false,
156
- content: 'default',
157
- theme: 'normal',
158
- align: 'middle',
167
+ alignTop: false,
159
168
  showActions: true,
160
169
  disableGutters: false,
161
170
  hideTitle: false
162
- }
171
+ }]
163
172
 
164
173
  ;
165
174
 
166
- <>
167
- <BreakpointsProvider>
168
- <p>With close button:
169
- <StateRadio value={true} name='withCloseButton' /> yes{' '}
170
- <StateRadio value={false} name='withCloseButton' /> no
171
- </p>
172
- <p>With back button:
173
- <StateRadio value={true} name='withBackButton' /> yes{' '}
174
- <StateRadio value={false} name='withBackButton' /> no
175
- </p>
176
- <p>Disable Title auto-positionning:
177
- <StateRadio value={true} name='disableTitleAutoPadding' /> yes{' '}
178
- <StateRadio value={false} name='disableTitleAutoPadding' /> no
179
- </p>
180
- <p>Title:
181
- <StateRadio value='short' name='title' /> short{' '}
182
- <StateRadio value='long' name='title' /> long
183
- </p>
184
- <p>Hide title:
185
- <StateRadio value={true} name='hideTitle' /> yes{' '}
186
- <StateRadio value={false} name='hideTitle' /> no
187
- </p>
188
- <p>Content:
189
- <StateRadio value='default' name='content' /> default{' '}
190
- <StateRadio value='short' name='content' /> short{' '}
191
- <StateRadio value='long' name='content' /> long
192
- </p>
193
- <p>Size:
194
- <StateRadio value='small' name='size' /> small {' '}
195
- <StateRadio value='medium' name='size' /> medium {' '}
196
- <StateRadio value='large' name='size' /> large
197
- </p>
198
- <p>With actions:
199
- <StateRadio value={true} name='showActions' /> yes
200
- <StateRadio value={false} name='showActions' /> no
201
- </p>
202
- <p>Actions layout:
203
- <StateRadio value='row' name='actionsLayout' /> row{' '}
204
- <StateRadio value='column' name='actionsLayout' /> column
205
- </p>
206
- <p>Alignment:
207
- <StateRadio value='middle' name='align' /> middle
208
- <StateRadio value='top' name='align' /> top{' '}
209
- </p>
210
- <p>Disable gutters (inner padding):
211
- <StateRadio value={true} name='disableGutters' /> yes
212
- <StateRadio value={false} name='disableGutters' /> no{' '}
213
- </p>
214
- <DialogComponent
215
- size={DialogComponent !== ConfirmDialog ? state.size : undefined}
216
- open={state.modalOpened}
217
- onClose={state.withCloseButton ? handleClose : undefined}
218
- onBack={state.withBackButton ? handleBack : undefined}
219
- disableTitleAutoPadding={state.disableTitleAutoPadding}
220
- align={state.align}
221
- title={state.hideTitle
222
- ? undefined
223
- : DialogComponent !== IllustrationDialog && state.title === "long"
224
- ? `${dialogTitles[DialogComponent.name]} - ${content.ada.short}`
225
- : dialogTitles[DialogComponent.name]
226
- }
227
- disableGutters={state.disableGutters}
228
- content={
229
- <Typography variant='body1' color='textPrimary'>
230
- { state.content == 'default'
231
- ? dialogContents[DialogComponent.name]
232
- : state.content == 'long'
233
- ? content.ada.long
234
- : content.ada.short}<br/>
235
- <Button className='u-mt-1 u-ml-0' label="Show an alert" onClick={() => Alerter.success('Hello', { duration: 100000 })}/>
236
- </Typography>}
237
- actions={state.showActions && dialogActions[DialogComponent.name]}
238
- actionsLayout={state.actionsLayout}
239
- />
240
- </BreakpointsProvider>
241
-
242
- {dialogs.map(dialog => (
243
- <button
244
- key={`open-btn-${dialog.name}`}
245
- data-testid={`open-btn-${dialog.name}`}
246
- onClick={() => toggleDialog(dialog)}
247
- >
248
- Open {dialog.name}
249
- </button>
250
- ))}
251
- </>
175
+ <BreakpointsProvider>
176
+ <Variants initialVariants={initialVariants}>
177
+ {variant => (
178
+ <>
179
+ <FormControl component="fieldset" fullWidth>
180
+ <FormLabel component="legend">Content</FormLabel>
181
+ <RadioGroup
182
+ aria-label="radio"
183
+ name="content"
184
+ row
185
+ value={state.content}
186
+ onChange={event => { setState({ content: event.target.value }) }}
187
+ >
188
+ <FormControlLabel
189
+ value="default"
190
+ label="Default"
191
+ control={<Radio />}
192
+ />
193
+ <FormControlLabel
194
+ value="short"
195
+ label="Short"
196
+ control={<Radio />}
197
+ />
198
+ <FormControlLabel
199
+ value="long"
200
+ label="Long"
201
+ control={<Radio />}
202
+ />
203
+ </RadioGroup>
204
+ </FormControl>
205
+ <FormControl component="fieldset" >
206
+ <FormLabel component="legend">Size</FormLabel>
207
+ <RadioGroup
208
+ aria-label="radio"
209
+ name="size"
210
+ row
211
+ value={state.size}
212
+ onChange={event => { setState({ size: event.target.value }) }}
213
+ >
214
+ <FormControlLabel
215
+ value="small"
216
+ label="Small"
217
+ control={<Radio />}
218
+ />
219
+ <FormControlLabel
220
+ value="medium"
221
+ label="Medium"
222
+ control={<Radio />}
223
+ />
224
+ <FormControlLabel
225
+ value="large"
226
+ label="Large"
227
+ control={<Radio />}
228
+ />
229
+ </RadioGroup>
230
+ </FormControl>
231
+ <div className="u-mt-1">
232
+ {dialogs.map(dialog => (
233
+ <Button
234
+ key={`open-btn-${dialog.name}`}
235
+ data-testid={`open-btn-${dialog.name}`}
236
+ className="u-m-half"
237
+ label={`Open ${dialog.name}`}
238
+ variant="ghost"
239
+ size="small"
240
+ onClick={() => toggleDialog(dialog)}
241
+ />
242
+ ))}
243
+ </div>
244
+
245
+ <DialogComponent
246
+ size={DialogComponent !== ConfirmDialog ? state.size : undefined}
247
+ open={state.modalOpened}
248
+ onClose={variant.withCloseButton ? handleClose : undefined}
249
+ onBack={variant.withBackButton ? handleBack : undefined}
250
+ disableTitleAutoPadding={variant.disableTitleAutoPadding}
251
+ align={variant.alignTop ? 'top': 'middle'}
252
+ title={variant.hideTitle
253
+ ? undefined
254
+ : DialogComponent !== IllustrationDialog && variant.titleLong
255
+ ? `${dialogTitles[DialogComponent.name]} - ${content.ada.short}`
256
+ : dialogTitles[DialogComponent.name]
257
+ }
258
+ disableGutters={variant.disableGutters}
259
+ content={
260
+ <Typography variant='body1' color='textPrimary'>
261
+ { state.content == 'default'
262
+ ? dialogContents[DialogComponent.name]
263
+ : state.content == 'long'
264
+ ? content.ada.long
265
+ : content.ada.short}<br/>
266
+ <Button className='u-mt-1 u-ml-0' label="Show an alert" onClick={() => Alerter.success('Hello', { duration: 100000 })}/>
267
+ </Typography>}
268
+ actions={variant.showActions && dialogActions[DialogComponent.name]}
269
+ actionsLayout={variant.actionsLayoutColumn ? 'column' : 'row'}
270
+ />
271
+ </>
272
+ )}
273
+ </Variants>
274
+ </BreakpointsProvider>
252
275
  ```
@@ -577,7 +577,19 @@ const makeOverrides = theme => ({
577
577
  marginBottom: '24px',
578
578
  '&.withFluidActions': {
579
579
  [theme.breakpoints.down('sm')]: {
580
- marginBottom: '16px'
580
+ marginBottom: 0,
581
+ display: 'flex',
582
+ flexDirection: 'column',
583
+ height: '100%',
584
+ '& .dialogContentWrapper': {
585
+ flexGrow: 1,
586
+ '&:not(.withActions)': {
587
+ paddingBottom: '16px'
588
+ }
589
+ },
590
+ '& .cozyDialogActions': {
591
+ paddingBottom: '16px'
592
+ }
581
593
  }
582
594
  },
583
595
  '& .dialogTitleFluidContainer': {
@@ -31,7 +31,7 @@ const DownloadButton = ({ file, t }) => {
31
31
  }
32
32
 
33
33
  DownloadButton.propTypes = {
34
- file: PropTypes.object.isRequired
34
+ file: PropTypes.object
35
35
  }
36
36
 
37
37
  export default withViewerLocales(DownloadButton)
@@ -0,0 +1,20 @@
1
+ import { cloneElement } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { mapToAllChildren } from './helpers'
5
+
6
+ const FooterActionButtons = ({ children, file }) => {
7
+ if (!children) return null
8
+
9
+ return mapToAllChildren(children, child => cloneElement(child, { file }))
10
+ }
11
+
12
+ FooterActionButtons.propTypes = {
13
+ children: PropTypes.oneOfType([
14
+ PropTypes.node,
15
+ PropTypes.arrayOf(PropTypes.node)
16
+ ]),
17
+ file: PropTypes.object
18
+ }
19
+
20
+ export default FooterActionButtons
@@ -0,0 +1,30 @@
1
+ import React from 'react'
2
+ import { render } from '@testing-library/react'
3
+
4
+ import FooterActionButtons from './FooterActionButtons'
5
+
6
+ describe('FooterActionButtons', () => {
7
+ it('should not return children', () => {
8
+ const { container } = render(<FooterActionButtons />)
9
+
10
+ expect(container).toMatchInlineSnapshot('<div />')
11
+ })
12
+
13
+ it('should render all childrens', () => {
14
+ const { getByText } = render(
15
+ <FooterActionButtons>
16
+ <div>
17
+ <p>First child</p>
18
+ <div>
19
+ <p>Sub first children</p>
20
+ </div>
21
+ </div>
22
+ <div>Second child</div>
23
+ </FooterActionButtons>
24
+ )
25
+
26
+ expect(getByText('First child'))
27
+ expect(getByText('Sub first children'))
28
+ expect(getByText('Second child'))
29
+ })
30
+ })
@@ -1,22 +1,12 @@
1
- import React, { useMemo } from 'react'
1
+ import React, { useMemo, Children, cloneElement } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { makeStyles } from '@material-ui/core/styles'
4
4
 
5
- import { getReferencedBy, useQuery, models, useClient } from 'cozy-client'
6
-
7
5
  import BottomSheet, { BottomSheetHeader } from '../../BottomSheet'
8
6
 
9
- import { buildContactByIdsQuery } from '../queries'
10
7
  import { isValidForPanel } from '../helpers'
11
- import Sharing from './Sharing'
12
- import ForwardButton from './ForwardButton'
13
- import DownloadButton from './DownloadButton'
14
8
  import BottomSheetContent from './BottomSheetContent'
15
- import { shouldBeForwardButton } from './helpers'
16
-
17
- const {
18
- contact: { getDisplayName }
19
- } = models
9
+ import useReferencedContactName from './useReferencedContactName'
20
10
 
21
11
  const useStyles = makeStyles(theme => ({
22
12
  footer: {
@@ -30,54 +20,49 @@ const useStyles = makeStyles(theme => ({
30
20
  }
31
21
  }))
32
22
 
33
- const FooterContent = ({ file, toolbarRef, disableSharing }) => {
23
+ const FooterContent = ({ file, toolbarRef, children }) => {
34
24
  const styles = useStyles()
35
- const client = useClient()
36
- const FileActionButton = shouldBeForwardButton(client)
37
- ? ForwardButton
38
- : DownloadButton
25
+
39
26
  const toolbarProps = useMemo(() => ({ ref: toolbarRef }), [toolbarRef])
40
27
 
41
- const contactIds = getReferencedBy(file, 'io.cozy.contacts').map(
42
- ref => ref.id
43
- )
44
- const contactByIdsQuery = buildContactByIdsQuery(contactIds)
45
- const { data: contactList } = useQuery(contactByIdsQuery.definition, {
46
- ...contactByIdsQuery.options,
47
- enabled: contactIds.length > 0
28
+ const { contactName, isLoadingContacts } = useReferencedContactName(file)
29
+
30
+ const FooterActionButtons = Children.toArray(children).find(child => {
31
+ return (
32
+ child.type.name === 'FooterActionButtons' ||
33
+ child.type.displayName === 'FooterActionButtons'
34
+ )
48
35
  })
49
36
 
50
- const contactsFullname = Array.isArray(contactList)
51
- ? contactList.map(contact => `${getDisplayName(contact)}`).join(', ')
52
- : ''
37
+ const FooterActionButtonsWithFile = cloneElement(FooterActionButtons, {
38
+ file
39
+ })
53
40
 
54
- if (
55
- isValidForPanel({ file }) &&
56
- (contactsFullname || contactIds.length === 0)
57
- ) {
41
+ // We have to wait for the Contact request to finish before rendering `BottomSheet`, because it doesn't handle async well.
42
+ if (isValidForPanel({ file }) && !isLoadingContacts) {
58
43
  return (
59
44
  <BottomSheet toolbarProps={toolbarProps}>
60
45
  <BottomSheetHeader className="u-ph-1 u-pb-1">
61
- {!disableSharing && <Sharing file={file} />}
62
- <FileActionButton file={file} />
46
+ {FooterActionButtonsWithFile}
63
47
  </BottomSheetHeader>
64
- <BottomSheetContent file={file} contactsFullname={contactsFullname} />
48
+ <BottomSheetContent file={file} contactsFullname={contactName} />
65
49
  </BottomSheet>
66
50
  )
67
51
  }
68
52
 
69
- return (
70
- <div className={styles.footer}>
71
- {!disableSharing && <Sharing file={file} />}
72
- <FileActionButton file={file} />
73
- </div>
74
- )
53
+ // If `FooterActionButtons` hasn't children
54
+ if (!FooterActionButtons) return null
55
+
56
+ return <div className={styles.footer}>{FooterActionButtonsWithFile}</div>
75
57
  }
76
58
 
77
59
  FooterContent.propTypes = {
78
60
  file: PropTypes.object.isRequired,
79
61
  toolbarRef: PropTypes.object,
80
- disableSharing: PropTypes.bool
62
+ children: PropTypes.oneOfType([
63
+ PropTypes.node,
64
+ PropTypes.arrayOf(PropTypes.node)
65
+ ])
81
66
  }
82
67
 
83
68
  export default FooterContent
@@ -0,0 +1,24 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { useClient } from 'cozy-client'
5
+
6
+ import ForwardButton from './ForwardButton'
7
+ import DownloadButton from './DownloadButton'
8
+ import { shouldBeForwardButton } from './helpers'
9
+
10
+ const ForwardOrDownloadButton = ({ file }) => {
11
+ const client = useClient()
12
+
13
+ const FileActionButton = shouldBeForwardButton(client)
14
+ ? ForwardButton
15
+ : DownloadButton
16
+
17
+ return <FileActionButton file={file} />
18
+ }
19
+
20
+ ForwardOrDownloadButton.propTypes = {
21
+ file: PropTypes.object
22
+ }
23
+
24
+ export default ForwardOrDownloadButton
@@ -37,7 +37,7 @@ const Sharing = ({ file }) => {
37
37
  }
38
38
 
39
39
  Sharing.propTypes = {
40
- file: PropTypes.object.isRequired
40
+ file: PropTypes.object
41
41
  }
42
42
 
43
43
  export default Sharing