SyncM8/syncm8

View on GitHub
client/src/components/FamilyDroppable/FamilyDroppable.tsx

Summary

Maintainability
A
0 mins
Test Coverage
/* eslint-disable react/jsx-props-no-spreading */
import React, { CSSProperties } from "react";
import {
  Draggable,
  DraggingStyle,
  Droppable,
  NotDraggingStyle,
} from "react-beautiful-dnd";

import { Mate } from "../../graphql/types";
import { UnassignedMate } from "../../pages/types";
import UnassignedMateCard from "../UnassignedMateCard/UnassignedMateCard";

const CARD_WIDTH = 200;
const GRID = 8;
const DROP_MIN_HEIGHT = 125;

type StyleType = DraggingStyle | NotDraggingStyle | undefined;
type CSSType = CSSProperties | undefined;

type FamilyDroppableType = {
  mates: UnassignedMate[];
  direction: "horizontal" | "vertical";
  droppableId: string;
  removeMate: (mate: Mate) => void;
};

/**
 * CSS style for horizontal grid item
 * @param draggableStyle
 * @param isDragging
 * @returns CSSProperties
 */
const horizontalGetItemStyle = (
  draggableStyle: StyleType,
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  isDragging: boolean
): CSSType => ({
  userSelect: "none",
  margin: `0 ${GRID}px 0 0`,
  ...draggableStyle,
});

/**
 * CSS style for horizontal grid list
 * @param isDraggingOver
 * @returns CSSProperties
 */
const horizontalGetListStyle = (isDraggingOver: boolean): CSSType => ({
  background: isDraggingOver ? "lightblue" : "lightgrey",
  display: "flex",
  padding: GRID,
  overflow: "auto",
  minHeight: DROP_MIN_HEIGHT,
});

/**
 * CSS style for vertical grid item
 * @param draggableStyle
 * @param isDragging
 * @returns CSSProperties
 */
const verticalGetItemStyle = (
  draggableStyle: StyleType,
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  isDragging: boolean
): CSSType => ({
  userSelect: "none",
  margin: `0 auto ${GRID}px auto`,
  width: CARD_WIDTH,
  ...draggableStyle,
});

/**
 * CSS style for vertical grid list
 * @param isDraggingOver
 * @returns CSSProperties
 */
const verticalGetListStyle = (isDraggingOver: boolean): CSSType => ({
  background: isDraggingOver ? "lightblue" : "lightgrey",
  padding: GRID,
  width: 220,
  minHeight: DROP_MIN_HEIGHT,
  borderRadius: 5,
});

/**
 * Droppable area for drag-and-drop items
 * @param CustomDroppableProps
 * @returns
 */
const FamilyDroppable = ({
  mates,
  droppableId,
  direction,
  removeMate,
}: FamilyDroppableType): JSX.Element => {
  const getListStyle =
    direction === "vertical" ? verticalGetListStyle : horizontalGetListStyle;
  const getItemStyle =
    direction === "vertical" ? verticalGetItemStyle : horizontalGetItemStyle;
  return (
    <Droppable droppableId={droppableId} direction={direction}>
      {(provided, snapshot) => (
        <div
          ref={provided.innerRef}
          style={getListStyle(snapshot.isDraggingOver)}
        >
          {mates.map((item, index) => (
            <Draggable key={item.id} draggableId={item.id} index={index}>
              {(draggableProvided, draggableSnapshot) => (
                <div
                  ref={draggableProvided.innerRef}
                  {...draggableProvided.draggableProps}
                  {...draggableProvided.dragHandleProps}
                  style={getItemStyle(
                    draggableProvided.draggableProps.style,
                    draggableSnapshot.isDragging
                  )}
                >
                  <UnassignedMateCard
                    mate={item}
                    lastSynced={item.lastSynced}
                    style={{ width: CARD_WIDTH }}
                    removeMate={removeMate}
                  />
                </div>
              )}
            </Draggable>
          ))}
          {provided.placeholder}
        </div>
      )}
    </Droppable>
  );
};

export default FamilyDroppable;