move url filter functionality to service ProductFiltersService

This commit is contained in:
Gaetan Riou
2020-08-07 18:10:51 +10:00
parent bba683469b
commit 7356d0fe77
6 changed files with 151 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, $httpParamSerializer, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser) ->
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser, ProductFiltersService) ->
$scope.StatusMessage = StatusMessage
$scope.columns = Columns.columns
@@ -14,11 +14,13 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
]
productFilters = ['producerFilter', 'categoryFilter', 'query', 'sorting', 'importDateFilter']
$scope.producerFilter = ""
$scope.categoryFilter = ""
$scope.importDateFilter = ""
$scope.query = ""
$scope.sorting = ""
$scope.q = {
producerFilter: ""
categoryFilter: ""
importDateFilter: ""
query: ""
sorting: ""
}
$scope.producers = producers
$scope.taxons = Taxons.all
@@ -30,13 +32,8 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.sortOptions = SortOptions
loadFilterFromUrl = ->
filters = $location.search()
for filter in productFilters
$scope[filter] = if filters[filter] then filters[filter] else ""
$scope.initialise = ->
loadFilterFromUrl()
$scope.q = ProductFiltersService.loadFromUrl($location.search())
$scope.fetchProducts()
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter, per_page]', ->
@@ -50,33 +47,33 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
filters = {}
for filter in productFilters
filters[filter] = $scope[filter] if $scope[filter]
filters
$scope.fetchProducts = ->
removeClearedValues()
params = {
'q[name_cont]': $scope.query,
'q[supplier_id_eq]': $scope.producerFilter,
'q[primary_taxon_id_eq]': $scope.categoryFilter,
'q[s]': $scope.sorting,
import_date: $scope.importDateFilter,
'q[name_cont]': $scope.q.query,
'q[supplier_id_eq]': $scope.q.producerFilter,
'q[primary_taxon_id_eq]': $scope.q.categoryFilter,
'q[s]': $scope.q.sorting,
import_date: $scope.q.importDateFilter,
page: $scope.page,
per_page: $scope.per_page
}
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
# update url with the filters used
$location.search(generateFilter())
$location.search(ProductFiltersService.generate($scope.q))
$scope.resetProducts()
removeClearedValues = ->
delete $scope.producerFilter if $scope.producerFilter == "0"
delete $scope.categoryFilter if $scope.categoryFilter == "0"
delete $scope.importDateFilter if $scope.importDateFilter == "0"
delete $scope.q.producerFilter if $scope.q.producerFilter == "0"
delete $scope.q.categoryFilter if $scope.q.categoryFilter == "0"
delete $scope.q.importDateFilter if $scope.q.importDateFilter == "0"
$timeout ->
if $scope.showLatestImport
$scope.importDateFilter = $scope.importDates[1].id
$scope.q.importDateFilter = $scope.importDates[1].id
$scope.resetProducts = ->
DirtyProducts.clear()
@@ -106,10 +103,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.visibleTab = tab
$scope.resetSelectFilters = ->
$scope.query = ""
$scope.producerFilter = "0"
$scope.categoryFilter = "0"
$scope.importDateFilter = "0"
$scope.q.query = ""
$scope.q.producerFilter = "0"
$scope.q.categoryFilter = "0"
$scope.q.importDateFilter = "0"
$scope.fetchProducts()
$scope.$watch 'sortOptions', (sort) ->
@@ -127,9 +124,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.editWarn = (product, variant) ->
if confirm_unsaved_changes()
filterUrl = $httpParamSerializer(generateFilter())
filterUrl = "?#{filterUrl}" if filterUrl isnt ""
$window.location.href = "#{editProductUrl(product, variant)}#{filterUrl}"
$window.location.href = ProductFiltersService.buildUrl(editProductUrl(product, variant), $scope.q)
$scope.toggleShowAllVariants = ->
showVariants = !DisplayProperties.showVariants 0
@@ -226,10 +221,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
data:
products: productsToSubmit
filters:
'q[name_cont]': $scope.query
'q[supplier_id_eq]': $scope.producerFilter
'q[primary_taxon_id_eq]': $scope.categoryFilter
import_date: $scope.importDateFilter
'q[name_cont]': $scope.q.query
'q[supplier_id_eq]': $scope.q.producerFilter
'q[primary_taxon_id_eq]': $scope.q.categoryFilter
import_date: $scope.q.importDateFilter
page: $scope.page
per_page: $scope.per_page
).success((data) ->

View File

@@ -5,8 +5,8 @@ angular.module("ofn.admin").directive "ofnSelect2MinSearch", ->
minimumResultsForSearch: attrs.ofnSelect2MinSearch
ngModel.$formatters.push (value) ->
# select2 populate options with a value like "number:3" or "string:category" but
# select2('val', value) doesn't do the translation for us as one would expect
# select2 populates options with a value like "number:3" or "string:category" but
# select2('val', value) doesn't do the type conversion for us as one would expect
if isNaN(value)
element.select2('val', "string:#{value}")
else

View File

@@ -0,0 +1,23 @@
angular.module("ofn.admin").factory "ProductFiltersService", ($httpParamSerializer) ->
new class ProductFiltersService
productFilters: ['producerFilter', 'categoryFilter', 'query', 'sorting', 'importDateFilter']
loadFromUrl: (filters) ->
loadedFilters = {}
for filter in @productFilters
loadedFilters[filter] = if filters[filter] then filters[filter] else ""
loadedFilters
generate: (ctrlFilters) ->
filters = {}
for filter in @productFilters
filters[filter] = ctrlFilters[filter] if ctrlFilters[filter]
filters
buildUrl: (baseUrl, ctrlFilters) ->
filterUrl = $httpParamSerializer(@generate(ctrlFilters))
filterUrl = "?#{filterUrl}" if filterUrl isnt ""
"#{baseUrl}#{filterUrl}"

View File

@@ -5,20 +5,20 @@
.quick_search.three.columns.alpha
%label{ for: 'quick_filter' }
%br
%input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
%input.quick-search.fullwidth{ ng: {model: 'q.query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
.one.columns  
.filter_select.three.columns
%label{ for: 'producer_filter' }= t 'producer'
%br
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'producerFilter', options: 'producer.id as producer.name for producer in producers'} }
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.producerFilter', options: 'producer.id as producer.name for producer in producers'} }
.filter_select.three.columns
%label{ for: 'category_filter' }= t 'category'
%br
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
.filter_select.three.columns
%label{ for: 'import_filter' } Import Date
%br
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}", options: 'date.id as date.name for date in importDates'} }
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}", options: 'date.id as date.name for date in importDates'} }
.filter_clear.three.columns.omega
%label{ for: 'clear_all_filters' }

