@bigfishtv/cockpit
Version:
225 lines (202 loc) • 6.69 kB
JavaScript
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { DragSource } from 'react-dnd'
import classnames from 'classnames'
import _throttle from 'lodash/debounce'
import ImageCell from '../asset/ImageCell'
import VideoCell from '../asset/VideoCell'
import AudioCell from '../asset/AudioCell'
import DocumentCell from '../asset/DocumentCell'
import UnknownFileCell from '../asset/UnknownFileCell'
import AssetCellToolbar from '../asset/AssetCellToolbar'
import * as DragTypes from '../../constants/DragTypes'
import { getAssetUrl, getImageUrl } from '../../utils/fileUtils'
import { connect } from 'react-redux'
import {
cancelGeneratedImageRequest,
requestGeneratedImage,
generatedImageRequestFulfilled,
} from '../../actions/imageRequestQueue'
const dragSource = {
beginDrag(props) {
return {
id: props.asset.id,
}
},
}
// we define this because react-docgen fails when defaultProp directly references an imported component
const DefaultAssetCellToolbar = props => <AssetCellToolbar {...props} />
/**
* AssetCell is the base asset cell component which takes a generic asset objects and displays the corresponding cell
* e.g. DocumentCell, ImageCell, UnknownFileCell, VideoCell
* NOTE: AssetCell is wrapped as a react-dnd dragSource, use AssetCellStandard for custom drag'n'drop implementations
*/
export class AssetCellStandard extends Component {
static propTypes = {
/** Tank asset object */
asset: PropTypes.object.isRequired,
/** If asset cell is selected */
selected: PropTypes.bool,
/** React component for a custom cell toolbar */
Toolbar: PropTypes.any,
/** Sets maxWidth of cell (cell expands with flex) */
cellSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Tank asset size string, e.g. cockpit-150 */
size: PropTypes.string,
/** custom class name for cell */
className: PropTypes.string,
onClick: PropTypes.func,
onDoubleClick: PropTypes.func,
onEdit: PropTypes.func,
onDetails: PropTypes.func,
onRemove: PropTypes.func,
}
static defaultProps = {
selected: false,
Toolbar: DefaultAssetCellToolbar,
cellSize: 150,
size: 'cockpit-150',
className: null,
onClick: () => console.warn('[AssetCell] no onClick prop'),
onDoubleClick: () => console.warn('[AssetCell] no onDoubleClick prop'),
onEdit: () => console.warn('[AssetCell] no onEdit prop'),
onPlay: () => console.warn('[AssetCell] no onPlay prop'),
onDetails: () => console.warn('[AssetCell] no onDetails prop'),
onRemove: () => console.warn('[AssetCell] no onRemove prop'),
}
constructor(props) {
super(props)
this.handleClick = _throttle(this.handleClick.bind(this), 100)
this.state = { broken: false, generatedAssetUrl: null, generatedAssetUrlWaiting: props.imageRequestQueueEnabled }
}
componentDidMount() {
this.requestCurrentGeneratedImage()
}
componentDidUpdate(prevProps) {
if (this.props.imageRequestQueueEnabled && this.props.asset && this.props.asset.kind === 'image') {
if ((this.props.asset && this.props.asset.id) !== (prevProps.asset && prevProps.asset.id)) {
this.setState({ generatedAssetUrl: null, generatedAssetUrlWaiting: !!this.props.asset })
this.cancelCurrentGeneratedImageRequest(prevProps.asset, prevProps.size)
this.requestCurrentGeneratedImage()
}
}
}
componentWillUnmount() {
this.cancelCurrentGeneratedImageRequest()
}
requestCurrentGeneratedImage() {
if (!this.props.imageRequestQueueEnabled) return
if (!this.props.asset || this.props.asset.kind !== 'image') return
this.props.dispatch(requestGeneratedImage(this.props.asset, this.props.size, this.handleGeneratedAssetUrlReceived))
}
cancelCurrentGeneratedImageRequest(asset = this.props.asset, size = this.props.size) {
if (!this.props.imageRequestQueueEnabled) return
if (!asset || asset.kind !== 'image') return
if (this.state.generatedAssetUrlWaiting && !this.state.generatedAssetUrl) {
this.props.dispatch(cancelGeneratedImageRequest(asset, size, this.handleGeneratedAssetUrlReceived))
}
}
handleGeneratedAssetUrlReceived = url => {
this.setState({ generatedAssetUrl: url, generatedAssetUrlWaiting: false })
}
handleImageStatus = (broken = false) => {
this.setState({ broken, generatedAssetUrlWaiting: false })
if (this.props.imageRequestQueueEnabled) {
this.props.dispatch(
generatedImageRequestFulfilled(this.props.asset, this.props.size, this.handleGeneratedAssetUrlReceived)
)
}
}
handleClick(event) {
this.props.onClick()
}
render() {
const {
imageRequestQueueEnabled,
connectDragSource,
isDragSource,
isDragging,
asset,
className,
size,
cellSize,
selected,
onClick,
onDoubleClick,
Toolbar,
...rest
} = this.props
let assetUrl = getAssetUrl(asset)
let AssetComponent = null
let queued = false
const toolbarProps = {
onRemove: this.props.onRemove,
onDetails: this.props.onDetails,
}
switch (asset.kind) {
case 'image':
AssetComponent = ImageCell
assetUrl = imageRequestQueueEnabled ? this.state.generatedAssetUrl : getImageUrl(asset, size)
queued = imageRequestQueueEnabled && !this.state.generatedAssetUrl && !this.state.broken
toolbarProps.onEdit = this.props.onEdit
break
case 'video':
AssetComponent = VideoCell
toolbarProps.onPlay = this.props.onPlay
break
case 'audio':
AssetComponent = AudioCell
toolbarProps.onPlay = this.props.onPlay
break
case 'pdf':
case 'excel':
case 'word':
case 'text':
case 'html':
AssetComponent = DocumentCell
break
default:
AssetComponent = UnknownFileCell
}
return (
<div
className={classnames('image', className, { selected: selected, dragging: isDragging })}
onClick={this.handleClick}
onDoubleClick={onDoubleClick}
style={{ maxWidth: cellSize }}>
<div className="image-inner">
<AssetComponent
{...asset}
size={size}
url={assetUrl}
onStatus={this.handleImageStatus}
queued={queued}
{...rest}
/>
{Toolbar && (
<Toolbar
asset={asset}
isDragging={isDragging}
queued={queued}
broken={this.state.broken}
{...toolbarProps}
/>
)}
</div>
</div>
)
}
}
const AssetCell = DragSource(props => DragTypes.ASSET_CELL, dragSource, (connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
isDragSource: true,
}))(({ connectDragSource, ...props }) =>
connectDragSource(
<div>
<AssetCellStandard {...props} />
</div>
)
)
export default AssetCell