diff --git a/backend/app/assets/javascripts/spree/backend/checkouts/edit.js b/backend/app/assets/javascripts/spree/backend/checkouts/edit.js index 47a50792d7c..9151451483b 100644 --- a/backend/app/assets/javascripts/spree/backend/checkouts/edit.js +++ b/backend/app/assets/javascripts/spree/backend/checkouts/edit.js @@ -1,99 +1,12 @@ -//= require_self -$(document).ready(function() { - var customerTemplate = HandlebarsTemplates['orders/customer_details/autocomplete']; - - var formatCustomerResult = function(customer) { - return customerTemplate({ - customer: customer, - bill_address: customer.bill_address, - ship_address: customer.ship_address - }) - } - - if ($("#customer_search").length > 0) { - $("#customer_search").select2({ - placeholder: Spree.translations.choose_a_customer, - ajax: { - url: Spree.routes.users_api, - params: { "headers": { "X-Spree-Token": Spree.api_key } }, - datatype: 'json', - data: function(term, page) { - return { - q: { - m: 'or', - email_start: term, - addresses_firstname_start: term, - addresses_lastname_start: term - } - } - }, - results: function(data, page) { - return { - results: data.users, - more: data.current_page < data.pages - } - } - }, - dropdownCssClass: 'customer_search', - formatResult: formatCustomerResult, - formatSelection: function (customer) { - return Select2.util.escapeMarkup(customer.email); - } - }) - - $("#customer_search").on("select2-selecting", function(e) { - var customer = e.choice; - $('#order_email').val(customer.email); - $('#user_id').val(customer.id); - $('#guest_checkout_true').prop("checked", false); - $('#guest_checkout_false').prop("checked", true); - $('#guest_checkout_false').prop("disabled", false); - - var billAddress = customer.bill_address; - if (billAddress) { - $('#order_bill_address_attributes_firstname').val(billAddress.firstname); - $('#order_bill_address_attributes_lastname').val(billAddress.lastname); - $('#order_bill_address_attributes_address1').val(billAddress.address1); - $('#order_bill_address_attributes_address2').val(billAddress.address2); - $('#order_bill_address_attributes_city').val(billAddress.city); - $('#order_bill_address_attributes_zipcode').val(billAddress.zipcode); - $('#order_bill_address_attributes_phone').val(billAddress.phone); - - $('#order_bill_address_attributes_country_id').select2("val", billAddress.country_id).promise().done(function () { - update_state('b', function () { - $('#order_bill_address_attributes_state_id').select2("val", billAddress.state_id); - }); - }); - } +$(function() { + if($(".js-customer-details").length) { + var order = new Spree.Models.Order({ + bill_address: {}, + ship_address: {} + }); + new Spree.Views.Order.CustomerDetails({ + el: $(".js-customer-details"), + model: order }); } - - var order_use_billing_input = $('input#order_use_billing'); - - var order_use_billing = function () { - if (!order_use_billing_input.is(':checked')) { - $('#shipping').show(); - } else { - $('#shipping').hide(); - } - }; - - order_use_billing_input.click(function() { - order_use_billing(); - }); - - order_use_billing(); - - $('#guest_checkout_true').change(function() { - $('#customer_search').val(""); - $('#user_id').val(""); - $('#checkout_email').val(""); - - var fields = ["firstname", "lastname", "company", "address1", "address2", - "city", "zipcode", "state_id", "country_id", "phone"] - $.each(fields, function(i, field) { - $('#order_bill_address_attributes' + field).val(""); - $('#order_ship_address_attributes' + field).val(""); - }) - }); }); diff --git a/backend/app/assets/javascripts/spree/backend/collections/index.js b/backend/app/assets/javascripts/spree/backend/collections/index.js index b8194ae6c50..3e58d183d79 100644 --- a/backend/app/assets/javascripts/spree/backend/collections/index.js +++ b/backend/app/assets/javascripts/spree/backend/collections/index.js @@ -1 +1,2 @@ //= require spree/backend/collections/line_items +//= require spree/backend/collections/states diff --git a/backend/app/assets/javascripts/spree/backend/collections/states.js b/backend/app/assets/javascripts/spree/backend/collections/states.js new file mode 100644 index 00000000000..60001ee15f5 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/collections/states.js @@ -0,0 +1,13 @@ +Spree.Collections.States = Backbone.Collection.extend({ + initialize: function (models, options) { + this.country_id = options.country_id + }, + + url: function () { + return Spree.routes.states_search + "?country_id=" + this.country_id + }, + + parse: function(resp, options) { + return resp.states; + } +}) diff --git a/backend/app/assets/javascripts/spree/backend/models/address.js b/backend/app/assets/javascripts/spree/backend/models/address.js new file mode 100644 index 00000000000..574a87b722c --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/models/address.js @@ -0,0 +1,2 @@ +Spree.Models.Address = Backbone.Model.extend({ +}) diff --git a/backend/app/assets/javascripts/spree/backend/models/order.js b/backend/app/assets/javascripts/spree/backend/models/order.js index ce2fb833efe..c7f213f2bf8 100644 --- a/backend/app/assets/javascripts/spree/backend/models/order.js +++ b/backend/app/assets/javascripts/spree/backend/models/order.js @@ -1,5 +1,6 @@ //= require spree/backend/routes //= require spree/backend/collections/line_items +//= require spree/backend/models/address Spree.Models.Order = Backbone.Model.extend({ urlRoot: Spree.routes.orders_api, @@ -7,7 +8,9 @@ Spree.Models.Order = Backbone.Model.extend({ relations: { "line_items": Spree.Collections.LineItems, - "shipments": Backbone.Collection + "shipments": Backbone.Collection, + "bill_address": Spree.Models.Address, + "ship_address": Spree.Models.Address }, advance: function(opts) { @@ -25,7 +28,9 @@ Spree.Models.Order.fetch = function(number, opts) { var model = new Spree.Models.Order({ number: number, line_items: [], - shipments: [] + shipments: [], + bill_address: {}, + ship_address: {}, }); model.fetch(options); return model; diff --git a/backend/app/assets/javascripts/spree/backend/views/index.js b/backend/app/assets/javascripts/spree/backend/views/index.js index 98e374532da..2578ca92f9d 100644 --- a/backend/app/assets/javascripts/spree/backend/views/index.js +++ b/backend/app/assets/javascripts/spree/backend/views/index.js @@ -1,6 +1,10 @@ //= require 'spree/backend/views/cart/add_line_item_button' //= require 'spree/backend/views/cart/line_item_row' //= require 'spree/backend/views/cart/line_item_table' +//= require 'spree/backend/views/order/address' //= require 'spree/backend/views/order/details_adjustments' //= require 'spree/backend/views/order/details_total' +//= require 'spree/backend/views/order/customer_details' +//= require 'spree/backend/views/order/customer_select' //= require 'spree/backend/views/order/summary' +//= require 'spree/backend/views/state_select' diff --git a/backend/app/assets/javascripts/spree/backend/views/order/address.js b/backend/app/assets/javascripts/spree/backend/views/order/address.js new file mode 100644 index 00000000000..0051da5b85f --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/order/address.js @@ -0,0 +1,52 @@ +Spree.Views.Order.Address = Backbone.View.extend({ + initialize: function(options) { + this.$(".js-country_id").select2(); + + // read initial values from page + this.onChange(); + + this.render(); + this.listenTo(this.model, "change", this.render); + + this.stateSelect = + new Spree.Views.StateSelect({ + model: this.model, + el: this.$el + }); + }, + + events: { + "change": "onChange", + }, + + onChange: function() { + this.model.set(this.getValues()) + }, + + eachField: function(callback){ + var view = this; + var fields = ["firstname", "lastname", "company", "address1", "address2", + "city", "zipcode", "phone"]; + _.each(fields, function(field) { + var el = view.$('[name$="[' + field + ']"]'); + if (el.length) callback(field, el); + }); + }, + + getValues: function() { + var attributes = {}; + this.eachField(function(name, el) { + attributes[name] = el.val(); + }); + attributes['country_id'] = this.$(".js-country_id").select2("val") + return attributes; + }, + + render: function() { + var model = this.model; + this.eachField(function(name, el) { + el.val(model.get(name)) + }) + this.$(".js-country_id").select2("val", this.model.get("country_id")) + } +}); diff --git a/backend/app/assets/javascripts/spree/backend/views/order/customer_details.js b/backend/app/assets/javascripts/spree/backend/views/order/customer_details.js new file mode 100644 index 00000000000..46d425b4f95 --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/order/customer_details.js @@ -0,0 +1,68 @@ +Spree.Views.Order.CustomerDetails = Backbone.View.extend({ + initialize: function() { + this.billAddressView = + new Spree.Views.Order.Address({ + model: this.model.get("bill_address"), + el: this.$('.js-billing-address') + }); + + this.shipAddressView = + new Spree.Views.Order.Address({ + model: this.model.get("ship_address"), + el: this.$('.js-shipping-address') + }); + + this.customerSelectView = + new Spree.Views.Order.CustomerSelect({ + el: this.$('#customer_search') + }); + this.listenTo(this.customerSelectView, "select", this.onSelectCustomer); + + this.onGuestCheckoutChanged(); + this.onChange(); + + this.listenTo(this.model, "change", this.render) + this.render() + }, + + events: { + "click #guest_checkout_true": "onGuestCheckoutChanged", + "click #order_use_billing": "onChange", + "change #order_email": "onChange" + }, + + onGuestCheckoutChanged: function() { + if(this.$('#guest_checkout_true').is(':checked')) { + this.model.set({user_id: null}) + } + }, + + onChange: function() { + this.model.set({ + use_billing: this.$('#order_use_billing').is(':checked'), + email: this.$("#order_email").val() + }) + }, + + onSelectCustomer: function(customer) { + this.model.set({ + email: customer.email, + user_id: customer.id, + bill_address: customer.bill_address + }) + }, + + render: function() { + var user_id = this.model.get("user_id") + this.$("#user_id").val(user_id); + this.$('#guest_checkout_true') + .prop("checked", !user_id); + this.$('#guest_checkout_false') + .prop("checked", !!user_id) + .prop("disabled", !user_id); + + this.$('#shipping').toggleClass("hidden", !!this.model.get("use_billing")); + this.$('#order_email').val(this.model.get("email")) + } +}) + diff --git a/backend/app/assets/javascripts/spree/backend/views/order/customer_select.js b/backend/app/assets/javascripts/spree/backend/views/order/customer_select.js new file mode 100644 index 00000000000..c21750d625c --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/order/customer_select.js @@ -0,0 +1,55 @@ +Spree.Views.Order.CustomerSelect = Backbone.View.extend({ + initialize: function() { + this.render(); + }, + + events: { + "select2-selecting": "onSelect" + }, + + onSelect: function(e) { + var customer = e.choice; + this.trigger("select", customer) + }, + + render: function() { + var customerTemplate = HandlebarsTemplates['orders/customer_details/autocomplete']; + + var formatCustomerResult = function(customer) { + return customerTemplate({ + customer: customer, + bill_address: customer.bill_address, + ship_address: customer.ship_address + }) + } + + this.$el.select2({ + placeholder: Spree.translations.choose_a_customer, + ajax: { + url: Spree.routes.users_api, + params: { "headers": { "X-Spree-Token": Spree.api_key } }, + datatype: 'json', + data: function(term, page) { + return { + q: { + m: 'or', + email_start: term, + addresses_firstname_start: term, + addresses_lastname_start: term + } + } + }, + results: function(data, page) { + return { + results: data.users, + more: data.current_page < data.pages + } + } + }, + formatResult: formatCustomerResult, + formatSelection: function (customer) { + return Select2.util.escapeMarkup(customer.email); + } + }) + } +}); diff --git a/backend/app/assets/javascripts/spree/backend/views/state_select.js b/backend/app/assets/javascripts/spree/backend/views/state_select.js new file mode 100644 index 00000000000..baf523e967a --- /dev/null +++ b/backend/app/assets/javascripts/spree/backend/views/state_select.js @@ -0,0 +1,71 @@ +Spree.Views.StateSelect = Backbone.View.extend({ + initialize: function() { + this.states = {} // null object + + this.$state_select = this.$('.js-state_id'); + this.$state_input = this.$('.js-state_name'); + + // read initial values from page + this.model.set({ + state_name: this.$state_input.val(), + state_id: this.$state_select.val() + }) + + this.updateStates(); + this.listenTo(this.model, 'change:country_id', this.updateStates) + this.render(); + }, + + events: { + "change .js-state_name": "onChange", + "change .js-state_id": "onChange", + }, + + onChange: function() { + this.model.set({ + state_name: this.$state_input.val(), + state_id: this.$state_select.select2("val") + }) + }, + + updateStates: function() { + this.stopListening(this.states); + var country_id = this.model.get("country_id"); + if (country_id) { + this.states = Spree.Views.StateSelect.stateCache(country_id); + this.listenTo(this.states, "sync", this.render); + this.render(); + } + }, + + render: function() { + this.$state_select.empty().select2("destroy").hide(); + this.$state_input.hide(); + + if (!this.states.fetched) { + this.$state_select.show().select2().select2("disable"); + } else if (this.states.length) { + var $state_select = this.$state_select; + this.states.each(function(state) { + $state_select.append( + $('