ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/corpus/ui/alignment/WordAligner.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
A
100%
import React, { useState } from 'react'
import { Button, Col, Form, Row } from 'react-bootstrap'
import _ from 'lodash'
import Word from './Word'

import './WordAligner.css'

import { Token } from 'transliteration/domain/token'
import { AlignmentToken } from 'corpus/domain/alignment'
import ModalButton from 'common/ModalButton'
import { isAnyWord } from 'transliteration/domain/type-guards'

interface AlignerProps {
  readonly token: AlignmentToken
  readonly reconstructionTokens: ReadonlyArray<Token>
  readonly onChange: (token: AlignmentToken) => void
}

function AlignmentForm(props: AlignerProps) {
  const [alignment, setAlignment] = useState(props.token.alignment)
  const [variant, setVariant] = useState(props.token.variant?.value ?? '')

  function updateToken(alignmentToken: AlignmentToken): AlignmentToken {
    const token = !_.isNil(alignment) && props.reconstructionTokens[alignment]
    return token && isAnyWord(token)
      ? {
          value: alignmentToken.value,
          alignment: alignment,
          variant: variant
            ? {
                value: variant,
                type: token.type,
                language: token.language,
              }
            : null,
          isAlignable: true,
          suggested: false,
        }
      : {
          value: alignmentToken.value,
          alignment: null,
          variant: null,
          isAlignable: true,
          suggested: false,
        }
  }

  const onClick = () => props.onChange(updateToken(props.token))

  const handleAlignmentChange = (
    event: React.ChangeEvent<HTMLSelectElement>
  ) => {
    const alignmentIndex = event.target.value
    const alignmnet = /\d+/.test(alignmentIndex) ? Number(alignmentIndex) : null
    setAlignment(alignmnet)
  }

  const handleVariantChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setVariant(event.target.value)
  }

  return (
    <Form className="WordAligner__form">
      <Row>
        <Form.Group as={Col} controlId={_.uniqueId('WordAligner-Select-')}>
          <Form.Label>Ideal word</Form.Label>
          <Form.Control
            as="select"
            value={String(alignment)}
            onChange={handleAlignmentChange}
          >
            <option value="">--</option>
            {props.reconstructionTokens.map((reconstructionToken, index) =>
              isAnyWord(reconstructionToken) ? (
                <option key={index} value={index}>
                  {' '}
                  {reconstructionToken.value}
                </option>
              ) : null
            )}
          </Form.Control>
        </Form.Group>
        <Form.Group as={Col} controlId={_.uniqueId('WordAligner-Select-')}>
          <Form.Label>Variant</Form.Label>
          <Form.Control
            as="input"
            value={variant}
            onChange={handleVariantChange}
          />
        </Form.Group>
      </Row>
      <Button onClick={onClick}>Set alignment</Button>
    </Form>
  )
}

export default function WordAligner({
  token,
  reconstructionTokens,
  onChange,
}: AlignerProps): JSX.Element {
  const [show, setShow] = useState(false)

  const handleChange = (value: AlignmentToken): void => {
    onChange(value)
    setShow(false)
  }

  const toggle = (
    <Word token={token} reconstructionTokens={reconstructionTokens} />
  )

  const menu = (
    <AlignmentForm
      token={token}
      reconstructionTokens={reconstructionTokens}
      onChange={handleChange}
    />
  )

  return (
    <ModalButton onToggle={setShow} show={show} toggle={toggle} dialog={menu} />
  )
}