Skip to content

Commit

Permalink
feat: Add Viewer bottomSheet for mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
JF-Cozy committed Mar 15, 2021
1 parent 1bee0df commit 0b8d6f5
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 6 deletions.
110 changes: 110 additions & 0 deletions src/drive/web/modules/viewer/Footer/BottomSheet.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState, useEffect, useRef } from 'react'
import { BottomSheet } from 'mui-bottom-sheet'
import { makeStyles } from '@material-ui/core/styles'

const useStyles = ({ isTopPosition }) => ({
root: {
borderTopLeftRadius: '1rem',
borderTopRightRadius: '1rem',
transition: 'border-radius 0.5s',
boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.5)',
...(isTopPosition && {
borderTopLeftRadius: 0,
borderTopRightRadius: 0
})
}
})

const useClasses = makeStyles(theme => ({
header: {
height: '2.5rem',
width: '100%',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
indicator: {
width: '4rem',
height: '0.25rem',
borderRadius: '99px',
backgroundColor: theme.palette.divider
}
}))

const BottomSheetWrapper = ({ file, actionButtonsRef, children }) => {
const [isTopPosition, setIsTopPosition] = useState(false)
const [peekHeights, setPeekHeights] = useState(null)
const [initPos, setInitPos] = useState(null)
const [bottomSpacerHeight, setBottomSpacerHeight] = useState(0)
const classes = useClasses()
const styles = useStyles({ isTopPosition })
const innerContentRef = useRef()
const headerRef = useRef()

const toolbar = document.getElementById('viewer-toolbar')

useEffect(
() => {
const maxHeight = toolbar
? window.innerHeight - toolbar.offsetHeight
: window.innerHeight
const mediumHeight = maxHeight * 0.33
const actionButtonsHeight = parseFloat(
getComputedStyle(actionButtonsRef.current).getPropertyValue('height')
)
// this is the margin of action buttons without bottomSheet
const actionButtonsBottomMargin = 7
const minHeight =
headerRef.current.offsetHeight +
actionButtonsHeight +
actionButtonsBottomMargin

// Used so that the bottomSheet can be opened to the top,
// without stopping at the content height
const bottomSpacerHeight =
maxHeight - innerContentRef.current.offsetHeight

setPeekHeights([minHeight, mediumHeight, maxHeight])
setInitPos(mediumHeight)
setBottomSpacerHeight(bottomSpacerHeight)
},
[toolbar, innerContentRef, file, actionButtonsRef]
)

const handleOnIndexChange = snapIndex => {
const maxHeightSnapIndex = peekHeights.length - 1

if (snapIndex === maxHeightSnapIndex && !isTopPosition) {
setIsTopPosition(true)
}
if (snapIndex !== maxHeightSnapIndex && isTopPosition) {
setIsTopPosition(false)
}
}

return (
<BottomSheet
peekHeights={peekHeights}
defaultHeight={initPos}
backdrop={false}
fullHeight={false}
onIndexChange={snapIndex => handleOnIndexChange(snapIndex)}
styles={{ root: styles.root }}
>
<div ref={innerContentRef}>
<div
data-testid="bottomSheet-header"
className={classes.header}
ref={headerRef}
>
<div className={classes.indicator} />
</div>
{children}
</div>
<div style={{ height: bottomSpacerHeight }} />
</BottomSheet>
)
}

export default BottomSheetWrapper
55 changes: 55 additions & 0 deletions src/drive/web/modules/viewer/Footer/BottomSheetContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { forwardRef } from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import { makeStyles } from '@material-ui/core/styles'

import { isMobileApp } from 'cozy-device-helper'
import Paper from 'cozy-ui/transpiled/react/Paper'
import Typography from 'cozy-ui/transpiled/react/Typography'
import Stack from 'cozy-ui/transpiled/react/Stack'

import Sharing from './Sharing'
import ForwardButton from './ForwardButton'
import DownloadButton from './DownloadButton'
import getPanelBlocks, { panelBlocksSpecs } from '../Panel/getPanelBlocks'

const useStyles = makeStyles(theme => ({
stack: {
backgroundColor: theme.palette.background.default
}
}))

const BottomSheetContent = forwardRef(({ file }, ref) => {
const panelBlocks = getPanelBlocks({ panelBlocksSpecs, file })
const FileActionButton = isMobileApp() ? ForwardButton : DownloadButton
const styles = useStyles()

return (
<Stack
spacing="s"
className={cx('u-flex u-flex-column u-ov-hidden', styles.stack)}
>
<Paper className={'u-flex u-ph-1 u-pb-1'} elevation={2} square ref={ref}>
<Sharing file={file} />
<FileActionButton file={file} />
</Paper>
{panelBlocks.map((PanelBlock, index) => (
<Paper
key={index}
elevation={index === panelBlocks.length - 1 ? 0 : 2}
square
>
<Typography variant="h4">
<PanelBlock file={file} />
</Typography>
</Paper>
))}
</Stack>
)
})

BottomSheetContent.propTypes = {
file: PropTypes.object.isRequired
}

export default BottomSheetContent
31 changes: 28 additions & 3 deletions src/drive/web/modules/viewer/Footer/FooterContent.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
import React from 'react'
import React, { useRef } from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '@material-ui/core/styles'

import { isMobileApp } from 'cozy-device-helper'

import { showPanel } from '../helpers'
import Sharing from './Sharing'
import ForwardButton from './ForwardButton'
import DownloadButton from './DownloadButton'
import BottomSheet from './BottomSheet'
import BottomSheetContent from './BottomSheetContent'

const useStyles = makeStyles({
footer: {
display: 'flex',
alignItems: 'center',
width: 'calc(100% - 2rem)',
height: '100%',
paddingLeft: '1rem',
paddingRight: '1rem',
borderTop: '1px solid var(--dividerColor)'
}
})

const FooterContent = ({ file }) => {
const styles = useStyles()
const FileActionButton = isMobileApp() ? ForwardButton : DownloadButton
const actionButtonsRef = useRef()

if (showPanel({ file }))
return (
<BottomSheet file={file} actionButtonsRef={actionButtonsRef}>
<BottomSheetContent file={file} ref={actionButtonsRef} />
</BottomSheet>
)

return (
<>
<div className={styles.footer}>
<Sharing file={file} />
<FileActionButton file={file} />
</>
</div>
)
}

Expand Down
16 changes: 13 additions & 3 deletions src/drive/web/modules/viewer/Footer/FooterContent.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jest.mock('cozy-device-helper', () => ({
isMobileApp: jest.fn()
}))

const file = {
const staticFile = {
id: 'fileId',
name: 'Demo.pdf'
}
Expand All @@ -23,7 +23,8 @@ const client = createMockClient({})
const setup = ({
byDocId = { fileId: {} },
isOwner = false,
isMobileAppValue = false
isMobileAppValue = false,
file
} = {}) => {
const mockSharingContext = {
byDocId,
Expand All @@ -35,7 +36,7 @@ const setup = ({

const root = render(
<AppLike client={client} sharingContextValue={mockSharingContext}>
<FooterContent file={file} />
<FooterContent file={file || staticFile} />
</AppLike>
)

Expand Down Expand Up @@ -86,4 +87,13 @@ describe('FooterContent', () => {
expect(getByText('Shared'))
expect(queryByText('Share')).toBeFalsy()
})

it('should show bottom sheet for file with certification or konnector', () => {
const { root } = setup({
file: { metadata: { carbonCopy: true }, ...staticFile }
})
const { getByTestId } = root

expect(getByTestId('bottomSheet-header')).toBeTruthy()
})
})

0 comments on commit 0b8d6f5

Please sign in to comment.