imaginerio/narratives

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

Summary

Maintainability
A
1 hr
Test Coverage
C
72%
/* eslint-disable jsx-a11y/label-has-associated-control */
import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { useQuery, useMutation, gql } from '@apollo/client';
import { Button, List, Segment, Form, Input } from 'semantic-ui-react';

import { useDraw } from '../../providers/DrawProvider';
import useLocale from '../../hooks/useLocale';

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

export const GET_ANNOTATIONS = gql`
  query GetAnnotations($slide: ID!) {
    Slide(where: { id: $slide }) {
      id
      annotations {
        id
        feature
      }
    }
  }
`;

const UPDATE_ANNOTATION_FEATURE = gql`
  mutation UpdateAnnotation($id: ID!, $feature: String) {
    updateAnnotation(id: $id, data: { feature: $feature }) {
      id
      feature
    }
  }
`;

const DELETE_ANNOTATION = gql`
  mutation DeleteAnnotation($id: ID!) {
    deleteAnnotation(id: $id) {
      id
    }
  }
`;

const DrawList = ({ slide }) => {
  const [features, setFeatures] = useState([]);
  const [titles, setTitles] = useState([]);
  const [{ editing }, dispatch] = useDraw();
  const { data } = useQuery(GET_ANNOTATIONS, { variables: { slide } });
  const [deleteAnnotation] = useMutation(DELETE_ANNOTATION);
  const [updateAnnotation] = useMutation(UPDATE_ANNOTATION_FEATURE);
  const updateTimer = useRef();
  const { features: featuresText } = useLocale();

  useEffect(() => {
    if (data) {
      setFeatures(data.Slide.annotations);
      setTitles(data.Slide.annotations.map(a => JSON.parse(a.feature).properties.title));
    }
  }, [data]);

  if (!features || features.length === 0) return null;
  return (
    <Form.Field>
      <label>{featuresText}</label>
      <Segment>
        <List divided verticalAlign="middle">
          {features.map(({ id, feature }, index) => {
            const newFeature = JSON.parse(feature);
            const {
              geometry: { type },
            } = newFeature;
            return (
              <List.Item key={id}>
                <List.Content>
                  <div className={styles.input}>
                    <img src={`/img/${type}.svg`} className={styles.icon} alt={type} />
                    <Input
                      disabled={!editing}
                      size="mini"
                      value={titles[index]}
                      onChange={(e, { value }) => {
                        setTitles(titles.map((t, i) => (i === index ? value : t)));
                        clearTimeout(updateTimer.current);
                        updateTimer.current = setTimeout(() => {
                          const updatedFeature = {
                            ...newFeature,
                            properties: { ...newFeature.properties, title: value },
                          };
                          const featureString = JSON.stringify(updatedFeature);
                          updateAnnotation({
                            variables: { id, feature: featureString },
                            optimisticResponse: {
                              __typename: 'Mutation',
                              updateAnnotation: {
                                __typename: 'Annotation',
                                id,
                                feature: featureString,
                              },
                            },
                          });
                        }, 500);
                      }}
                    />
                    <div>
                      <Button
                        size="tiny"
                        icon="edit outline"
                        disabled={!editing}
                        onClick={() => dispatch(['SET_SELECTED_FEATURE_INDEX', index])}
                      />
                      <Button
                        size="tiny"
                        icon="trash alternate"
                        disabled={!editing}
                        onClick={() =>
                          deleteAnnotation({
                            variables: { id },
                            refetchQueries: [{ query: GET_ANNOTATIONS, variables: { slide } }],
                          })
                        }
                      />
                    </div>
                  </div>
                </List.Content>
              </List.Item>
            );
          })}
        </List>
      </Segment>
    </Form.Field>
  );
};

DrawList.propTypes = {
  slide: PropTypes.string.isRequired,
};

export default DrawList;