Preventing shop from being changed when unsaved customer changes exist

Also making layout of filters on customer index more consistent with other pages
This commit is contained in:
Rob Harrington
2016-06-16 15:10:16 +10:00
parent fb33be78dd
commit 25cdd4af8e
6 changed files with 87 additions and 39 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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('')