just-paja/radio-drama-queen

View on GitHub
src/soundCategories/components/CategoryItem.jsx

Summary

Maintainability
A
2 hrs
Test Coverage
import PropTypes from 'prop-types'
import React from 'react'

import { CategoryItemMenu } from './CategoryItemMenu'
import { connect } from 'react-redux'
import { DragSource } from 'react-dnd'
import { focusable } from '../../components'
import { Sound } from '../../sounds/proptypes'
import { SoundName, SoundStatusIcon } from '../../sounds/components'
import { SoundPlaybackInfo } from './SoundPlaybackInfo'
import { soundRoutines, soundStore, DRAG_TYPE_SOUND } from '../../sounds'
import { withStyles } from '@material-ui/core/styles'

const styles = theme => ({
  button: {
    alignItems: 'stretch',
    flexDirection: 'column',
    background: 'none',
    border: 'none',
    display: 'flex',
    padding: theme.spacing(1),
    userSelect: 'none',
    width: '100%',
    ...theme.components.listSeparator,

    '&:hover': {
      background: theme.palette.action.hover
    }
  },
  duration: {
    display: 'flex',
    fontSize: theme.typography.fontSize / 2,
    marginTop: theme.spacing(1 / 2),
    paddingLeft: theme.spacing(1),
    paddingRight: theme.spacing(1)
  },
  identification: {
    display: 'flex',
    alignItems: 'center',
    textAlign: 'left'
  },
  name: {
    height: theme.spacing(2),
    overflow: 'hidden',
    paddingRight: theme.spacing(1),
    textOverflow: 'ellipsis',
    whiteSpace: 'nowrap'
  },
  icon: {
    height: theme.spacing(2),
    marginLeft: theme.spacing(1 / 2),
    marginRight: theme.spacing(1 / 2),
    width: theme.spacing(2)
  }
})

class CategoryItemComponent extends React.PureComponent {
  constructor () {
    super()
    this.handleFocus = this.handleFocus.bind(this)
    this.handleToggle = this.handleToggle.bind(this)
  }

  handleFocus (event) {
    event.stopPropagation()
    if (!this.props.focused) {
      this.props.onFocus(this.props.sound.uuid)
    }
  }

  handleToggle () {
    this.props.onToggle(this.props.sound.uuid)
  }

  render () {
    const {
      categoryUuid,
      classes,
      focusableRef,
      connectDragSource,
      search,
      sound
    } = this.props
    const draggable = sound && connectDragSource && connectDragSource(
      <button
        className={classes.button}
        disabled={Boolean(sound.error)}
        onClick={this.handleToggle}
        onContextMenu={this.handleContextMenuOpen}
        onFocus={this.handleFocus}
        ref={focusableRef}
      >
        <span className={classes.identification}>
          <SoundStatusIcon
            className={classes.icon}
            error={sound.error}
            loading={sound.loading}
            playing={sound.playing}
            size={16}
            valid={sound.valid}
          />
          <SoundName
            className={classes.name}
            name={sound.name}
            uuid={sound.uuid}
            highlight={search}
          />
        </span>
        <span className={classes.duration}>
          <SoundPlaybackInfo
            duration={sound.duration}
            playing={sound.playing}
            uuid={sound.uuid}
          />
        </span>
      </button>
    )

    return (
      <CategoryItemMenu
        categoryUuid={categoryUuid}
        soundUuid={sound.uuid}
      >
        {draggable}
      </CategoryItemMenu>
    )
  }
}

CategoryItemComponent.displayName = 'CategoryItem'
CategoryItemComponent.propTypes = {
  categoryUuid: PropTypes.string.isRequired,
  classes: PropTypes.objectOf(PropTypes.string).isRequired,
  connectDragSource: PropTypes.func,
  onToggle: PropTypes.func.isRequired,
  search: PropTypes.string,
  sound: Sound.isRequired
}

CategoryItemComponent.defaultProps = {
  connectDragSource: null,
  search: ''
}

const soundItem = {
  beginDrag ({ sound }) {
    return sound
  }
}

const collect = (connectDrag, monitor) => ({
  connectDragSource: connectDrag.dragSource(),
  isDragging: monitor.isDragging()
})

const mapStateToProps = (state, { uuid }) => ({
  sound: soundStore.getObject(state, uuid)
})

const mapDispatchToProps = {
  onFocus: soundRoutines.focus,
  onToggle: soundRoutines.toggle
}

export const CategoryItem = connect(
  mapStateToProps,
  mapDispatchToProps
)(DragSource(
  DRAG_TYPE_SOUND,
  soundItem,
  collect
)(withStyles(styles)(
  focusable(CategoryItemComponent)
)))