paging done, needs some additional refactoring
This commit is contained in:
@@ -16,6 +16,7 @@ before do
|
||||
headers 'Access-Control-Allow-Origin' => 'http://localhost:3001',
|
||||
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST','PUT'],
|
||||
'Access-Control-Allow-Headers' => 'Origin, X-Requested-With, Content-Type, Accept',
|
||||
'Access-Control-Expose-Headers' => 'X-Total-Count',
|
||||
'Access-Control-Allow-Credentials' => 'true'
|
||||
|
||||
request.body.rewind
|
||||
|
||||
@@ -3,6 +3,10 @@ def get_querystring_hash()
|
||||
Rack::Utils.parse_nested_query(request.query_string)
|
||||
end
|
||||
|
||||
def add_total_count_header(total)
|
||||
response.headers['X-Total-Count'] = total
|
||||
end
|
||||
|
||||
# converts list of parameters to array of integers
|
||||
def mass_to_i(*id_strings)
|
||||
id_strings.map(&:to_i)
|
||||
|
||||
@@ -21,7 +21,7 @@ end
|
||||
|
||||
def filter_by_traits(items)
|
||||
get_querystring_hash.each do |k,v|
|
||||
items = items.where(["traits ->> '#{k}' = '#{v}'"])
|
||||
items = items.where(["traits ->> ? = ?", k, v])
|
||||
end
|
||||
items
|
||||
end
|
||||
@@ -54,9 +54,12 @@ get '/item/category/:category_id/offset/:offset/limit/:limit' do |category_id_s,
|
||||
input_invalid = offset_and_limit_invalid?(offset,limit) or category_id <= 0
|
||||
return [].to_json if input_invalid
|
||||
|
||||
all_in_cat = filter_by_traits(Item.all_in_category(category_id))
|
||||
items = Item.best_selling_in_category(category_id, offset,limit)
|
||||
items = filter_by_traits(items)
|
||||
|
||||
add_total_count_header(all_in_cat.count)
|
||||
|
||||
prepare_items_for_mass_display(items)
|
||||
end
|
||||
|
||||
|
||||
@@ -10,7 +10,13 @@ class Item < ActiveRecord::Base
|
||||
|
||||
# TODO: change "best selling" algorithm when get some data - currently it's only sorted by earnings
|
||||
scope :best_selling, -> (offset, limit) { where(:on_display => true).order("(list_price - current_input_price) DESC").limit(limit).offset(offset) }
|
||||
|
||||
scope :best_selling_in_sub_category, -> (sub_category_id, offset, limit) { best_selling(offset, limit).where(sub_category_id: sub_category_id) }
|
||||
|
||||
scope :best_selling_in_category, -> (category_id, offset, limit) { best_selling(offset, limit).joins( sub_category: [:category] ).where(["category_id = ?", category_id]) }
|
||||
|
||||
scope :best_selling_in_section, -> (section_id, offset, limit) { best_selling(offset, limit).joins( sub_category: [category: [ :section ]] ).where( ["section_id = ?", section_id] ) }
|
||||
|
||||
scope :all_in_category, -> (category_id) { where(on_display: true).joins( sub_category: [:category]).where(["category_id = ?", category_id]) }
|
||||
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class SubCategory < ActiveRecord::Base
|
||||
belongs_to :category
|
||||
has_many :filter_criterias, as: :owner
|
||||
has_many :items
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ var ItemConstants = require('../constants/itemConstants');
|
||||
// Define action methods
|
||||
var ItemActions = {
|
||||
|
||||
loadByCategory: function(categoryId, query) {
|
||||
loadByCategory: function(categoryId, offset, limit, query) {
|
||||
AppDispatcher.handleAction({
|
||||
actionType: ItemConstants.LOAD_BY_CATEGORY,
|
||||
categoryId : categoryId,
|
||||
query : query
|
||||
query : query,
|
||||
offset : offset,
|
||||
limit: limit
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -21,20 +21,30 @@ var NavigationActions = {
|
||||
});
|
||||
},
|
||||
|
||||
goToCategory: function(category,section, query) {
|
||||
goToCategory: function(category,section, query, offset, limit) {
|
||||
var url ='/sekcija/' + section.get('name') +'/kategorija/'+ category.get('id') + '/' + category.get('name');
|
||||
|
||||
var q = '';
|
||||
var qp = [];
|
||||
|
||||
if(query) {
|
||||
var qp = [];
|
||||
for(var key in query) {
|
||||
if (query.hasOwnProperty(key)) {
|
||||
|
||||
if (key !== 'offset' && key !== 'limit' && query.hasOwnProperty(key)) {
|
||||
qp.push(key + '=' + query[key]);
|
||||
}
|
||||
}
|
||||
if (qp.length > 0) {
|
||||
q = '?' + qp.join('&');
|
||||
}
|
||||
}
|
||||
if (offset !== undefined) {
|
||||
qp.push('offset='+offset);
|
||||
}
|
||||
|
||||
if (limit !== undefined) {
|
||||
qp.push('limit='+limit);
|
||||
}
|
||||
|
||||
if (qp.length > 0) {
|
||||
q = '?' + qp.join('&');
|
||||
}
|
||||
AppDispatcher.handleAction({
|
||||
actionType: NavigationConstants.CHANGE_URL,
|
||||
|
||||
@@ -19,7 +19,8 @@ var ByCategory = React.createClass({
|
||||
return {
|
||||
category: category,
|
||||
items: items,
|
||||
filter :{}
|
||||
filter :{},
|
||||
pagination: {}
|
||||
};
|
||||
},
|
||||
filter: {},
|
||||
@@ -30,16 +31,24 @@ var ByCategory = React.createClass({
|
||||
var category = this.state.category;
|
||||
|
||||
this.filter[fc.field_name] = fcv.filter_value;
|
||||
NavigationActions.goToCategory(category, section, this.filter);
|
||||
NavigationActions.goToCategory(category, section, this.filter, 0, this.state.pagination.limit);
|
||||
},
|
||||
removeAppliedFilter: function(name) {
|
||||
delete this.filter[name];
|
||||
var section = new Section(this.state.category.get('section'));
|
||||
var category = this.state.category;
|
||||
NavigationActions.goToCategory(category, section, this.filter);
|
||||
NavigationActions.goToCategory(category, section, this.filter, 0, this.state.pagination.limit);
|
||||
|
||||
},
|
||||
changePage: function(page) {
|
||||
var section = new Section(this.state.category.get('section'));
|
||||
var category = this.state.category;
|
||||
|
||||
NavigationActions.goToCategory(category, section, this.filter, parseInt(page) * this.state.pagination.limit, this.state.pagination.limit);
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='col-md-2'>
|
||||
@@ -54,7 +63,7 @@ var ByCategory = React.createClass({
|
||||
{this.state.category.get('filter_criterias').map(function(fc) {
|
||||
return (<div>
|
||||
|
||||
<div className='h4'>{fc.title}</div>
|
||||
<div className='h4' style={{color: '#cd3071'}}>{fc.title}</div>
|
||||
<ul>
|
||||
{fc.filter_criteria_values.map(function(fcv) {
|
||||
return (<li>
|
||||
@@ -68,7 +77,7 @@ var ByCategory = React.createClass({
|
||||
|
||||
<div className='col-md-10'>
|
||||
|
||||
<h3> Browse products by category : {this.state.category.get('name')}</h3>
|
||||
<h3> Kategorija - {this.state.category.get('name')}</h3>
|
||||
Number of items in this category: {this.state.items.length}
|
||||
<div>
|
||||
{this.appliedCategoryFiltersArray().map(function(acf) {
|
||||
@@ -80,7 +89,8 @@ var ByCategory = React.createClass({
|
||||
</div>
|
||||
|
||||
|
||||
<ItemList items={this.state.items} />
|
||||
<div> total count is : {this.state.items.totalCount}</div>
|
||||
<ItemList items={this.state.items} paginationEnabled={true} total={this.state.items.totalCount} limit={this.state.pagination.limit} onPageChange={this.changePage} currentOffset={this.state.pagination.offset} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -88,7 +98,7 @@ var ByCategory = React.createClass({
|
||||
appliedCategoryFiltersArray: function() {
|
||||
var filters = [];
|
||||
for(var key in this.state.filter) {
|
||||
if(this.state.filter.hasOwnProperty(key)) {
|
||||
if(this.state.filter.hasOwnProperty(key) && key !== 'limit' && key !== 'offset') {
|
||||
filters.push({name: key, value: this.state.filter[key]});
|
||||
}
|
||||
}
|
||||
@@ -98,21 +108,36 @@ var ByCategory = React.createClass({
|
||||
var categoryId = this.getParams().id;
|
||||
|
||||
this.filter = this.getQuery();
|
||||
var offset = this.filter.offset || 0;
|
||||
var limit = this.filter.limit || 30;
|
||||
|
||||
|
||||
this.setState({
|
||||
filter: this.filter
|
||||
filter: this.filter,
|
||||
pagination: {
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}
|
||||
});
|
||||
ItemActions.loadByCategory(categoryId, this.filter);
|
||||
ItemActions.loadByCategory(categoryId, offset, limit, this.filter);
|
||||
CategoryActions.loadCategoryDetails(categoryId);
|
||||
},
|
||||
componentDidMount: function() {
|
||||
var categoryId = this.getParams().id;
|
||||
|
||||
this.filter = this.getQuery();
|
||||
|
||||
var offset = this.filter.offset || 0;
|
||||
var limit = this.filter.limit || 30;
|
||||
this.setState({
|
||||
filter: this.filter
|
||||
filter: this.filter,
|
||||
pagination: {
|
||||
offset: offset,
|
||||
limit: limit
|
||||
}
|
||||
});
|
||||
|
||||
ItemActions.loadByCategory(categoryId, this.getQuery());
|
||||
ItemActions.loadByCategory(categoryId, offset, limit, this.getQuery());
|
||||
CategoryActions.loadCategoryDetails(categoryId);
|
||||
|
||||
ItemStore.addChangeListener(this._onChange);
|
||||
|
||||
@@ -3,7 +3,12 @@ var SingleItem = require('./singleItem');
|
||||
var ItemCollection = require('../../models/itemCollection.js');
|
||||
|
||||
var ItemList = React.createClass({
|
||||
|
||||
changePage: function(page, e) {
|
||||
e.preventDefault();
|
||||
if(this.props.onPageChange) {
|
||||
this.props.onPageChange(page);
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
|
||||
var items = this.props.items.models.map( function(item) {
|
||||
@@ -18,10 +23,50 @@ var ItemList = React.createClass({
|
||||
<ul className="item_list">
|
||||
{items}
|
||||
</ul>
|
||||
{this.getPages()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
getPages: function() {
|
||||
if (!this.props.paginationEnabled) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var nrOfPages = Math.ceil(this.props.total/ this.props.limit);
|
||||
if (nrOfPages === 1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var maxSlots = 3;
|
||||
var selectedIndex = Math.floor(this.props.currentOffset / this.props.limit);
|
||||
|
||||
var start, end;
|
||||
start = selectedIndex - Math.floor(maxSlots / 2);
|
||||
end = selectedIndex + Math.floor(maxSlots / 2 ) + 1;
|
||||
|
||||
if (start < 0) start = 0;
|
||||
if (end > nrOfPages) end = nrOfPages;
|
||||
|
||||
if ((end - start) < maxSlots) {
|
||||
start = Math.max(0, end - maxSlots);
|
||||
end = Math.min(nrOfPages, start + maxSlots);
|
||||
}
|
||||
|
||||
var pages = [];
|
||||
for(var i = start; i < end; i++) {
|
||||
var cn = i === selectedIndex ? "active": "";
|
||||
pages.push(<li className={cn}><a onClick={this.changePage.bind(this, i)}href="#">{i + 1}</a></li>)
|
||||
}
|
||||
|
||||
return (
|
||||
<nav>
|
||||
<ul className="pagination">
|
||||
|
||||
{pages}
|
||||
</ul>
|
||||
</nav>)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ var ItemCollection = Backbone.Collection.extend({
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
setTotalCount: function(total) {
|
||||
this.totalCount = total;
|
||||
},
|
||||
addFilter: function(name, value) {
|
||||
this.filters = this.filters || {};
|
||||
this.filters[name] = value;
|
||||
@@ -75,4 +77,4 @@ var ItemCollection = Backbone.Collection.extend({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ItemCollection;
|
||||
module.exports = ItemCollection;
|
||||
|
||||
@@ -51,24 +51,30 @@ var fetchItemWithDetails = function() {
|
||||
}
|
||||
}
|
||||
|
||||
var fetchItemsByCategory = function(categoryId, query) {
|
||||
var items = _itemsByCategory;
|
||||
var fetchItemsByCategory = function(categoryId, offset, limit, query) {
|
||||
//var items = _itemsByCategory;
|
||||
var items = new ItemCollection();
|
||||
items.clearFilter();
|
||||
items.setClassificationType(2);
|
||||
items.setClassificationId(categoryId);
|
||||
items.setLimit(30);
|
||||
items.setOffset(0);
|
||||
items.setLimit(limit);
|
||||
items.setOffset(offset);
|
||||
|
||||
for(var key in query) {
|
||||
if (query.hasOwnProperty(key)) {
|
||||
if (query.hasOwnProperty(key) && key != 'limit' && key !='offset') {
|
||||
items.addFilter(key, query[key]);
|
||||
}
|
||||
}
|
||||
|
||||
items.fetch({
|
||||
success: function() {
|
||||
success: function(collection, response, options) {
|
||||
var total = options.xhr.getResponseHeader('x-total-count');
|
||||
items.setTotalCount(total);
|
||||
|
||||
ItemStore.emitChange();
|
||||
}});
|
||||
|
||||
_itemsByCategory = items;
|
||||
};
|
||||
|
||||
var fetchBestSellingItemsForSection = function(sectionId) {
|
||||
@@ -78,7 +84,6 @@ var fetchBestSellingItemsForSection = function(sectionId) {
|
||||
items.setClassificationId(sectionId);
|
||||
items.setLimit(30);
|
||||
items.setOffset(0);
|
||||
|
||||
|
||||
items.fetch({
|
||||
success: function() {
|
||||
@@ -147,7 +152,7 @@ AppDispatcher.register(function(payload) {
|
||||
loadItemsForFrontpage();
|
||||
break;
|
||||
case ItemConstants.LOAD_BY_CATEGORY:
|
||||
fetchItemsByCategory(action.categoryId, action.query);
|
||||
fetchItemsByCategory(action.categoryId, action.offset, action.limit, action.query);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user