@@ -1258,6 +1229,7 @@
pastItemsSelected: null,
% endif
productIsKnown: true,
+ selectedProduct: null,
productUUID: null,
productDisplay: null,
productKey: null,
@@ -1544,6 +1516,18 @@
this.$refs.contactAutocomplete.clearSelection()
}
},
+
+ productIsKnown(newval, oldval) {
+ // TODO: seems like this should be better somehow?
+ // e.g. maybe we should not be clearing *everything*
+ // in case user accidentally clicks, and then clicks
+ // "is known" again? and if we *should* clear all,
+ // why does that require 2 steps?
+ if (!newval) {
+ this.selectedProduct = null
+ this.clearProduct()
+ }
+ },
},
methods: {
@@ -1894,20 +1878,12 @@
}
},
- productFullLookup() {
- this.showingItemDialog = false
- let term = this.$refs.productAutocomplete.getUserInput()
- this.$refs.productLookup.showDialog(term)
- },
-
- productLookupCanceled() {
- this.showingItemDialog = true
- },
-
productLookupSelected(selected) {
+ // TODO: this still is a hack somehow, am sure of it.
+ // need to clean this up at some point
+ this.selectedProduct = selected
this.clearProduct()
- this.productChanged(selected.uuid)
- this.showingItemDialog = true
+ this.productChanged(selected)
},
copyPendingProductAttrs(from, to) {
@@ -1930,6 +1906,7 @@
this.customerPanelOpen = false
this.editingItem = null
this.productIsKnown = true
+ this.selectedProduct = null
this.productUUID = null
this.productDisplay = null
this.productKey = null
@@ -1962,7 +1939,7 @@
this.itemDialogTabIndex = 0
this.showingItemDialog = true
this.$nextTick(() => {
- this.$refs.productAutocomplete.focus()
+ this.$refs.productLookup.focus()
})
},
@@ -2027,6 +2004,16 @@
this.productIsKnown = !!row.product_uuid
this.productUUID = row.product_uuid
+ if (row.product_uuid) {
+ this.selectedProduct = {
+ uuid: row.product_uuid,
+ full_description: row.product_full_description,
+ url: row.product_url,
+ }
+ } else {
+ this.selectedProduct = null
+ }
+
// nb. must construct new object before updating data
// (otherwise vue does not notice the changes?)
let pending = {}
@@ -2131,11 +2118,11 @@
}
},
- productChanged(uuid) {
- if (uuid) {
+ productChanged(product) {
+ if (product) {
let params = {
action: 'get_product_info',
- uuid: uuid,
+ uuid: product.uuid,
}
// nb. it is possible for the handler to "swap"
// the product selection, i.e. user chooses a "per
@@ -2144,6 +2131,8 @@
// received above is the correct one, but just use
// whatever came back from handler
this.submitBatchData(params, response => {
+ this.selectedProduct = response.data
+
this.productUUID = response.data.uuid
this.productKey = response.data.key
this.productDisplay = response.data.full_description
diff --git a/tailbone/templates/products/lookup.mako b/tailbone/templates/products/lookup.mako
index cdc4c565..42ee0742 100644
--- a/tailbone/templates/products/lookup.mako
+++ b/tailbone/templates/products/lookup.mako
@@ -2,8 +2,49 @@
<%def name="tailbone_product_lookup_template()">
%def>
@@ -166,9 +208,17 @@
const TailboneProductLookup = {
template: '#tailbone-product-lookup-template',
+ props: {
+ selectedProduct: {
+ type: Object,
+ },
+ },
data() {
return {
- showingDialog: false,
+ autocompleteValue: '',
+ autocompleteOptions: [],
+
+ lookupShowDialog: false,
searchTerm: null,
searchTermLastUsed: null,
@@ -187,23 +237,67 @@
},
methods: {
- showDialog(term) {
+ focus() {
+ if (!this.selectedProduct) {
+ this.$refs.productAutocomplete.focus()
+ }
+ },
+ clearSelection(focus) {
+
+ // clear data
+ this.autocompleteValue = ''
+ this.$emit('selected', null)
+
+ // maybe set focus to our (autocomplete) component
+ if (focus) {
+ this.$nextTick(() => {
+ this.focus()
+ })
+ }
+ },
+
+ getAutocompleteOptions: debounce(function (entry) {
+
+ // since the `@typing` event from buefy component does not
+ // "self-regulate" in any way, we a) use `debounce` above,
+ // but also b) skip the search unless we have at least 3
+ // characters of input from user
+ if (entry.length < 3) {
+ this.data = []
+ return
+ }
+
+ // and perform the search
+ let url = '${url(f'{route_prefix}.product_autocomplete')}'
+ this.$http.get(url + '?term=' + encodeURIComponent(entry))
+ .then(({ data }) => {
+ this.autocompleteOptions = data
+ }).catch((error) => {
+ this.autocompleteOptions = []
+ throw error
+ })
+ }),
+
+ autocompleteSelected(option) {
+ this.$emit('selected', {
+ uuid: option.value,
+ full_description: option.label,
+ })
+ },
+
+ lookupInit() {
this.searchResultSelected = null
+ this.lookupShowDialog = true
- if (term !== undefined) {
- this.searchTerm = term
- // perform search if invoked with new term
- if (term != this.searchTermLastUsed) {
+ this.$nextTick(() => {
+
+ this.searchTerm = this.autocompleteValue
+ if (this.searchTerm != this.searchTermLastUsed) {
this.searchTermLastUsed = null
this.performSearch()
}
- } else {
- this.searchTerm = this.searchTermLastUsed
- }
- this.showingDialog = true
- this.$nextTick(() => {
this.$refs.searchTermInput.focus()
})
},
@@ -214,17 +308,6 @@
}
},
- cancelDialog() {
- this.searchResultSelected = null
- this.showingDialog = false
- this.$emit('canceled')
- },
-
- selectResult() {
- this.showingDialog = false
- this.$emit('selected', this.searchResultSelected)
- },
-
performSearch() {
if (this.searchResultsLoading) {
return
@@ -255,6 +338,16 @@
this.searchResultsLoading = false
})
},
+
+ selectResult() {
+ this.lookupShowDialog = false
+ this.$emit('selected', this.searchResultSelected)
+ },
+
+ cancelDialog() {
+ this.searchResultSelected = null
+ this.lookupShowDialog = false
+ },
},
}