Skip to content

Commit

Permalink
feat: Refactor the viewer to let the app handle the action buttons
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The management of action buttons
should now be handled on the application side
via the `FooterActionButtons` component.
The `disableSharing` prop has also been removed, as it is no longer needed.

Example:
```
<Viewer {...props}>
   <FooterActionButtons>
      <SharingButton />
      <ForwardOrDownloadButton />
   </FooterActionButtons>
</Viewer>
```
You can use a codemods `transform-viewer.js` to automatically handle this breaking change.
[See the codemods documentation](https://github.com/cozy/cozy-libs/tree/master/packages/cozy-codemods).
Using linter js auto-correction can be a good idea after that.
Here a common example (don't forget to change `src` value):
```
jscodeshift -t $(yarn global dir)/node_modules/@cozy/codemods/src/transforms/transform-viewer.js src --parser babel --extensions js,jsx && yarn lint:js --fix
```
  • Loading branch information
Merkur39 committed May 24, 2022
1 parent 5f4d79e commit 60084d6
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 36 deletions.
39 changes: 24 additions & 15 deletions react/Viewer/Footer/FooterContent.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { useMemo } from 'react'
import React, { useMemo, Children, cloneElement } from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/core/styles'

import { getReferencedBy, useQuery, models, useClient } from 'cozy-client'
import { getReferencedBy, useQuery, models } from 'cozy-client'

import BottomSheet, { BottomSheetHeader } from '../../BottomSheet'

import { buildContactByIdsQuery } from '../queries'
import { isValidForPanel } from '../helpers'
import Sharing from './Sharing'
import BottomSheetContent from './BottomSheetContent'
import ForwardOrDownloadButton from './ForwardOrDownloadButton'

const {
contact: { getDisplayName }
Expand All @@ -28,9 +26,9 @@ const useStyles = makeStyles(theme => ({
}
}))

const FooterContent = ({ file, toolbarRef, disableSharing }) => {
const FooterContent = ({ file, toolbarRef, children }) => {
const styles = useStyles()
const client = useClient()

const toolbarProps = useMemo(() => ({ ref: toolbarRef }), [toolbarRef])

const contactIds = getReferencedBy(file, 'io.cozy.contacts').map(
Expand All @@ -46,33 +44,44 @@ const FooterContent = ({ file, toolbarRef, disableSharing }) => {
? contactList.map(contact => `${getDisplayName(contact)}`).join(', ')
: ''

const FooterActionButtons = Children.toArray(children).find(child => {
return (
child.type.name === 'FooterActionButtons' ||
child.type.displayName === 'FooterActionButtons'
)
})

const FooterActionButtonsWithFile = cloneElement(FooterActionButtons, {
file
})

if (
isValidForPanel({ file }) &&
(contactsFullname || contactIds.length === 0)
) {
return (
<BottomSheet toolbarProps={toolbarProps}>
<BottomSheetHeader className="u-ph-1 u-pb-1">
{!disableSharing && <Sharing file={file} />}
<ForwardOrDownloadButton file={file} />
{FooterActionButtonsWithFile}
</BottomSheetHeader>
<BottomSheetContent file={file} contactsFullname={contactsFullname} />
</BottomSheet>
)
}

return (
<div className={styles.footer}>
{!disableSharing && <Sharing file={file} />}
<FileActionButton file={file} />
</div>
)
// If `FooterActionButtons` hasn't children
if (!FooterActionButtons) return null

return <div className={styles.footer}>{FooterActionButtonsWithFile}</div>
}

FooterContent.propTypes = {
file: PropTypes.object.isRequired,
toolbarRef: PropTypes.object,
disableSharing: PropTypes.bool
children: PropTypes.oneOfType([
PropTypes.node,
PropTypes.arrayOf(PropTypes.node)
])
}

export default FooterContent
17 changes: 5 additions & 12 deletions react/Viewer/ViewerContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ import ViewerInformationsWrapper from './ViewerInformationsWrapper'
import EncryptedProvider from './EncryptedProvider'

const ViewerContainer = props => {
const {
className,
disableFooter,
disablePanel,
disableSharing,
...rest
} = props
const { className, disableFooter, disablePanel, children, ...rest } = props
const { currentIndex, files, currentURL } = props
const toolbarRef = createRef()
const { isDesktop } = useBreakpoints()
Expand All @@ -43,11 +37,12 @@ const ViewerContainer = props => {
</EncryptedProvider>
<ViewerInformationsWrapper
disableFooter={disableFooter}
disableSharing={disableSharing}
validForPanel={validForPanel}
currentFile={currentFile}
toolbarRef={toolbarRef}
/>
>
{children}
</ViewerInformationsWrapper>
</ViewerWrapper>
)
}
Expand Down Expand Up @@ -79,9 +74,7 @@ ViewerContainer.propTypes = {
/** Show/Hide the panel containing more information about the file only on Desktop */
disablePanel: PropTypes.bool,
/** Show/Hide the panel containing more information about the file only on Phone & Tablet devices */
disableFooter: PropTypes.bool,
/** Show/Hide cozy share button */
disableSharing: PropTypes.bool
disableFooter: PropTypes.bool
}

ViewerContainer.defaultProps = {
Expand Down
19 changes: 10 additions & 9 deletions react/Viewer/ViewerInformationsWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { useSetFlagshipUI } from '../hooks/useSetFlagshipUi/useSetFlagshipUI'
const ViewerInformationsWrapper = ({
currentFile,
disableFooter,
disableSharing,
validForPanel,
toolbarRef
toolbarRef,
children
}) => {
const theme = useTheme()
const sidebar = document.querySelector('[class*="sidebar"]')
Expand All @@ -34,11 +34,9 @@ const ViewerInformationsWrapper = ({
<>
{!disableFooter && (
<Footer>
<FooterContent
file={currentFile}
toolbarRef={toolbarRef}
disableSharing={disableSharing}
/>
<FooterContent file={currentFile} toolbarRef={toolbarRef}>
{children}
</FooterContent>
</Footer>
)}
{validForPanel && (
Expand All @@ -53,9 +51,12 @@ const ViewerInformationsWrapper = ({
ViewerInformationsWrapper.propTypes = {
currentFile: FileDoctype.isRequired,
disableFooter: PropTypes.bool,
disableSharing: PropTypes.bool,
validForPanel: PropTypes.bool,
toolbarRef: PropTypes.object
toolbarRef: PropTypes.object,
children: PropTypes.oneOfType([
PropTypes.node,
PropTypes.arrayOf(PropTypes.node)
])
}

export default ViewerInformationsWrapper
63 changes: 63 additions & 0 deletions react/Viewer/ViewerInformationsWrapper.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react'
import { render } from '@testing-library/react'

import ViewerInformationsWrapper from './ViewerInformationsWrapper'

/* eslint-disable react/display-name */
jest.mock('./Footer', () => ({ children }) => (
<div data-testid="Footer">{children}</div>
))
jest.mock('./InformationPanel', () => ({ children }) => (
<div data-testid="InformationPanel">{children}</div>
))
jest.mock('./Panel/PanelContent', () => () => (
<div data-testid="PanelContent" />
))
jest.mock('./Footer/FooterContent', () => () => (
<div data-testid="FooterContent" />
))
/* eslint-enable react/display-name */

const setup = ({ validForPanel, disableFooter } = {}) => {
return render(
<ViewerInformationsWrapper
currentFile={{}}
disableFooter={disableFooter}
validForPanel={validForPanel}
/>
)
}

describe('ViewerInformationsWrapper', () => {
describe('disableFooter', () => {
it('should render FooterContent components', () => {
const { getByTestId } = setup({ disableFooter: false })

expect(getByTestId('Footer'))
expect(getByTestId('FooterContent'))
})

it('should not render FooterContent components', () => {
const { queryByTestId } = setup({ disableFooter: true })

expect(queryByTestId('Footer')).toBeNull()
expect(queryByTestId('FooterContent')).toBeNull()
})
})

describe('validForPanel', () => {
it('should render InformationPanel & PanelContent components', () => {
const { getByTestId } = setup({ validForPanel: true })

expect(getByTestId('InformationPanel'))
expect(getByTestId('PanelContent'))
})

it('should not render InformationPanel & PanelContent components', () => {
const { queryByTestId } = setup({ validForPanel: false })

expect(queryByTestId('InformationPanel')).toBeNull()
expect(queryByTestId('PanelContent')).toBeNull()
})
})
})

0 comments on commit 60084d6

Please sign in to comment.