Newer
Older
expense / src / components / Input.vue
<template>
  <b-col md="6">
    <b-card no-body>
      <b-card-header :header-bg-variant="color" header-text-variant="white" class="container-fluid">
        <b-row>
          <b-col md="10">
            <h3 class="w-75 p-3">{{ title }}</h3>
          </b-col>
          <b-col md="2" class="float-right align-self-center">
            <b-button @click="add()" variant="primary" size="lg"><b-icon-plus /></b-button>
          </b-col>
        </b-row>
      </b-card-header>
      <b-card-body>
        <b-table :fields="fields" :items="data" responsive="sm" v-model="currentItems">
          <template #cell(index)="data">
            {{ data.index + 1 }}
          </template>

          <template #cell(options)="data">
            <b-button-group size="sm">
              <b-button @click="toggleDetails(data)" v-b-tooltip.hover :title="data.detailsShowing ? 'Cancel' : 'Edit'" :variant="data.detailsShowing ? 'outline-danger' : 'primary'">
                <b-icon-x-square v-if="data.detailsShowing" />
                <b-icon-pencil-square v-else />
              </b-button>
              <b-button @click="askDelete(data)" v-b-tooltip.hover title="Remove" variant="danger"><b-icon-trash /></b-button>
            </b-button-group>
          </template>

          <template #cell()="data">
            {{ data.value }}
          </template>

          <template #cell(amount)="data">
            {{ data.item.amount | currency }}
          </template>

          <template #cell(frequency)="data">
            {{ $enums.Frequency.byId(data.item.frequency).name }}
          </template>

          <template #cell(tags)="data">
            {{ (data.item.tags ? data.item.tags.length : 0) }}
          </template>

          <template #row-details="row">
            <b-card>
              <b-form @submit.prevent="save(row)">
                <b-form-group
                id="name-group"
                label="Name:"
                label-for="name">
                  <b-form-input
                    id="name"
                    v-model="editingCache.name"
                    type="text"
                    placeholder="Name"
                    required></b-form-input>
                </b-form-group>

                <b-form-group
                  id="amount-group"
                  label="Amount:"
                  label-for="amount">
                  <b-input-group append="€" class="mb-2 mr-sm-2 mb-sm-0">
                    <b-form-input
                      id="amount"
                      v-model="editingCache.amount"
                      type="number"
                      placeholder="0,00"
                      step="0.01"
                      min="0.01"
                      required></b-form-input>
                  </b-input-group>
                </b-form-group>

                <b-form-group
                  id="frequency-group"
                  label="Frequency:"
                  label-for="frequency">
                  <b-form-select
                    id="frequency"
                    v-model="editingCache.frequency"
                    type="text"
                    :options="$enums.Frequency.options()"
                    required></b-form-select>
                </b-form-group>

                <b-form-group
                  id="tags-group"
                  description="Enter new tags separated by comma or semicolon"
                  label="Tags:"
                  label-for="tags">
                  <b-form-tags
                    id="tags"
                    separator=",;"
                    v-model="editingCache.tags"></b-form-tags>
                </b-form-group>

                <b-button type="submit" variant="success"><b-icon-check /> Save</b-button>
              </b-form>
            </b-card>
          </template>
        </b-table>
      </b-card-body>
    </b-card>
  </b-col>
</template>

<script>
import Vue from 'vue'
import Frequency from '../enums/Frequency'

export default {
  name: 'Input',
  enums: {
    Frequency
  },
  props: [
    'title',
    'color',
    'entries'
  ],
  data () {
    return {
      fields: [
        {
          key: 'index',
          label: '#'
        },
        'name',
        'amount',
        'frequency',
        'tags',
        {
          key: 'options',
          label: ''
        }
      ],
      data: [],
      currentItems: [],
      editingCache: undefined,
      editing: undefined
    }
  },
  mounted () {
    this.$set(this, 'data', this.$props.entries)
  },
  methods: {
    add () {
      this.data.push({
        name: '',
        amount: 1.00,
        frequency: 0
      })

      this.toggleDetails({index: this.data.length - 1, toggleDetails: () => {}})
    },
    askDelete (row) {
      // ask before deletion
      this.$bvModal.msgBoxConfirm(`Please confirm that you want to delete '${row.item.name}'?`, {
        title: 'Are you sure?',
        size: 'sm',
        buttonSize: 'sm',
        okVariant: 'danger',
        okTitle: 'Yes',
        cancelTitle: 'No',
        footerClass: 'p-2',
        hideHeaderClose: false,
        centered: true
      })
        .then(confirmedDelete => {
          if (!confirmedDelete) return
          this.data.splice(row.index, 1)
        })
    },
    save (row) {
      // override active data with from cache
      this.$set(this.data, row.index, this.editingCache)
      this.toggleDetails(row)
    },
    toggleDetails (row) {
      // close all open details
      this.currentItems.forEach((item, i) => {
        if (i === row.index) return
        this.$set(item, '_showDetails', false)
      })

      // create (or reset) local copy for form data
      if (row.detailsShowing) {
        this.editingCache = undefined
      } else {
        this.editingCache = Vue.util.extend({}, row.item)
      }

      row.toggleDetails()
    }
  },
  watch: {
    data: {
      deep: true,
      handler () {
        this.$emit('input', this.data)
      }
    },
    entries: {
      deep: true,
      handler () {
        this.$set(this, 'data', this.$props.entries)
      }
    }
  }
}
</script>

<style>
/* highlight selected row */
.b-table-has-details {
  background: var(--gray);
  color: var(--white);
}
.b-table-has-details + tr {
  background: var(--gray);
}
</style>