SpeciesFileGroup/taxonworks

View on GitHub
app/javascript/vue/components/radials/object/components/asserted_distributions/asserted_distributions_annotator.vue

Summary

Maintainability
Test Coverage
<template>
  <div class="biological_relationships_annotator">
    <div
      v-if="assertedDistribution?.id"
      class="flex-separate gap-small"
    >
      <h3>
        <span v-html="editTitle" />
      </h3>
      <VBtn
        circle
        color="primary"
        @click="resetForm"
      >
        <VIcon
          name="undo"
          small
        />
      </VBtn>
    </div>
    <h3 v-else>New asserted distribution</h3>

    <FormCitation
      v-model="citation"
      v-model:absent="assertedDistribution.is_absent"
      :klass="ASSERTED_DISTRIBUTION"
      :target="ASSERTED_DISTRIBUTION"
      absent-field
      lock-button
      use-session
      @lock="lock.source = $event"
    />
    <div class="margin-small-top margin-small-bottom">
      <VBtn
        v-if="assertedDistribution.id"
        :color="editCitation ? 'create' : 'primary'"
        medium
        @click="saveAssertedDistribution"
      >
        {{ editCitation ? 'Update' : 'Create' }}
      </VBtn>
    </div>
    <DisplayList
      v-if="assertedDistribution.id"
      edit
      class="margin-medium-top"
      label="citation_source_body"
      :list="assertedDistribution.citations"
      @edit="setCitation"
      @delete="removeCitation"
    />
    <GeographicArea
      class="separate-bottom"
      :source-lock="lock.source"
      :disabled="!citation.source_id || assertedDistribution.id"
      @select="
        ($event) => {
          assertedDistribution.geographic_area_id = $event
          saveAssertedDistribution()
        }
      "
    />
    <div class="horizontal-left-content">
      <VSpinner
        v-if="isLoading"
        legend="Loading..."
      />
      <VMap
        v-if="list.length"
        width="90%"
        height="300px"
        tooltips
        actions
        :zoom="2"
        :zoom-on-click="false"
        :geojson="shapes"
      />
    </div>
    <TableList
      class="separate-top"
      :list="list"
      @edit="setDistribution"
      @delete="removeItem"
    />
  </div>
</template>

<script setup>
import TableList from './table.vue'
import DisplayList from '@/components/displayList.vue'
import GeographicArea from './geographicArea.vue'
import VSpinner from '@/components/ui/VSpinner.vue'
import VMap from '@/components/georeferences/map.vue'
import makeEmptyCitation from '../../helpers/makeEmptyCitation.js'
import VBtn from '@/components/ui/VBtn/index.vue'
import VIcon from '@/components/ui/VIcon/index.vue'
import FormCitation from '@/components/Form/FormCitation.vue'
import { ASSERTED_DISTRIBUTION } from '@/constants/index'
import { AssertedDistribution } from '@/routes/endpoints'
import { useSlice } from '@/components/radials/composables'
import { ref, computed, reactive } from 'vue'

const EXTEND_PARAMS = {
  embed: ['shape'],
  extend: [
    'geographic_area',
    'geographic_area_type',
    'parent',
    'citations',
    'source'
  ]
}

const props = defineProps({
  objectType: {
    type: String,
    required: true
  },

  objectId: {
    type: Number,
    required: true
  },

  radialEmit: {
    type: Object,
    required: true
  }
})

const { list, addToList, removeFromList } = useSlice({
  radialEmit: props.radialEmit
})

const shapes = computed(() =>
  list.value.map((item) => {
    const shape = item.geographic_area.shape
    shape.properties.is_absent = item.is_absent
    return shape
  })
)

const lock = reactive({
  geo: false,
  source: false
})

const assertedDistribution = ref(newAsserted())
const editTitle = ref()
const editCitation = ref()
const isLoading = ref(false)
const citation = ref(makeEmptyCitation())

function setCitation(citation) {
  citation.value = {
    id: citation.id,
    pages: citation.pages,
    source_id: citation.source_id,
    is_original: citation.is_original
  }
  editCitation.value = citation
}

function saveAssertedDistribution() {
  const createdObject = list.value.find(
    (item) =>
      item.geographic_area.id ===
        assertedDistribution.value.geographic_area_id &&
      !!assertedDistribution.value.is_absent === !!item.is_absent
  )
  const params = {
    asserted_distribution: {
      ...assertedDistribution.value,
      citations_attributes: [citation.value]
    },
    ...EXTEND_PARAMS
  }

  const saveRequest = createdObject
    ? AssertedDistribution.update(createdObject.id, params)
    : AssertedDistribution.create(params)

  saveRequest
    .then(({ body }) => {
      TW.workbench.alert.create(
        'Asserted distribution was successfully saved.',
        'notice'
      )

      addToList(body)
      resetForm()
    })
    .catch(() => {})
}

function removeCitation(item) {
  const payload = {
    asserted_distribution: {
      citations_attributes: [
        {
          id: item.id,
          _destroy: true
        }
      ]
    },
    ...EXTEND_PARAMS
  }

  AssertedDistribution.update(assertedDistribution.value.id, payload).then(
    ({ body }) => {
      addToList(body)
      resetForm()
    }
  )
}

function setDistribution(item) {
  resetForm()
  editTitle.value = item.object_tag
  assertedDistribution.value = {
    id: item.id,
    citations: item.citations,
    otu_id: item.otu_id,
    is_absent: item.is_absent,
    geographic_area_id: item.geographic_area_id
  }

  editCitation.value = undefined
}

function newAsserted() {
  return {
    id: undefined,
    otu_id: props.objectId,
    geographic_area_id: lock.geo
      ? assertedDistribution.value.geographic_area_id
      : undefined,
    citations: [],
    is_absent: null
  }
}

function resetForm() {
  assertedDistribution.value = {
    ...newAsserted(),
    is_absent: lock.source ? assertedDistribution.value.is_absent : undefined
  }

  citation.value = {
    ...makeEmptyCitation(),
    source_id: lock.source ? citation.value.source_id : undefined,
    pages: lock.source ? citation.value.pages : undefined,
    is_original: lock.source ? citation.value.is_original : undefined
  }
}

function removeItem(item) {
  AssertedDistribution.destroy(item.id).then(() => {
    removeFromList(item)
  })
}

AssertedDistribution.all({
  otu_id: props.objectId,
  ...EXTEND_PARAMS
}).then(({ body }) => {
  isLoading.value = false
  list.value = body
})
</script>
<style lang="scss">
.radial-annotator {
  .biological_relationships_annotator {
    position: relative;
    overflow-y: scroll;

    .pages {
      width: 86px;
    }
    .asserted-map-link {
      position: absolute;
      right: 0px;
    }
  }
}
</style>