Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions manifest.webapp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
"action": "OPEN",
"type": ["io.cozy.suggestions"],
"href": "/intents"
},
{
"action": "PICK",
"type": ["io.cozy.files"],
"href": "/intents"
}
],
"entrypoints": [
Expand Down
111 changes: 111 additions & 0 deletions src/modules/services/components/FilePicker/FilePickerBody.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import PropTypes from 'prop-types'
import React, { useCallback } from 'react'

import { models, useQuery } from 'cozy-client'
import List from 'cozy-ui/transpiled/react/List'
import LoadMore from 'cozy-ui/transpiled/react/LoadMore'

import FilePickerBodyItem from './FilePickerBodyItem'
import { isValidFile } from './helpers'
import { buildContentFolderQuery } from './queries'

const {
file: { isDirectory }
} = models

const FilePickerBody = ({
navigateTo,
folderId,
onSelectItemId,
itemsIdsSelected,
itemTypesAccepted,
multiple
}) => {
const contentFolderQuery = buildContentFolderQuery(folderId)
const {
data: contentFolder,
hasMore,
fetchMore
} = useQuery(contentFolderQuery.definition, contentFolderQuery.options)

const onCheck = useCallback(
itemId => {
const isChecked = itemsIdsSelected.some(
fileIdSelected => fileIdSelected === itemId
)
if (isChecked) {
onSelectItemId(
itemsIdsSelected.filter(fileIdSelected => fileIdSelected !== itemId)
)
} else onSelectItemId(prev => [...prev, itemId])
},
[itemsIdsSelected, onSelectItemId]
)

// When click on checkbox/radio area...
const handleChoiceClick = useCallback(
item => () => {
if (multiple) onCheck(item._id)
else onSelectItemId(item._id)
},
[multiple, onCheck, onSelectItemId]
)

// ...when click anywhere on the rest of the line
const handleListItemClick = useCallback(
item => () => {
if (isDirectory(item)) {
navigateTo(contentFolder.find(it => it._id === item._id))
}

if (isValidFile(item, itemTypesAccepted)) {
if (multiple) onCheck(item._id)
else onSelectItemId(item._id)
}
},
[
contentFolder,
itemTypesAccepted,
multiple,
navigateTo,
onCheck,
onSelectItemId
]
)

return (
<List>
{contentFolder &&
contentFolder.map((item, idx) => {
const hasDivider = contentFolder
? idx !== contentFolder.length - 1
: false

return (
<FilePickerBodyItem
key={item._id}
item={item}
itemTypesAccepted={itemTypesAccepted}
multiple={multiple}
handleChoiceClick={handleChoiceClick}
handleListItemClick={handleListItemClick}
onCheck={onCheck}
itemsIdsSelected={itemsIdsSelected}
hasDivider={hasDivider}
/>
)
})}
{hasMore && <LoadMore label="loadMore" fetchMore={fetchMore} />}
</List>
)
}

FilePickerBody.propTypes = {
onSelectItemId: PropTypes.func.isRequired,
itemsIdsSelected: PropTypes.arrayOf(PropTypes.string).isRequired,
folderId: PropTypes.string.isRequired,
navigateTo: PropTypes.func.isRequired,
itemTypesAccepted: PropTypes.arrayOf(PropTypes.string).isRequired
}

export default FilePickerBody
126 changes: 126 additions & 0 deletions src/modules/services/components/FilePicker/FilePickerBodyItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import cx from 'classnames'
import { filesize } from 'filesize'
import PropTypes from 'prop-types'
import React from 'react'

import { models } from 'cozy-client'
import Checkbox from 'cozy-ui/transpiled/react/Checkbox'
import Divider from 'cozy-ui/transpiled/react/Divider'
import Icon from 'cozy-ui/transpiled/react/Icon'
import FileTypeFolder from 'cozy-ui/transpiled/react/Icons/FileTypeFolder'
import FileTypeText from 'cozy-ui/transpiled/react/Icons/FileTypeText'
import ListItem from 'cozy-ui/transpiled/react/ListItem'
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
import Radio from 'cozy-ui/transpiled/react/Radios'
import { makeStyles } from 'cozy-ui/transpiled/react/styles'
import { useI18n } from 'twake-i18n'

import { isValidFile, isValidFolder } from './helpers'
import styles from './styles.styl'

const {
file: { isDirectory, isFile }
} = models

const useStyles = makeStyles(() => ({
verticalDivider: {
height: '2rem',
display: 'flex',
alignSelf: 'auto',
alignItems: 'center',
marginLeft: '0.5rem'
}
}))

const FilePickerBodyItem = ({
item,
itemTypesAccepted,
multiple,
handleChoiceClick,
handleListItemClick,
itemsIdsSelected,
hasDivider
}) => {
const classes = useStyles()
const { f } = useI18n()
const hasChoice =
isValidFile(item, itemTypesAccepted) ||
isValidFolder(item, itemTypesAccepted)

const Input = multiple ? Checkbox : Radio

const listItemSecondaryContent = isFile(item)
? `${f(item.updated_at, 'dd LLL yyyy')} - ${filesize(item.size, {
base: 10
})}`
: null

return (
<>
<ListItem
disabled={!hasChoice && isFile(item)}
size="small"
button
data-testid="list-item"
>
<div
data-testid="listitem-onclick"
className={styles['filePickerBreadcrumb-wrapper']}
onClick={handleListItemClick(item)}
>
<ListItemIcon>
<Icon
icon={isDirectory(item) ? FileTypeFolder : FileTypeText}
width="32"
height="32"
/>
</ListItemIcon>
<ListItemText
primary={item.name}
secondary={listItemSecondaryContent}
/>
</div>
{isDirectory(item) && hasChoice && (
<Divider
orientation="vertical"
flexItem
className={classes.verticalDivider}
/>
)}
<div
data-testid="choice-onclick"
className="u-pv-half u-h-2 u-flex u-flex-items-center"
onClick={hasChoice ? handleChoiceClick(item) : undefined}
>
<Input
data-testid={multiple ? 'checkbox-btn' : 'radio-btn'}
onChange={() => {
// handled by onClick on the container
}}
checked={itemsIdsSelected.includes(item._id)}
value={item._id}
className={cx('u-p-0', {
'u-o-100': hasChoice,
'u-o-0': !hasChoice
})}
disabled={!hasChoice}
/>
</div>
</ListItem>
{hasDivider && <Divider component="li" />}
</>
)
}
Comment on lines +36 to +114
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Method
FilePickerBodyItem has a cyclomatic complexity of 11, threshold = 10

Suppress


FilePickerBodyItem.propTypes = {
item: PropTypes.object.isRequired,
itemTypesAccepted: PropTypes.arrayOf(PropTypes.string).isRequired,
multiple: PropTypes.bool,
handleChoiceClick: PropTypes.func.isRequired,
handleListItemClick: PropTypes.func.isRequired,
itemsIdsSelected: PropTypes.arrayOf(PropTypes.string).isRequired,
hasDivider: PropTypes.bool.isRequired
}

export default FilePickerBodyItem
Loading
Loading