diff --git a/backend/build/server.js b/backend/build/server.js index ffc23dc..de02920 100644 --- a/backend/build/server.js +++ b/backend/build/server.js @@ -58,9 +58,13 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } var MongoClient = __webpack_require__(3).MongoClient; + var ObjectID = __webpack_require__(3).ObjectID; + var url = 'mongodb://localhost:27017/kivi'; __webpack_require__(4); @@ -72,9 +76,9 @@ var db = void 0; - router.get('/search', function () { + 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, properties, query, _bounds$split$map, _bounds$split$map2, lat1, lng1, lat2, lng2, box, price, and, allRooms, or, size, allCategories, _or, all; + 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; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { @@ -90,6 +94,7 @@ adType = req.query.adType; category = req.query.category; sort = req.query.sort; + lastRecordId = req.query.lastRecordId; properties = db.collection('listings'); query = {}; @@ -149,9 +154,6 @@ and.push({ "$or": or }); - //query = Object.assign(query, { - //rooms: - //}); } if (minSize || maxSize) { @@ -180,9 +182,6 @@ and.push({ "$or": _or }); - //query = Object.assign(query, { - //{"$or" : or } - //}); } if (and.length > 0) { @@ -191,35 +190,60 @@ }); } + //query = Object.assign(query, { + //"_id": 1 + //}); + console.log('QUERY: ', query); - _context.next = 23; + _context.next = 24; + return properties.find(query).count(); + + case 24: + cnt = _context.sent; + + + res.header('X-Total-Count', cnt); + + if (lastRecordId) { + query = Object.assign(query, { + "_id": { + "$gt": new ObjectID(lastRecordId) + } + }); + } + + _context.next = 29; return properties.find(query, { //"sort": [['field1','asc'], ['field2','desc']] "sort": [['price', 'asc']] - }).toArray(); + }).limit(20).toArray(); - case 23: + case 29: all = _context.sent; + if (all.length > 0) { + res.header('X-Last-Record-Id', [].concat(_toConsumableArray(all)).pop()._id); + } + res.json(all); res.end(); - _context.next = 32; + _context.next = 39; break; - case 28: - _context.prev = 28; + case 35: + _context.prev = 35; _context.t0 = _context['catch'](0); console.log('error:', _context.t0); next(_context.t0); - case 32: + case 39: case 'end': return _context.stop(); } } - }, _callee, undefined, [[0, 28]]); + }, _callee, undefined, [[0, 35]]); })); return function (_x, _x2, _x3) { @@ -232,7 +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"); + 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-Methods", "GET, POST, OPTIONS"); res.header('Access-Control-Allow-Credentials', 'true'); next(); diff --git a/backend/server.js b/backend/server.js index 82e987f..73cca71 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,6 +1,8 @@ import express from 'express' import bodyParser from 'body-parser'; var MongoClient = require('mongodb').MongoClient; +var ObjectID = require('mongodb').ObjectID; + var url = 'mongodb://localhost:27017/kivi'; require("babel-polyfill"); @@ -12,17 +14,18 @@ const AGENTURA_KEY = process.env.AGENTURA_KEY || '1somethingverysecret'; let db; -router.get('/search', async (req, res, next) => { +router.get('/search/listings', async (req, res, next) => { try { - const bounds = req.query.bounds || ''; - const minPrice = req.query.minPrice; - const maxPrice = req.query.maxPrice; - const minSize = req.query.minSize; - const maxSize = req.query.maxSize; - const rooms = req.query.rooms; - const adType = req.query.adType; - const category = req.query.category; - const sort = req.query.sort; + const bounds = req.query.bounds || ''; + const minPrice = req.query.minPrice; + const maxPrice = req.query.maxPrice; + const minSize = req.query.minSize; + const maxSize = req.query.maxSize; + const rooms = req.query.rooms; + const adType = req.query.adType; + const category = req.query.category; + const sort = req.query.sort; + const lastRecordId = req.query.lastRecordId; const properties = db.collection('listings'); let query = {}; @@ -111,11 +114,31 @@ router.get('/search', async (req, res, next) => { }); } + //query = Object.assign(query, { + //"_id": 1 + //}); + console.log('QUERY: ', query); + const cnt = await properties.find(query).count(); + + res.header('X-Total-Count', cnt); + + 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']] - }).toArray(); + }).limit(20).toArray(); + + if (all.length > 0) { + res.header('X-Last-Record-Id', [...all].pop()._id); + } res.json(all); res.end(); @@ -131,7 +154,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"); + 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-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 39dc8e8..99c3bdf 100644 --- a/web/components/Listings.js +++ b/web/components/Listings.js @@ -1,7 +1,31 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import {formatPrice} from '../lib/helpers'; export default class Listings extends React.Component { + constructor(props) { + super(props); + + this.handleScroll = (e) => { + const node = e.target; + const offset = node.scrollHeight - node.scrollTop - node.clientHeight; + + //console.log('-----------------'); + //console.log('node.scrollHeight', node.scrollHeight); + //console.log('node.parentNode.scrollTop', node.scrollTop); + //console.log('node.parentNode.clientHeight', node.clientHeight); + + + console.log('scrolling', node.scrollTop, node.scrollHeight, offset); + if (offset < 50) { + + console.log('load more'); + this.removeScrollListener(); + this.props.dispatch({type: 'LOAD_MORE_LISTINGS'}); + } + } + } + onListingClick(id) { this.props.dispatch({ type: 'VIEW_LISTING_DETAILS', @@ -20,6 +44,19 @@ 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); + } + } + } + renderListings () { const {listings = (new Map())} = this.props; @@ -69,12 +106,35 @@ export default class Listings extends React.Component { return rendered; } - render() { + componentDidMount () { + this.attachScrollListener(); + } + + componentWillUnmount () { + this.removeScrollListener(); + } + + attachScrollListener () { + const listings = ReactDOM.findDOMNode(this.refs.listings); + listings.parentNode.addEventListener('scroll', this.handleScroll); + } + + removeScrollListener () { + const listings = ReactDOM.findDOMNode(this.refs.listings); + listings.parentNode.removeEventListener('scroll', this.handleScroll); + } + + //componentDidUpdate() { + //console.log('componentDidUpdate'); + ////this.attachScrollListener(); + //} + + render () { const {listings = (new Map())} = this.props; return ( -