@bigfishtv/cockpit
Version:
221 lines (198 loc) • 6.08 kB
JavaScript
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createValue } from '@bigfishtv/react-forms'
import { modalHandler } from '../modal/ModalHost'
import { addFile, getUploader } from '../../api/tankUpload'
import { openImageEditModal } from '../../utils/imageEditUtils'
import FileDropzone from '../container/FileDropzone'
import AssetAutoCell from '../asset/AssetAutoCell'
import AssetEditModal from '../asset/AssetEditModal'
import MediaPreviewModal from '../asset/MediaPreviewModal'
import AssetSelectControls from '../asset/AssetSelectControls'
import ReorderableAssetCell from '../asset/ReorderableAssetCell'
import { AssetCellStandard } from '../asset/AssetCell'
// we define this because react-docgen fails when defaultProp directly references an imported component
const DefaultAssetSelectControls = props => <AssetSelectControls {...props} />
export default class AssetDropzoneInput extends Component {
static propTypes = {
onChange: PropTypes.func,
onRemove: PropTypes.func,
cellSize: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
}
static defaultProps = {
type: 'image',
dropzoneSize: 'small',
assetSize: 'cockpit-150',
multiple: false,
extensions: [],
reorderable: true, // only applicable if multiple = true
AssetSelectControls: DefaultAssetSelectControls,
assetFolderId: null,
readOnly: false,
}
constructor(props) {
super(props)
const extensions =
props.extensions && props.extensions.length
? props.extensions
: props.type in props.fileTypes
? props.fileTypes[props.type].join(', ')
: '*'
this.fileProps = {
subject: props.type,
multiple: props.multiple,
extensions,
}
this.onEdit = props.onEdit || this.handleEdit
this.onDetails = props.onDetails || this.handleDetailsEdit
this.onPlay = props.onPlay || this.handlePlay
this.onMove = props.onMove || this.handleMove
}
componentDidMount() {
if (getUploader()) getUploader().bind('FileUploaded', this.handleFileUploaded, this)
}
componentWillUnmount() {
if (getUploader()) getUploader().unbind('FileUploaded', this.handleFileUploaded)
}
handleEdit = asset => {
openImageEditModal(asset, this.handleAssetUpdate)
}
handleDetailsEdit = asset => {
modalHandler.add({
Component: AssetEditModal,
props: {
formValue: createValue({
schema: null,
value: { asset },
}),
onSave: formValue => this.handleAssetUpdate(formValue.select('asset').value, asset),
onClose: () => {},
},
})
}
handlePlay = asset => {
modalHandler.add({
Component: MediaPreviewModal,
props: {
asset,
onClose: () => {},
},
})
}
handleAssetUpdate = (asset, previousAsset) => {
let { value, multiple } = this.props
if (multiple) {
value = value.map(file => (file.id === previousAsset.id ? asset : file))
} else {
value = asset
}
this.props.onChange(value)
}
// triggered upon global file upload
handleFileUploaded = (uploader, file, response) => {
const { value, multiple, onChange } = this.props
if (response.status !== 200 || !value) return
if (multiple) {
const ids = (value || []).map(asset => asset.id)
if (ids.indexOf(file.id) !== -1) {
const newValue = (value || []).map(asset => (asset.id === file.id ? JSON.parse(response.response) : asset))
onChange(newValue)
}
} else {
if (value && value.id === file.id) {
onChange(JSON.parse(response.response))
}
}
}
// called by browse button
handleReceivedFiles = files => {
const { value, multiple, onChange, defaultAssetFolder, assetFolderId } = this.props
const newFiles = files.map(file => ({
id: addFile(file, defaultAssetFolder ? defaultAssetFolder.id : assetFolderId),
}))
onChange(multiple ? [...(value || []), ...newFiles] : newFiles[0])
}
// called when media is selected from modal
handleSelectedFiles = files => {
const { value, multiple, onChange } = this.props
onChange(multiple ? [...(value || []), ...files] : files[0])
}
handleRemove(asset, i) {
if (this.props.multiple) {
this.props.onChange((this.props.value || []).filter(child => child !== asset))
} else {
this.props.onChange(null)
}
}
handleMove = (id, afterId) => {
let Cells = this.props.value.slice()
const cell = Cells.filter(c => c.id === id)[0]
const afterCell = Cells.filter(c => c.id === afterId)[0]
const cellIndex = Cells.indexOf(cell)
const afterIndex = Cells.indexOf(afterCell)
Cells.splice(cellIndex, 1)
Cells.splice(afterIndex, 0, cell)
this.props.onChange(Cells)
}
render() {
const {
value,
text,
multiple,
dropzoneSize,
assetSize,
cellSize,
onEdit,
onRemove,
AssetSelectControls,
AssetCell,
assetFolderId,
...rest
} = this.props
const assets = value ? (multiple ? value : [value]) : []
const _AssetCell = AssetCell || (multiple ? ReorderableAssetCell : undefined)
if (this.props.readOnly) {
return (
<div>
{assets.map((asset, i) => {
return <AssetCellStandard key={i} asset={asset} Toolbar={null} />
})}
</div>
)
}
return (
<FileDropzone {...this.fileProps} files={assets} onReceivedFiles={this.handleReceivedFiles}>
<div>
{assets.length > 0 &&
assets.map((asset, i) => (
<AssetAutoCell
key={i}
size={assetSize}
cellSize={cellSize}
asset={asset}
onRemove={() => (onRemove ? onRemove(i, asset) : this.handleRemove(asset, i))}
onEdit={this.onEdit}
onMove={this.onMove}
onDetails={this.onDetails}
onPlay={this.onPlay}
{...rest}
AssetCell={_AssetCell}
/>
))}
</div>
{(multiple || !assets.length) && (
<AssetSelectControls
{...rest}
{...this.fileProps}
size={dropzoneSize}
files={assets}
onReceivedFiles={this.handleReceivedFiles}
onFilesSelected={this.handleSelectedFiles}
/>
)}
</FileDropzone>
)
}
}