diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee index 23bfb37738..aefcab9f90 100644 --- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee +++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee @@ -1,6 +1,5 @@ -angular.module("admin.customers").controller "customersCtrl", ($scope, $q, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops) -> +angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops) -> $scope.shops = shops - $scope.CurrentShop = CurrentShop $scope.RequestMonitor = RequestMonitor $scope.submitAll = pendingChanges.submitAll $scope.add = Customers.add @@ -8,15 +7,21 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, Custo $scope.customerLimit = 20 $scope.columns = Columns.columns - $scope.$watch "CurrentShop.shop", -> - if $scope.CurrentShop.shop.id? - Customers.index({enterprise_id: $scope.CurrentShop.shop.id}).then (data) -> + $scope.confirmRefresh = (event) -> + event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning")) + + $scope.$watch "shop_id", -> + if $scope.shop_id? + CurrentShop.shop = $filter('filter')($scope.shops, {id: $scope.shop_id})[0] + Customers.index({enterprise_id: $scope.shop_id}).then (data) -> + pendingChanges.removeAll() + $scope.customers_form.$setPristine() $scope.customers = data $scope.findTags = (query) -> defer = $q.defer() params = - enterprise_id: $scope.CurrentShop.shop.id + enterprise_id: $scope.shop_id TagRuleResource.mapByTag params, (data) => filtered = data.filter (tag) -> tag.text.toLowerCase().indexOf(query.toLowerCase()) != -1 diff --git a/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee b/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee index bbb5221682..d65341e6fe 100644 --- a/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee +++ b/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee @@ -7,6 +7,7 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout, text: "@?" blank: "=?" filter: "=?" + onSelecting: "=?" link: (scope, element, attrs, ngModel) -> $timeout -> scope.text ||= 'name' @@ -24,6 +25,8 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout, formatResult: (item) -> item[scope.text] + element.on "select2-opening", scope.onSelecting || angular.noop + attrs.$observe 'disabled', (value) -> element.select2('enable', !value) diff --git a/app/assets/javascripts/admin/index_utils/services/pending_changes.js.coffee b/app/assets/javascripts/admin/index_utils/services/pending_changes.js.coffee index 15626b1479..a3d842c16d 100644 --- a/app/assets/javascripts/admin/index_utils/services/pending_changes.js.coffee +++ b/app/assets/javascripts/admin/index_utils/services/pending_changes.js.coffee @@ -10,6 +10,8 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta removeAll: => @pendingChanges = {} + StatusMessage.clear() + remove: (id, attr) => if @pendingChanges.hasOwnProperty("#{id}") @@ -40,5 +42,8 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta @errors.push error change.scope.error() + unsavedCount: -> + Object.keys(@pendingChanges).length + changeCount: (objectChanges) -> Object.keys(objectChanges).length diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 7e82536526..65523cda57 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -14,21 +14,25 @@ = admin_inject_shops %div{ ng: { controller: 'customersCtrl' } } - .row - .five.columns.alpha - %h3 - =t :please_select_hub - .four.columns - %select.select2.fullwidth#shop_id{ 'ng-model' => 'CurrentShop.shop', name: 'shop_id', 'ng-options' => 'shop as shop.name for shop in shops' } - .seven.columns.omega   + .row.filters + .sixteen.columns.alpha.omega + .filter_select.five.columns.alpha + %label{ :for => 'quick_search', ng: {class: '{disabled: !shop_id}'} }=t('admin.quick_search') + %br + %input.fullwidth{ :type => "text", :id => 'quick_search', ng: { model: 'quickSearch', disabled: '!shop_id' }, :placeholder => "Search by email/code..." } + .filter_select.four.columns + %label{ :for => 'hub_id', ng: { bind: "shop_id ? '#{t('admin.shop')}' : '#{t('admin.variant_overrides.index.select_a_shop')}'" } } + %br + %input.ofn-select2.fullwidth#shop_id{ 'ng-model' => 'shop_id', name: 'shop_id', data: 'shops', on: { selecting: 'confirmRefresh' } } + .seven.columns.omega   - .row{ 'ng-hide' => 'RequestMonitor.loading || !CurrentShop.shop.id || customers.length == 0' } - .controls.sixteen.columns.alpha.omega - .five.columns.alpha - %input.fullwidth{ :type => "text", :id => 'quick_search', 'ng-model' => 'quickSearch', :placeholder => 'Quick Search' } - .eight.columns   - %columns-dropdown{ action: "#{controller_name}_#{action_name}" } - .row{ 'ng-if' => 'CurrentShop.shop.id && RequestMonitor.loading' } + %hr.divider{ ng: { show: "!RequestMonitor.loading && filteredCustomers.length > 0" } } + + .row.controls{ ng: { show: "!RequestMonitor.loading && filteredCustomers.length > 0" } } + .thirteen.columns.alpha   + %columns-dropdown{ action: "#{controller_name}_#{action_name}" } + + .row{ 'ng-if' => 'shop_id && RequestMonitor.loading' } .sixteen.columns.alpha#loading %img.spinner{ src: "/assets/spinning-circles.svg" } %h1 diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 964608510d..3a17c06e32 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -5,14 +5,16 @@ feature 'Customers' do include WebHelper context "as an enterprise user" do - let(:user) { create_enterprise_user } - let(:managed_distributor) { create(:distributor_enterprise, owner: user) } + let(:user) { create_enterprise_user(enterprise_limit: 10) } + let(:managed_distributor1) { create(:distributor_enterprise, owner: user) } + let(:managed_distributor2) { create(:distributor_enterprise, owner: user) } let(:unmanaged_distributor) { create(:distributor_enterprise) } describe "using the customers index", js: true do - let!(:customer1) { create(:customer, enterprise: managed_distributor) } - let!(:customer2) { create(:customer, enterprise: managed_distributor) } + let!(:customer1) { create(:customer, enterprise: managed_distributor1) } + let!(:customer2) { create(:customer, enterprise: managed_distributor1) } let!(:customer3) { create(:customer, enterprise: unmanaged_distributor) } + let!(:customer4) { create(:customer, enterprise: managed_distributor2) } before do quick_login_as user @@ -21,14 +23,15 @@ feature 'Customers' do it "passes the smoke test" do # Prompts for a hub for a list of my managed enterprises - expect(page).to have_select2 "shop_id", with_options: [managed_distributor.name], without_options: [unmanaged_distributor.name] + expect(page).to have_select2 "shop_id", with_options: [managed_distributor1.name,managed_distributor2.name], without_options: [unmanaged_distributor.name] - select2_select managed_distributor.name, from: "shop_id" + select2_select managed_distributor1.name, from: "shop_id" # Loads the right customers expect(page).to have_selector "tr#c_#{customer1.id}" expect(page).to have_selector "tr#c_#{customer2.id}" expect(page).to_not have_selector "tr#c_#{customer3.id}" + expect(page).to_not have_selector "tr#c_#{customer4.id}" # Searching fill_in "quick_search", with: customer2.email @@ -43,10 +46,19 @@ feature 'Customers' do first("div#columns-dropdown div.menu div.menu_item", text: "Email").click expect(page).to_not have_selector "th.email" expect(page).to_not have_content customer1.email + + # Changing Shops + select2_select managed_distributor2.name, from: "shop_id" + + # Loads the right customers + expect(page).to_not have_selector "tr#c_#{customer1.id}" + expect(page).to_not have_selector "tr#c_#{customer2.id}" + expect(page).to_not have_selector "tr#c_#{customer3.id}" + expect(page).to have_selector "tr#c_#{customer4.id}" end it "allows updating of attributes" do - select2_select managed_distributor.name, from: "shop_id" + select2_select managed_distributor1.name, from: "shop_id" within "tr#c_#{customer1.id}" do fill_in "code", with: "new-customer-code" @@ -78,7 +90,7 @@ feature 'Customers' do context "when a shop is selected" do before do - select2_select managed_distributor.name, from: "shop_id" + select2_select managed_distributor1.name, from: "shop_id" end it "creates customers when the email provided is valid" do @@ -88,21 +100,21 @@ feature 'Customers' do fill_in 'email', with: "not_an_email" click_button 'Add Customer' expect(page).to have_selector "#new-customer-dialog .error", text: "Please enter a valid email address" - }.to_not change{Customer.of(managed_distributor).count} + }.to_not change{Customer.of(managed_distributor1).count} # When an existing email is used expect{ fill_in 'email', with: customer1.email click_button 'Add Customer' expect(page).to have_selector "#new-customer-dialog .error", text: "Email is associated with an existing customer" - }.to_not change{Customer.of(managed_distributor).count} + }.to_not change{Customer.of(managed_distributor1).count} # When a new valid email is used expect{ fill_in 'email', with: "new@email.com" click_button 'Add Customer' expect(page).not_to have_selector "#new-customer-dialog" - }.to change{Customer.of(managed_distributor).count}.from(2).to(3) + }.to change{Customer.of(managed_distributor1).count}.from(2).to(3) end end end diff --git a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee index 7854700dfd..fca4c6744f 100644 --- a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee @@ -1,6 +1,7 @@ describe "CustomersCtrl", -> scope = null http = null + shops = null beforeEach -> module('admin.customers') @@ -8,28 +9,46 @@ describe "CustomersCtrl", -> $provide.value 'columns', [] null + shops = [ + { name: "Shop 1", id: 1 } + { name: "Shop 2", id: 2 } + { name: "Shop 3", id: 3 } + ] + + inject ($controller, $rootScope, _CustomerResource_, $httpBackend) -> scope = $rootScope http = $httpBackend - $controller 'customersCtrl', {$scope: scope, CustomerResource: _CustomerResource_, shops: {}} + $controller 'customersCtrl', {$scope: scope, CustomerResource: _CustomerResource_, shops: shops} jasmine.addMatchers toDeepEqual: (util, customEqualityTesters) -> compare: (actual, expected) -> { pass: angular.equals(actual, expected) } - it "has no shop pre-selected", -> - expect(scope.CurrentShop.shop).toEqual {} + it "has no shop pre-selected", inject (CurrentShop) -> + expect(CurrentShop.shop).toEqual {} describe "setting the shop on scope", -> customer = { id: 5, email: 'someone@email.com'} customers = [customer] - beforeEach -> - http.expectGET('/admin/customers.json?enterprise_id=1').respond 200, customers + beforeEach inject (pendingChanges) -> + spyOn(pendingChanges, "removeAll") + scope.customers_form = jasmine.createSpyObj('customers_form', ['$setPristine']) + http.expectGET('/admin/customers.json?enterprise_id=3').respond 200, customers scope.$apply -> - scope.CurrentShop.shop = {id: 1} + scope.shop_id = 3 http.flush() + it "sets the CurrentShop", inject (CurrentShop) -> + expect(CurrentShop.shop).toEqual shops[2] + + it "sets the form state to pristine", -> + expect(scope.customers_form.$setPristine).toHaveBeenCalled() + + it "clears all changes", inject (pendingChanges) -> + expect(pendingChanges.removeAll).toHaveBeenCalled() + it "retrievs the list of customers", -> expect(scope.customers).toDeepEqual customers @@ -38,7 +57,7 @@ describe "CustomersCtrl", -> email = "customer@example.org" newCustomer = {id: 6, email: email} customers.unshift(newCustomer) - http.expectPOST('/admin/customers.json?email=' + email + '&enterprise_id=1').respond 200, newCustomer + http.expectPOST('/admin/customers.json?email=' + email + '&enterprise_id=3').respond 200, newCustomer scope.add(email) http.flush() expect(scope.customers).toDeepEqual customers @@ -60,7 +79,7 @@ describe "CustomersCtrl", -> { text: 'three' } ] beforeEach -> - http.expectGET('/admin/tag_rules/map_by_tag.json?enterprise_id=1').respond 200, tags + http.expectGET('/admin/tag_rules/map_by_tag.json?enterprise_id=3').respond 200, tags it "retrieves the tag list", -> promise = scope.findTags('')