<template> <div :id="'select-item-button-' + _uid" class="w-full border-b"> <button type="button" class="w-full h-10 flex items-center justify-center text-purple font-medium disabled:bg-gray-200 hover:bg-gray-100" @click="showItems"> <span class="material-icons-outlined text-base font-bold ltr:mr-1 rtl:ml-1"> add </span> {{ addItemText }} </button> <div :class="[{'is-open': show.item_list}]" tabindex="-1"> <div class="-mt-10.5 left-0 right-0 bg-white border rounded-lg" v-if="show.item_list"> <div class="relative"> <span class="material-icons-round absolute left-4 top-3 text-lg">search</span> <input type="text" data-input="true" class="w-full text-sm px-10 py-2.5 mt-1rounded-none border border-gray-200 border-t-0 border-l-0 border-r-0 text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple" autocapitalize="default" autocorrect="ON" :placeholder="placeholder" :value="search" @input="onInput($event)" :ref="'input-item-field-' + _uid" /> </div> <ul class="w-full text-sm p-0 mt-0 rounded-lg border-0 border-light-gray text-black placeholder-light-gray bg-white cursor-pointer disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"> <div class="hover:bg-gray-100 px-4" v-for="(item, index) in sortedItems" :key="index" @click="onItemSelected(item)" > <div class="w-full flex items-center justify-between"> <span class="w-9/12">{{ item.name }}</span> <money :name="'item-id-' + item.id" :value="item.amount" v-bind="money" masked disabled class="w-1/12 text-right disabled-money text-gray" ></money> - <money :name="'item-id-' + item.id" :value="item.paid" v-bind="money" masked disabled class="w-1/12 text-right disabled-money text-gray" ></money> = <money :name="'item-id-' + item.id" :value="item.open" v-bind="money" masked disabled class="w-1/12 text-right disabled-money text-gray" ></money> </div> </div> <div class="hover:bg-gray-100 text-center py-2 px-4" v-if="!sortedItems.length"> <div class="text-center"> <span>{{ noDataText }}</span> </div> </div> </ul> </div> </div> </div> </template> <script> import Vue from 'vue'; import {Money} from 'v-money'; export default { name: 'akaunting-document-button', components: { Money, }, props: { placeholder: { type: String, default: 'Type an item name', description: 'Input placeholder' }, items: { type: Array, default: () => [], description: 'List of Items' }, selectedItems: { type: Array, default: () => [], description: 'List of Selected Items' }, addItemText: { type: String, default: 'Add an item', description: "" }, noDataText: { type: String, default: 'No Data', description: "Selectbox empty options message" }, dynamicCurrency: { type: Object, default: function () { return { decimal_mark: '.', thousands_separator: ',', symbol_first: 1, symbol: '$', precision: 2, }; }, description: "Dynamic currency" }, currency: { type: Object, default: function () { return { decimal_mark: '.', thousands_separator: ',', symbol_first: 1, symbol: '$', precision: 2, }; }, description: "Default currency" }, }, data() { return { item_list: [], search: '', // search column model show: { item_list: false, }, money: { decimal: this.currency.decimal_mark, thousands: this.currency.thousands_separator, prefix: (this.currency.symbol_first) ? this.currency.symbol : '', suffix: (!this.currency.symbol_first) ? this.currency.symbol : '', precision: parseInt(this.currency.precision), masked: this.masked } }; }, created() { this.setItemList(this.items); }, mounted() { if (this.dynamicCurrency.code != this.currency.code) { if (!this.dynamicCurrency.decimal) { this.money = { decimal: this.dynamicCurrency.decimal_mark, thousands: this.dynamicCurrency.thousands_separator, prefix: (this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '', suffix: (!this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '', precision: parseInt(this.dynamicCurrency.precision), masked: this.masked }; } else { this.money = this.dynamicCurrency; } } }, methods: { setItemList(items) { this.item_list = []; // Option set sort_option data if (Array.isArray(items)) { items.forEach(function (item, index) { let selected = this.selectedItems.find(function (selected_item) { return selected_item.id === item.id; }, this); if (selected) { return; } this.item_list.push({ id: item.id, name: item.document_number + ' | ' + item.contact_name + (item.notes ? ' | ' + item.notes : ''), amount: item.amount, paid: item.paid, open: item.amount - item.paid, }); }, this); } }, showItems() { this.show.item_list = true; setTimeout(function() { this.$refs['input-item-field-' + this._uid].focus(); }.bind(this), 100); }, onInput(event) { this.search = event.target.value; //to optimize performance we kept the condition that checks for if search exists or not if (!this.search) { return; } //condition that checks if input is below the given character limit this.setItemList(this.items); //once the user deletes the search input, we show the overall item list this.sortItems(); // we order it as wanted this.$emit('input', this.search); // keep the input binded to v-model }, onItemSelected(param_item) { let selected_item = this.items.find(function (item) { return item.id === param_item.id }, this); this.$emit('document-selected', selected_item); this.show.item_list = false; this.search = ''; // Set default item list this.setItemList(this.items); }, closeIfClickedOutside(event) { if (!document.getElementById('select-item-button-' + this._uid).contains(event.target)) { this.show.item_list = false; this.search = ''; document.removeEventListener('click', this.closeIfClickedOutside); this.setItemList(this.items); } }, sortItems() { this.item_list.sort(function (a, b) { var nameA = a.name.toUpperCase(); // ignore upper and lowercase var nameB = b.name.toUpperCase(); // ignore upper and lowercase if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } // names must be equal return 0; }); const sortedItemList = this.item_list.filter(item => item.name.toLowerCase().includes(this.search.toLowerCase()) ); return sortedItemList; }, }, computed: { sortedItems() { return this.sortItems(); }, }, watch: { dynamicCurrency: function (currency) { if (!currency) { return; } this.money = { decimal: currency.decimal_mark, thousands: currency.thousands_separator, prefix: (currency.symbol_first) ? currency.symbol : '', suffix: (!currency.symbol_first) ? currency.symbol : '', precision: parseInt(currency.precision), masked: this.masked }; }, show: { handler: function(newValue) { if (newValue) { document.addEventListener('click', this.closeIfClickedOutside); } }, deep: true }, items: function (items) { this.setItemList(items); }, selectedItems: function () { this.setItemList(this.items); } }, }; </script>