imaginerio/narratives

View on GitHub
src/components/Slide/index.jsx

Summary

Maintainability
B
4 hrs
Test Coverage
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import { useDrag, useDrop } from 'react-dnd';
import { Dropdown, Icon } from 'semantic-ui-react';

import ItemTypes from './ItemTypes';
import useLocale from '../../hooks/useLocale';

import styles from './Slide.module.css';

const Slide = ({
  id,
  title,
  index,
  color,
  moveCard,
  handler,
  duplicate,
  newSlide,
  removeSlide,
}) => {
  const ref = useRef(null);
  const { newText, copy, deleteText } = useLocale();

  const [, drop] = useDrop({
    accept: ItemTypes.SLIDE,
    hover(item, monitor) {
      if (!ref.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;
      if (dragIndex === hoverIndex) {
        return;
      }
      const hoverBoundingRect = ref.current.getBoundingClientRect();
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();
      const hoverClientY = clientOffset.y - hoverBoundingRect.top;
      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }
      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }
      moveCard(dragIndex, hoverIndex);
      // eslint-disable-next-line no-param-reassign
      item.index = hoverIndex;
    },
  });
  const [{ isDragging }, drag] = useDrag({
    item: {
      type: ItemTypes.SLIDE,
      id,
      index,
    },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  });
  const opacity = isDragging ? 0 : 1;
  drag(drop(ref));

  return (
    <div
      ref={ref}
      style={{ opacity }}
      role="button"
      tabIndex={index}
      className={`ui segment ${styles.slide} ${color}`}
      onClick={() => handler(id)}
      onKeyPress={() => handler(id)}
    >
      <Dropdown button icon="ellipsis horizontal" className={styles.duplicate}>
        <Dropdown.Menu direction="left">
          <Dropdown.Item onClick={() => newSlide(id)}>
            <Icon name="plus square outline" />
            {newText}
          </Dropdown.Item>
          <Dropdown.Item onClick={() => duplicate(id)}>
            <Icon name="copy outline" />
            {copy}
          </Dropdown.Item>
          <Dropdown.Item onClick={() => removeSlide(id)}>
            <Icon name="trash alternate outline" />
            {deleteText}
          </Dropdown.Item>
        </Dropdown.Menu>
      </Dropdown>
      <div className={styles.slideTitle}>{title}</div>
      <div className={styles.slideNumber}>{index}</div>
    </div>
  );
};

Slide.propTypes = {
  id: PropTypes.string.isRequired,
  title: PropTypes.string,
  index: PropTypes.number.isRequired,
  color: PropTypes.string,
  moveCard: PropTypes.func.isRequired,
  handler: PropTypes.func.isRequired,
  duplicate: PropTypes.func.isRequired,
  newSlide: PropTypes.func.isRequired,
  removeSlide: PropTypes.func.isRequired,
};

Slide.defaultProps = {
  title: '',
  color: '',
};

export default Slide;