diff --git a/backend/build/server.js b/backend/build/server.js index 73c48cc..144ca6e 100644 --- a/backend/build/server.js +++ b/backend/build/server.js @@ -82,21 +82,83 @@ var db = void 0; - router.get('/search/listings/:id', function () { + router.post('/contact/:listingId', function () { var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(req, res, next) { - var id, listings, listing; + var listingId, body, contactRequests, result; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.prev = 0; + listingId = req.params.listingId; + body = req.body; + contactRequests = db.collection('contact_requests'); + + + if (!body.email) { + res.status(422); + res.end('Email is required'); + } + + if (!body.name) { + res.status(422); + res.end('Name is required'); + } + + _context.next = 8; + return contactRequests.insertOne({ + name: body.name, + email: body.email, + listingId: listingId, + message: body.message, + phone: body.phone, + alert: body.alert + }); + + case 8: + result = _context.sent; + + + res.status(200); + res.end(); + _context.next = 17; + break; + + case 13: + _context.prev = 13; + _context.t0 = _context['catch'](0); + + console.log('error:', _context.t0); + next(_context.t0); + + case 17: + case 'end': + return _context.stop(); + } + } + }, _callee, undefined, [[0, 13]]); + })); + + return function (_x, _x2, _x3) { + return _ref.apply(this, arguments); + }; + }()); + + router.get('/search/listings/:id', function () { + var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(req, res, next) { + var id, listings, listing; + return regeneratorRuntime.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + _context2.prev = 0; id = req.params.id; listings = db.collection('listings'); - _context.next = 5; + _context2.next = 5; return listings.findOne({ _id: new ObjectID(id) }); case 5: - listing = _context.sent; + listing = _context2.sent; if (listing) { res.json(listing); @@ -105,38 +167,38 @@ } res.end(); - _context.next = 14; + _context2.next = 14; break; case 10: - _context.prev = 10; - _context.t0 = _context['catch'](0); + _context2.prev = 10; + _context2.t0 = _context2['catch'](0); - console.log('error:', _context.t0); - next(_context.t0); + console.log('error:', _context2.t0); + next(_context2.t0); case 14: case 'end': - return _context.stop(); + return _context2.stop(); } } - }, _callee, undefined, [[0, 10]]); + }, _callee2, undefined, [[0, 10]]); })); - return function (_x, _x2, _x3) { - return _ref.apply(this, arguments); + return function (_x4, _x5, _x6) { + return _ref2.apply(this, arguments); }; }()); router.get('/search/listings', function () { - var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(req, res, next) { + var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(req, res, next) { var bounds, minPrice, maxPrice, minSize, maxSize, rooms, adType, category, sort, page, pins, properties, query, _bounds$split$map, _bounds$split$map2, lat1, lng1, lat2, lng2, box, price, and, allRooms, or, size, allCategories, _or, cnt, getSort, all, isPins; - return regeneratorRuntime.wrap(function _callee2$(_context2) { + return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { - switch (_context2.prev = _context2.next) { + switch (_context3.prev = _context3.next) { case 0: - _context2.prev = 0; + _context3.prev = 0; bounds = req.query.bounds || ''; minPrice = req.query.minPrice; maxPrice = req.query.maxPrice; @@ -244,11 +306,11 @@ } console.log('QUERY: ', query); - _context2.next = 25; + _context3.next = 25; return properties.find(query).count(); case 25: - cnt = _context2.sent; + cnt = _context3.sent; res.header('X-Total-Count', cnt); @@ -273,24 +335,24 @@ isPins = pins === "true"; if (isPins) { - _context2.next = 36; + _context3.next = 36; break; } - _context2.next = 33; + _context3.next = 33; return all.skip(20 * page).limit(20).toArray(); case 33: - all = _context2.sent; - _context2.next = 39; + all = _context3.sent; + _context3.next = 39; break; case 36: - _context2.next = 38; + _context3.next = 38; return all.toArray(); case 38: - all = _context2.sent; + all = _context3.sent; case 39: @@ -306,14 +368,14 @@ }; })); } else { - res.json(all.map(function (_ref3) { - var _id = _ref3._id, - address = _ref3.address, - images = _ref3.images, - price = _ref3.price, - rooms = _ref3.rooms, - size = _ref3.size, - time = _ref3.time; + res.json(all.map(function (_ref4) { + var _id = _ref4._id, + address = _ref4.address, + images = _ref4.images, + price = _ref4.price, + rooms = _ref4.rooms, + size = _ref4.size, + time = _ref4.time; return { _id: _id, address: address, @@ -327,26 +389,26 @@ } res.end(); - _context2.next = 48; + _context3.next = 48; break; case 44: - _context2.prev = 44; - _context2.t0 = _context2['catch'](0); + _context3.prev = 44; + _context3.t0 = _context3['catch'](0); - console.log('error:', _context2.t0); - next(_context2.t0); + console.log('error:', _context3.t0); + next(_context3.t0); case 48: case 'end': - return _context2.stop(); + return _context3.stop(); } } - }, _callee2, undefined, [[0, 44]]); + }, _callee3, undefined, [[0, 44]]); })); - return function (_x4, _x5, _x6) { - return _ref2.apply(this, arguments); + return function (_x7, _x8, _x9) { + return _ref3.apply(this, arguments); }; }()); diff --git a/backend/server.js b/backend/server.js index e070446..330a44b 100644 --- a/backend/server.js +++ b/backend/server.js @@ -17,6 +17,43 @@ const AGENTURA_KEY = process.env.AGENTURA_KEY || '1somethingverysecret'; let db; +router.post('/contact/:listingId', async (req, res, next) => { + + try { + const listingId = req.params.listingId; + const body = req.body; + + const contactRequests = db.collection('contact_requests'); + + if (!body.email) { + res.status(422); + res.end('Email is required'); + return + } + + if (!body.name) { + res.status(422); + res.end('Name is required'); + return + } + + const result = await contactRequests.insertOne({ + name : body.name, + email : body.email, + listingId, + message : body.message, + phone : body.phone, + alert : body.alert + }); + + res.status(200); + res.end(); + } catch (e) { + console.log('error:', e); + next(e); + } +}); + router.get('/search/listings/:id', async (req, res, next) => { try { const id = req.params.id; diff --git a/web/dist/main.css b/web/dist/main.css index f38f465..81fea4e 100644 --- a/web/dist/main.css +++ b/web/dist/main.css @@ -938,5 +938,5 @@ h5 { } input.validation-failed { - border: 1px solid red; + border: 2px solid red; } diff --git a/web/src/components/ContactModal.js b/web/src/components/ContactModal.js index da263d2..54e9fbc 100644 --- a/web/src/components/ContactModal.js +++ b/web/src/components/ContactModal.js @@ -1,4 +1,5 @@ import React from 'react' +import {saveContactRequest} from '../lib/api' export default class ContactModal extends React.Component { onContactCloseClick (e) { @@ -11,16 +12,32 @@ export default class ContactModal extends React.Component { onSubmit (e) { e.preventDefault() - const {name, email} = this.props.contact; + const {name, email, message, phone, alert} = this.props.contact; if (!name || !email) { this.props.dispatch({ type: 'INVALID_CONTACT' }) } else { + this.props.dispatch({ - type: 'SUBMIT_CONTACT' + type: 'SUBMIT_CONTACT_START' }) + + saveContactRequest(this.props.listingId, { + name, + email, + phone, + message, + alert + }).then(l => l.text()).then(res => { + this.props.dispatch({ + type: 'SUBMIT_CONTACT_END' + }); + }).catch(e => { + // TODO: should we have a global view for rendering errors + console.error(e) + }); } } @@ -53,7 +70,8 @@ export default class ContactModal extends React.Component { name, alert: doAlert, nameInvalid, - emailInvalid + emailInvalid, + sending } = this.props.contact const nameValidationClass = nameInvalid ? 'validation-failed' : '' @@ -87,7 +105,8 @@ export default class ContactModal extends React.Component { className={emailValidationClass} onChange={this.onFieldChange.bind(this, 'email')} placeholder="Email adresa" - type="text" + type="email" + name="email" />