From 0fcee4a74106f455bfe2a216310f16d917af766c Mon Sep 17 00:00:00 2001 From: Edin Dazdarevic Date: Fri, 7 Apr 2017 04:50:46 +0200 Subject: [PATCH] Basic pagination working --- backend/build/server.js | 38 ++++++++++++------------- backend/server.js | 23 +++++++-------- web/components/Listings.js | 27 ++++++++++-------- web/components/Main.js | 19 +++++++------ web/lib/api.js | 10 +++---- web/lib/handlers.js | 58 +++++++++++++++++++------------------- 6 files changed, 90 insertions(+), 85 deletions(-) diff --git a/backend/build/server.js b/backend/build/server.js index de02920..b830721 100644 --- a/backend/build/server.js +++ b/backend/build/server.js @@ -78,7 +78,7 @@ router.get('/search/listings', function () { var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(req, res, next) { - var bounds, minPrice, maxPrice, minSize, maxSize, rooms, adType, category, sort, lastRecordId, properties, query, _bounds$split$map, _bounds$split$map2, lat1, lng1, lat2, lng2, box, price, and, allRooms, or, size, allCategories, _or, cnt, all; + var bounds, minPrice, maxPrice, minSize, maxSize, rooms, adType, category, sort, page, properties, query, _bounds$split$map, _bounds$split$map2, lat1, lng1, lat2, lng2, box, price, and, allRooms, or, size, allCategories, _or, cnt, all; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { @@ -94,7 +94,7 @@ adType = req.query.adType; category = req.query.category; sort = req.query.sort; - lastRecordId = req.query.lastRecordId; + page = req.query.page || 0; properties = db.collection('listings'); query = {}; @@ -204,21 +204,21 @@ res.header('X-Total-Count', cnt); - if (lastRecordId) { - query = Object.assign(query, { - "_id": { - "$gt": new ObjectID(lastRecordId) - } - }); - } + //if (lastRecordId) { + //query = Object.assign(query, { + //"_id": { + //"$gt": new ObjectID(lastRecordId) + //} + //}); + //} - _context.next = 29; + _context.next = 28; return properties.find(query, { //"sort": [['field1','asc'], ['field2','desc']] "sort": [['price', 'asc']] - }).limit(20).toArray(); + }).skip(20 * page).limit(20).toArray(); - case 29: + case 28: all = _context.sent; @@ -228,22 +228,22 @@ res.json(all); res.end(); - _context.next = 39; + _context.next = 38; break; - case 35: - _context.prev = 35; + case 34: + _context.prev = 34; _context.t0 = _context['catch'](0); console.log('error:', _context.t0); next(_context.t0); - case 39: + case 38: case 'end': return _context.stop(); } } - }, _callee, undefined, [[0, 35]]); + }, _callee, undefined, [[0, 34]]); })); return function (_x, _x2, _x3) { @@ -256,8 +256,8 @@ app.use(function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Last-Record-Id"); - res.header("Access-Control-Expose-Headers", "X-Last-Record-Id"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Last-Record-Id, X-Total-Count"); + res.header("Access-Control-Expose-Headers", "X-Last-Record-Id, X-Total-Count"); res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.header('Access-Control-Allow-Credentials', 'true'); next(); diff --git a/backend/server.js b/backend/server.js index 73cca71..5b3eb26 100644 --- a/backend/server.js +++ b/backend/server.js @@ -25,7 +25,8 @@ router.get('/search/listings', async (req, res, next) => { const adType = req.query.adType; const category = req.query.category; const sort = req.query.sort; - const lastRecordId = req.query.lastRecordId; + const page = req.query.page || 0; + const properties = db.collection('listings'); let query = {}; @@ -123,18 +124,18 @@ router.get('/search/listings', async (req, res, next) => { res.header('X-Total-Count', cnt); - if (lastRecordId) { - query = Object.assign(query, { - "_id": { - "$gt": new ObjectID(lastRecordId) - } - }); - } + //if (lastRecordId) { + //query = Object.assign(query, { + //"_id": { + //"$gt": new ObjectID(lastRecordId) + //} + //}); + //} const all = await properties.find(query, { //"sort": [['field1','asc'], ['field2','desc']] "sort": [['price','asc']] - }).limit(20).toArray(); + }).skip(20 * page).limit(20).toArray(); if (all.length > 0) { res.header('X-Last-Record-Id', [...all].pop()._id); @@ -154,8 +155,8 @@ app.use(bodyParser.json()); app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Last-Record-Id"); - res.header("Access-Control-Expose-Headers", "X-Last-Record-Id"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Last-Record-Id, X-Total-Count"); + res.header("Access-Control-Expose-Headers", "X-Last-Record-Id, X-Total-Count"); res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.header('Access-Control-Allow-Credentials', 'true'); next(); diff --git a/web/components/Listings.js b/web/components/Listings.js index 99c3bdf..4030d02 100644 --- a/web/components/Listings.js +++ b/web/components/Listings.js @@ -15,12 +15,17 @@ export default class Listings extends React.Component { //console.log('node.parentNode.scrollTop', node.scrollTop); //console.log('node.parentNode.clientHeight', node.clientHeight); + if (this.props && this.props.loadingMore) { + + console.log('still loading!'); + return; + } console.log('scrolling', node.scrollTop, node.scrollHeight, offset); if (offset < 50) { console.log('load more'); - this.removeScrollListener(); + //this.removeScrollListener(); this.props.dispatch({type: 'LOAD_MORE_LISTINGS'}); } } @@ -46,15 +51,13 @@ export default class Listings extends React.Component { componentDidUpdate (prevProps) { console.log('RECEIVING PROPS: ', prevProps, 'new are', this.props); - //setTimeout(() => { - //this.attachScrollListener(); - //}, 1000); - if (this.props.loadingMore != null) { - if (!this.props.loadingMore && prevProps.loadingMore) { - this.attachScrollListener(); - console.log('ATTACHING AGAIN', this); - } - } + + //if (this.props.loadingMore != null) { + //if (!this.props.loadingMore && prevProps.loadingMore) { + //this.attachScrollListener(); + //console.log('ATTACHING AGAIN', this); + //} + //} } renderListings () { @@ -131,7 +134,7 @@ export default class Listings extends React.Component { render () { - const {listings = (new Map())} = this.props; + const {listings = (new Map()), totalCount} = this.props; return (
@@ -145,7 +148,7 @@ export default class Listings extends React.Component {
- {listings.size} rezultata + {totalCount} rezultata
diff --git a/web/components/Main.js b/web/components/Main.js index 312d563..097214c 100644 --- a/web/components/Main.js +++ b/web/components/Main.js @@ -13,6 +13,7 @@ class Main extends React.Component { listingDetails: false, listings: (new Map()), imageIndex: 0, + page: 0, filters: { rooms: {}, category: {} @@ -89,7 +90,8 @@ class Main extends React.Component { map.addListener('idle', () => { console.log('idle'); - this.refreshListings(); + this.dispatch({type: 'MAP_IDLE'}); + //this.refreshListings(); }); } @@ -151,7 +153,7 @@ class Main extends React.Component { minPrice, maxPrice, category, - lastRecordId: this.state.lastRecordId + page: this.state.page }); @@ -161,16 +163,14 @@ class Main extends React.Component { properties .then(p => { - const lastRecordId = p.headers.get('X-Last-Record-Id'); - console.log('lastRecordId', lastRecordId, p.headers); return { body: p.text(), - lastRecordId: p.headers.get('X-Last-Record-Id') + totalCount: p.headers.get('X-Total-Count') }; }) - .then(({body, lastRecordId}) => { + .then(({body, totalCount}) => { body.then(p => { - console.log('results_received: ', body, lastRecordId); + console.log('results_received: ', totalCount); const data = JSON.parse(p); const listingExists = (id) => { @@ -252,8 +252,8 @@ class Main extends React.Component { action: { listings: data, newMarkers, - lastRecordId, - more + more, + totalCount } }); }); @@ -362,6 +362,7 @@ class Main extends React.Component { } else { children.push(); children.push( { const allRooms = Object .keys(rooms) @@ -22,11 +22,11 @@ export const loadProperties = ({ // TODO: handle errors //return fetch(process.env.API_URL + '/api/search', { - let url = `http://localhost:3001/api/search/listings?bounds=${bounds}&minPrice=${minPrice}&maxPrice=${maxPrice}&rooms=${allRooms}&minSize=${minSize}&maxSize=${maxSize}&category=${allCategories}` + let url = `http://localhost:3001/api/search/listings?bounds=${bounds}&minPrice=${minPrice}&maxPrice=${maxPrice}&rooms=${allRooms}&minSize=${minSize}&maxSize=${maxSize}&category=${allCategories}&page=${page}` - if (lastRecordId) { - url += `&lastRecordId=${lastRecordId}`; - } + //if (lastRecordId) { + //url += `&lastRecordId=${lastRecordId}`; + //} return fetch(url, { //credentials: 'include' diff --git a/web/lib/handlers.js b/web/lib/handlers.js index d67073e..4c8a6a3 100644 --- a/web/lib/handlers.js +++ b/web/lib/handlers.js @@ -3,7 +3,7 @@ import { markSeen } from './api'; const setMaxPrice = ({ type, action }, component) => { const maxPrice = parseFloat(action.maxPrice); component.setState({ - lastRecordId: null, + page: 0, filters: { ...component.state.filters, maxPrice: isNaN(maxPrice) ? undefined : maxPrice, @@ -15,7 +15,7 @@ const setMaxPrice = ({ type, action }, component) => { const setMinPrice = ({ type, action }, component) => { const minPrice = parseFloat(action.minPrice); component.setState({ - lastRecordId: null, + page: 0, filters: { ...component.state.filters, minPrice: isNaN(minPrice) ? undefined : minPrice, @@ -27,7 +27,7 @@ const setMinPrice = ({ type, action }, component) => { const setMinSize = ({ type, action }, component) => { const minSize = parseFloat(action.minSize); component.setState({ - lastRecordId: null, + page: 0, filters: { ...component.state.filters, minSize: isNaN(minSize) ? undefined : minSize, @@ -39,7 +39,7 @@ const setMinSize = ({ type, action }, component) => { const setMaxSize = ({ type, action }, component) => { const maxSize = parseFloat(action.maxSize); component.setState({ - lastRecordId: null, + page: 0, filters: { ...component.state.filters, maxSize: isNaN(maxSize) ? undefined : maxSize, @@ -78,8 +78,8 @@ const listingsLoaded = ({ type, action }, component) => { component.setState({ listings: action.more ? (new Map([...component.state.listings, ...currentListings])) : currentListings, - lastRecordId: !action.more ? null : action.lastRecordId, - loadingMore: false + loadingMore: false, + totalCount: action.totalCount }, () => { component.markers = action.newMarkers; console.log('ALL LOADED', component.state.listings); @@ -117,7 +117,7 @@ const viewImage = ({ type, action }, component) => { const searchPlaceChanged = ({ type, action }, component) => { component.setState({ listingDetails: false, - lastRecordId: null + page: 0 }); }; @@ -126,7 +126,7 @@ const setRooms = ({ type, action }, component) => { component.setState( { - lastRecordId: null, + page: 0, filters: { ...component.state.filters, rooms: { @@ -162,7 +162,7 @@ const setCategory = ({type, action}, component) => { component.setState( { - lastRecordId: null, + page: 0, filters: { ...component.state.filters, category: { @@ -220,27 +220,26 @@ const backToResults = ({type, action}, component) => { const loadMoreListings = ({type, action}, component) => { console.log('loading more'); - component.setState({ - loadingMore: true - }, () => { - component.refreshListings(true); - }); + const currentPage = component.state.page; + if (currentPage * 20 < component.state.totalCount) { + component.setState({ + loadingMore: true, + page: currentPage + 1 + }, () => { + component.refreshListings(true); + }); + } } -//const loadMoreListingsLoaded = ({type, action}, component) => { - //const currentListings = new Map(); - - //for (const listing of action.listings) { - //currentListings.set(listing._id, listing); - //} - - //component.setState({ - //listings: new Map([...component.state.listings, ...currentListings]), - //lastRecordId: action.lastRecordId - //}, () => { - //component.markers = action.newMarkers; - //}); -//} +const mapIdle = ({type, action}, component) => { + component.setState({ + page: 0 + }, () => { + const scrollElem = document.querySelector('.right-content'); + scrollElem.scrollTop = 0; + component.refreshListings(); + }) +} const handlers = { SET_MIN_PRICE: setMinPrice, @@ -259,7 +258,8 @@ const handlers = { SET_CATEGORY: setCategory, ON_LISTING_MOUSE_OVER: onListingMouseOver, BACK_TO_RESULTS: backToResults, - LOAD_MORE_LISTINGS: loadMoreListings + LOAD_MORE_LISTINGS: loadMoreListings, + MAP_IDLE: mapIdle }; export const handleMessage = ({ type, action }, component) => {