View File

@@ -246,7 +246,7 @@ describe "filtering products for submission to database", ->
]
describe "AdminProductEditCtrl", ->
$ctrl = $scope = $timeout = $httpBackend = BulkProducts = DirtyProducts = DisplayProperties = windowStub = null
$ctrl = $scope = $timeout = $httpBackend = BulkProducts = DirtyProducts = DisplayProperties = ProductFiltersService = windowStub = null
beforeEach ->
module "ofn.admin"
@@ -258,7 +258,7 @@ describe "AdminProductEditCtrl", ->
$provide.value 'columns', []
null
beforeEach inject((_$controller_, _$timeout_, $rootScope, _$httpBackend_, _BulkProducts_, _DirtyProducts_, _DisplayProperties_) ->
beforeEach inject((_$controller_, _$timeout_, $rootScope, _$httpBackend_, _BulkProducts_, _DirtyProducts_, _DisplayProperties_, _ProductFiltersService_) ->
$scope = $rootScope.$new()
$ctrl = _$controller_
$timeout = _$timeout_
@@ -266,8 +266,9 @@ describe "AdminProductEditCtrl", ->
BulkProducts = _BulkProducts_
DirtyProducts = _DirtyProducts_
DisplayProperties = _DisplayProperties_
ProductFiltersService = _ProductFiltersService_
# Stub the window object so we don't get redirected when href is updated
# Stub the window object so we don't get redirected when href is updated
windowStub = {navigator: {userAgent: 'foo'}, location: {href: ''}}
$ctrl "AdminProductEditCtrl", {$scope: $scope, $timeout: $timeout, $window: windowStub}
@@ -282,7 +283,7 @@ describe "AdminProductEditCtrl", ->
expect($scope.fetchProducts.calls.count()).toBe 1
it "gets a list of products applying filters from the url", inject ($location) ->
query = 'lala'
query = 'lala'
producerFilter = 2
categoryFilter = 5
sorting = 'name desc'
@@ -291,11 +292,11 @@ describe "AdminProductEditCtrl", ->
$scope.initialise()
expect($scope.query).toBe query
expect($scope.producerFilter).toBe producerFilter
expect($scope.categoryFilter).toBe categoryFilter
expect($scope.sorting).toBe sorting
expect($scope.importDateFilter).toBe importDateFilter
expect($scope.q.query).toBe query
expect($scope.q.producerFilter).toBe producerFilter
expect($scope.q.categoryFilter).toBe categoryFilter
expect($scope.q.sorting).toBe sorting
expect($scope.q.importDateFilter).toBe importDateFilter
describe "fetching products", ->
$q = null
@@ -316,18 +317,18 @@ describe "AdminProductEditCtrl", ->
$scope.$digest()
expect($scope.resetProducts).toHaveBeenCalled()
it "updates url wihth filter after data has been received", inject ($location, $window) ->
it "updates url with filter after data has been received", inject ($location, $window) ->
query = 'lala'
producerFilter = 2
categoryFilter = 5
sorting = 'name desc'
importDateFilter = '2020-06-08'
$scope.query = query
$scope.producerFilter = producerFilter
$scope.categoryFilter = categoryFilter
$scope.sorting = sorting
$scope.importDateFilter = importDateFilter
$scope.q.query = query
$scope.q.producerFilter = producerFilter
$scope.q.categoryFilter = categoryFilter
$scope.q.sorting = sorting
$scope.q.importDateFilter = importDateFilter
$scope.fetchProducts()
$scope.$digest()
@@ -995,14 +996,14 @@ describe "AdminProductEditCtrl", ->
it 'should load edit product page including the selected filters', inject ($httpParamSerializer) ->
query = 'lala'
category = 3
$scope.query = query
$scope.categoryFilter = category
$scope.q.query = query
$scope.q.categoryFilter = category
# use $httpParamSerializer as it will sort parameters alphabetically
expectedFilter = $httpParamSerializer({ query: query, categoryFilter: category })
$scope.editWarn(testProduct, null)
expect(windowStub.location.href).toBe(
"/admin/products/#{testProduct.permalink_live}/edit?#{expectedFilter}"
)
@@ -1010,13 +1011,13 @@ describe "AdminProductEditCtrl", ->
describe "filtering products", ->
describe "clearing filters", ->
it "resets filter variables", ->
$scope.query = "lala"
$scope.producerFilter = "5"
$scope.categoryFilter = "6"
$scope.q.query = "lala"
$scope.q.producerFilter = "5"
$scope.q.categoryFilter = "6"
$scope.resetSelectFilters()
expect($scope.query).toBe ""
expect($scope.producerFilter).toBeUndefined
expect($scope.categoryFilter).toBeUndefined
expect($scope.q.query).toBe ""
expect($scope.q.producerFilter).toBeUndefined
expect($scope.q.categoryFilter).toBeUndefined
describe "converting arrays of objects with ids to an object with ids as keys", ->

View File

@@ -0,0 +1,68 @@
describe "ProductFiltersService service", ->
ProductFiltersService = null
beforeEach ->
module "ofn.admin"
beforeEach inject (_ProductFiltersService_) ->
ProductFiltersService = _ProductFiltersService_
describe "loadFromUrl", ->
it "should return a hash with value populated for filters existing in parameter", ->
producerFilter = 2
query = 'fruit'
filters = ProductFiltersService.loadFromUrl(producerFilter: producerFilter, query: query)
expect(filters.producerFilter).toBe producerFilter
expect(filters.query).toBe query
it "should return a hash with empty value for filters missing from parameter", ->
filters = ProductFiltersService.loadFromUrl({})
expect(filters.producerFilter).toBe ""
expect(filters.query).toBe ""
expect(filters.categoryFilter).toBe ""
expect(filters.sorting).toBe ""
expect(filters.importDateFilter).toBe ""
describe "generate", ->
it 'should filter given hash with productFilters', ->
producerFilter = 2
query = 'fruit'
filters = ProductFiltersService.generate(
producerFilter: producerFilter, query: query, otherParam: 'otherParam'
)
expect(filters.producerFilter).toBe producerFilter
expect(filters.query).toBe query
expect(filters.otherParam).toBe undefined
describe "buildUrl", ->
it 'should return a url adding filters to the baseUrl', inject ($httpParamSerializer) ->
query = 'lala'
producerFilter = 2
categoryFilter = 5
sorting = 'name desc'
importDateFilter = '2020-06-08'
filters = {
producerFilter: producerFilter
categoryFilter: categoryFilter
query: query
sorting: sorting
importDateFilter: importDateFilter
}
baseUrl = "openfoodnetwork.org.au"
url = ProductFiltersService.buildUrl(baseUrl, filters)
expectedFilters = $httpParamSerializer(filters)
expect(url).toBe("#{baseUrl}?#{expectedFilters}")
it 'should return baseUrl if filters are empty', ->
baseUrl = "openfoodnetwork.org.au"
url = ProductFiltersService.buildUrl(baseUrl, {})
expect(url).toBe baseUrl