diff --git a/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee b/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee
deleted file mode 100644
index 79d4ac4a4b..0000000000
--- a/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee
+++ /dev/null
@@ -1,62 +0,0 @@
-angular.module("admin.orders").directive 'customerSearchOverride', ->
- restrict: 'C'
- scope:
- distributorId: '@'
- link: (scope, element, attr) ->
- if $('#customer_autocomplete_template').length > 0
- customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text())
-
- formatCustomerResult = (customer) ->
- customerTemplate
- customer: customer
- bill_address: customer.bill_address
- ship_address: customer.ship_address
-
- element.select2
- placeholder: Spree.translations.choose_a_customer
- minimumInputLength: 3
- ajax:
- url: '/admin/search/customers.json'
- datatype: 'json'
- data: (term, page) ->
- {
- q: term
- distributor_id: scope.distributorId # modified
- }
- results: (data, page) ->
- { results: data }
- dropdownCssClass: 'customer_search'
- formatResult: formatCustomerResult
- formatSelection: (customer) ->
- _.each [
- 'bill_address'
- 'ship_address'
- ], (address) ->
- data = customer[address]
- address_parts = [
- 'firstname'
- 'lastname'
- 'company'
- 'address1'
- 'address2'
- 'city'
- 'zipcode'
- 'phone'
- ]
- attribute_wrapper = '#order_' + address + '_attributes_'
- if data # modified
- _.each address_parts, (part) ->
- $(attribute_wrapper + part).val data[part]
- return
- $(attribute_wrapper + 'state_id').select2 'val', data['state_id']
- $(attribute_wrapper + 'country_id').select2 'val', data['country_id']
- else
- _.each address_parts, (part) ->
- $(attribute_wrapper + part).val ''
- return
- $(attribute_wrapper + 'state_id').select2 'val', ''
- $(attribute_wrapper + 'country_id').select2 'val', ''
- return
- $('#order_email').val customer.email
- $('#user_id').val customer.user_id # modified
- customer.email
diff --git a/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb b/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb
deleted file mode 100644
index 9484fa0dbb..0000000000
--- a/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb
+++ /dev/null
@@ -1,19 +0,0 @@
-
diff --git a/app/views/spree/admin/orders/customer_details/edit.html.haml b/app/views/spree/admin/orders/customer_details/edit.html.haml
index 765224d247..8735e3f5ee 100644
--- a/app/views/spree/admin/orders/customer_details/edit.html.haml
+++ b/app/views/spree/admin/orders/customer_details/edit.html.haml
@@ -17,8 +17,8 @@
%legend{:align => "center"}= Spree.t(:customer_search)
- content_for :main_ng_app_name do
= "admin.orders"
- = hidden_field_tag :customer_search_override, nil, distributor_id: @order.distributor_id, :class => 'fullwidth title customer-search-override'
- = render :partial => "spree/admin/orders/customer_details/autocomplete", :formats => :js
+ %label{for: "customer_search_override"}= Spree.t(:choose_a_customer)
+ %select{name: "customer_search_override", "data-controller": "select-customer", "data-select-customer-distributor-value": @order.distributor_id, class: "primary", placeholder: Spree.t(:choose_a_customer) }
= render :partial => 'spree/shared/error_messages', :locals => { :target => @order }
diff --git a/app/webpacker/controllers/mixins/useRenderCustomer.js b/app/webpacker/controllers/mixins/useRenderCustomer.js
new file mode 100644
index 0000000000..2f23da24c0
--- /dev/null
+++ b/app/webpacker/controllers/mixins/useRenderCustomer.js
@@ -0,0 +1,50 @@
+export const useRenderCustomer = (controller) => {
+ Object.assign(controller, {
+ renderOption(item, escape) {
+ if (!item.bill_address) {
+ return this.renderWithNoBillAddress(item, escape);
+ }
+ return `
+
+
${escape(item.email)}
+ ${
+ item.bill_address.firstname
+ ? `${I18n.t("bill_address")}
+ ${item.bill_address.firstname} ${
+ item.bill_address.lastname
+ }
+ ${item.bill_address.address1}, ${
+ item.bill_address.address2
+ }
+ ${item.bill_address.city}
+
+ ${
+ item.bill_address.state_id &&
+ item.bill_address.state &&
+ item.bill_address.state.name
+ ? item.bill_address.state.name
+ : item.bill_address.state_name
+ }
+
+ ${
+ item.bill_address.country &&
+ item.bill_address.country.name
+ ? item.bill_address.country.name
+ : item.bill_address.country_name
+ }
+ `
+ : ""
+ }
+
+
`;
+ },
+
+ renderWithNoBillAddress(item, escape) {
+ return `
+
${escape(
+ item.email
+ )}
+
`;
+ },
+ });
+};
diff --git a/app/webpacker/controllers/mixins/useSearchCustomer.js b/app/webpacker/controllers/mixins/useSearchCustomer.js
new file mode 100644
index 0000000000..a7776e14fc
--- /dev/null
+++ b/app/webpacker/controllers/mixins/useSearchCustomer.js
@@ -0,0 +1,22 @@
+export const useSearchCustomer = (controller) => {
+ Object.assign(controller, {
+ load: function (query, callback) {
+ var params = {
+ q: query,
+ distributor_id: this.distributorValue,
+ };
+
+ fetch("/admin/search/customers.json?" + new URLSearchParams(params))
+ .then((response) => response.json())
+ .then((json) => {
+ this.items = json;
+ callback(json);
+ })
+ .catch((error) => {
+ this.items = [];
+ console.log(error);
+ callback();
+ });
+ },
+ });
+};
diff --git a/app/webpacker/controllers/select_customer_controller.js b/app/webpacker/controllers/select_customer_controller.js
new file mode 100644
index 0000000000..7034dbd4d0
--- /dev/null
+++ b/app/webpacker/controllers/select_customer_controller.js
@@ -0,0 +1,66 @@
+import TomSelectController from "./tom_select_controller";
+import { useSearchCustomer } from "./mixins/useSearchCustomer";
+import { useRenderCustomer } from "./mixins/useRenderCustomer";
+
+export default class extends TomSelectController {
+ static values = { options: Object, distributor: Number };
+
+ connect() {
+ useSearchCustomer(this);
+ useRenderCustomer(this);
+ const options = {
+ valueField: "id",
+ labelField: "email",
+ searchField: ["email", "full_name", "last_name"],
+ load: this.load.bind(this),
+ shouldLoad: (query) => query.length > 2,
+ render: {
+ option: this.renderOption.bind(this),
+ },
+ };
+ super.connect(options);
+ this.control.on("item_add", this.onItemSelect.bind(this));
+ this.items = [];
+ }
+
+ onItemSelect(id, item) {
+ const customer = this.items.find((item) => item.id == id);
+ ["bill_address", "ship_address"].forEach((address) => {
+ const data = customer[address];
+ const address_parts = [
+ "firstname",
+ "lastname",
+ "address1",
+ "address2",
+ "city",
+ "zipcode",
+ "phone",
+ ];
+ const attribute_wrapper = "#order_" + address + "_attributes_";
+ address_parts.forEach((part) => {
+ document.querySelector(attribute_wrapper + part).value = data
+ ? data[part]
+ : "";
+ });
+ this.setValueOnTomSelectController(
+ document.querySelector(attribute_wrapper + "state_id"),
+ data ? data.state_id : ""
+ );
+ this.setValueOnTomSelectController(
+ document.querySelector(attribute_wrapper + "country_id"),
+ data ? data.country_id : ""
+ );
+ });
+ $("#order_email").val(customer.email);
+ $("#user_id").val(customer.user_id);
+ }
+
+ setValueOnTomSelectController = (element, value) => {
+ if (!value) {
+ return;
+ }
+ this.application
+ .getControllerForElementAndIdentifier(element, "tom-select")
+ .control.setValue(value, true);
+ };
+}
diff --git a/app/webpacker/controllers/tom_select_controller.js b/app/webpacker/controllers/tom_select_controller.js
index e1b7a65dfb..c39e8abaeb 100644
--- a/app/webpacker/controllers/tom_select_controller.js
+++ b/app/webpacker/controllers/tom_select_controller.js
@@ -1,22 +1,24 @@
-import { Controller } from "stimulus"
-import TomSelect from "tom-select"
+import { Controller } from "stimulus";
+import TomSelect from "tom-select";
export default class extends Controller {
- static values = { options: Object }
+ static values = { options: Object };
static defaults = {
maxItems: 1,
maxOptions: null,
plugins: ["dropdown_input"],
- allowEmptyOption: true
- }
+ allowEmptyOption: true,
+ };
- connect() {
- this.control = new TomSelect(
- this.element, { ...this.constructor.defaults, ...this.optionsValue }
- )
+ connect(options = {}) {
+ this.control = new TomSelect(this.element, {
+ ...this.constructor.defaults,
+ ...this.optionsValue,
+ ...options,
+ });
}
disconnect() {
- if (this.control) this.control.destroy()
+ if (this.control) this.control.destroy();
}
}
diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb
index 7daced0791..67d88115b5 100644
--- a/spec/support/request/web_helper.rb
+++ b/spec/support/request/web_helper.rb
@@ -127,6 +127,12 @@ module WebHelper
page.find(:css, 'body').click
end
+ def tomselect_search_and_select(value, options)
+ page.find("[name='#{options[:from]}']").sibling(".ts-wrapper").click
+ page.find(:css, '.ts-dropdown input.dropdown-input').set(value)
+ page.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click
+ end
+
def accept_js_alert
page.driver.browser.switch_to.alert.accept
end
diff --git a/spec/system/admin/order_spec.rb b/spec/system/admin/order_spec.rb
index c4cbfc125e..98d187c37e 100644
--- a/spec/system/admin/order_spec.rb
+++ b/spec/system/admin/order_spec.rb
@@ -383,7 +383,7 @@ describe '
expect(page).to have_selector '#select-customer'
# And I select that customer's email address and save the order
- select2_select customer.email, from: 'customer_search_override', search: true
+ tomselect_search_and_select customer.email, from: 'customer_search_override'
click_button 'Update'
expect(page).to have_selector "h1.js-admin-page-title", text: "Customer Details"
@@ -391,6 +391,10 @@ describe '
order = Spree::Order.last
expect(order.ship_address.lastname).to eq customer.ship_address.lastname
expect(order.bill_address.lastname).to eq customer.bill_address.lastname
+ expect(order.ship_address.zipcode).to eq customer.ship_address.zipcode
+ expect(order.bill_address.zipcode).to eq customer.bill_address.zipcode
+ expect(order.ship_address.city).to eq customer.ship_address.city
+ expect(order.bill_address.city).to eq customer.bill_address.city
end
context "as an enterprise manager" do