From 18032c6ca6e2b11f3725fa5bfd30c8c1e2cbcbc7 Mon Sep 17 00:00:00 2001 From: egradanin Date: Sat, 19 Jan 2019 16:53:27 +0100 Subject: [PATCH] connecting to remote mysql db, saving market alerts --- backend/MarketAlert.js | 18 ++ backend/db.js | 8 + backend/index.js | 45 +++- backend/package-lock.json | 242 ++++++++++++++++++ backend/package.json | 4 +- frontend-react/src/components/App.js | 30 ++- .../src/components/NotificationModal.js | 37 ++- frontend-react/src/constants/actionTypes.js | 1 + frontend-react/src/reducer.js | 4 +- frontend-react/src/reducers/userdata.js | 10 + .../src/utils/notificationmodalwrapper.js | 12 +- package-lock.json | 100 +++++++- 12 files changed, 487 insertions(+), 24 deletions(-) create mode 100644 backend/MarketAlert.js create mode 100644 backend/db.js create mode 100644 frontend-react/src/reducers/userdata.js diff --git a/backend/MarketAlert.js b/backend/MarketAlert.js new file mode 100644 index 0000000..7924077 --- /dev/null +++ b/backend/MarketAlert.js @@ -0,0 +1,18 @@ +const Sequelize = require("sequelize"); +const sequelize = require("./db.js"); +const MarketAlert = sequelize.define("market_alert", { + id: { + type: Sequelize.INTEGER, + autoIncrement: true, + primaryKey: true + }, + olx_url: Sequelize.STRING, + last_date: Sequelize.STRING, + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true + } +}); + +module.exports = MarketAlert; diff --git a/backend/db.js b/backend/db.js new file mode 100644 index 0000000..9117a17 --- /dev/null +++ b/backend/db.js @@ -0,0 +1,8 @@ +const Sequelize = require("sequelize"); +const sequelize = new Sequelize("sql7274844", "sql7274844", "upMgevlgak", { + host: "sql7.freemysqlhosting.net", + dialect: "mysql", + operatorsAliases: false +}); + +module.exports = sequelize; diff --git a/backend/index.js b/backend/index.js index 8efce90..4c6ba36 100644 --- a/backend/index.js +++ b/backend/index.js @@ -3,13 +3,19 @@ let cheerio = require("cheerio"); let express = require("express"); const path = require("path"); const bodyParser = require("body-parser"); -let fs = require("fs"); +const MarketAlert = require("./MarketAlert"); +const sequelize = require("./db.js"); const app = express(); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); const port = process.env.PORT || 5000; app.get("/api/:url", async (req, res) => { - let url = "https://www.olx.ba/pretraga?" + req.params.url; + let url = + "https://www.olx.ba/pretraga?" + + req.params.url + + "&sort_order=desc&sort_po=datum"; let appts = []; response = await fetch(url); const body = await response.text(); @@ -18,7 +24,13 @@ app.get("/api/:url", async (req, res) => { $("#rezultatipretrage") .find(".listitem") - .each(async (i, elem) => { + .each(async (index, elem) => { + if (index == 0) { + lastItemDate = $(elem) + .find(".cijena > .datum > div") + .first() + .attr("data-cijelidatum"); + } const id = $(elem) .find("a") .first() @@ -33,7 +45,32 @@ app.get("/api/:url", async (req, res) => { .attr("src"); appts.push({ url: id, price: cijena, image }); }); - res.json(appts); + const [dan, mjesec, godina] = lastItemDate + .split(". u ")[0] + .split(".") + .map(el => Number(el)); + const [sati, minute] = lastItemDate + .split(". u ")[1] + .split(":") + .map(el => Number(el)); + last_date = String(new Date(godina, mjesec, dan, sati, minute)); + res.json({ + last_date, + items: appts + }); +}); + +app.post("/api/marketalerts", function(req, res) { + const { email, last_date, olx_url } = req.body; + + sequelize.sync().then(() => + MarketAlert.create({ + olx_url, + last_date, + email + }) + ); + res.json({ message: "Market Alert Created!" }); }); app.listen(port, () => console.log(`Example app listening on port ${port}!`)); diff --git a/backend/package-lock.json b/backend/package-lock.json index 78401a1..86b49d1 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/geojson": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-1.0.6.tgz", + "integrity": "sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==" + }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", @@ -23,6 +28,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, "body-parser": { "version": "1.18.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", @@ -63,6 +73,15 @@ "parse5": "^3.0.1" } }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -107,6 +126,11 @@ "ms": "2.0.0" } }, + "denque": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.3.0.tgz", + "integrity": "sha512-4SRaSj+PqmrS1soW5/Avd7eJIM2JJIqLLmwhRqIGleZM/8KwZq80njbSS2Iqas+6oARkSkLDHEk4mm78q3JlIg==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -155,6 +179,11 @@ "domelementtype": "1" } }, + "dottie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz", + "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -241,6 +270,19 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "generic-pool": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.5.0.tgz", + "integrity": "sha512-dEkxmX+egB2o4NR80c/q+xzLLzLX+k68/K8xv81XprD+Sk7ZtP14VugeCz+fUwv5FzpWq40pPtAkzPRqT8ka9w==" + }, "htmlparser2": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz", @@ -273,6 +315,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -283,11 +330,35 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -321,11 +392,64 @@ "mime-db": "~1.37.0" } }, + "moment": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" + }, + "moment-timezone": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.23.tgz", + "integrity": "sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==", + "requires": { + "moment": ">= 2.9.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mysql2": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.4.tgz", + "integrity": "sha512-ZYbYgK06HKfxU45tYYLfwW5gKt8BslfE7FGyULNrf2K2fh+DuEX+e0QKsd2ObpZkMILefaVn8hsakVsTFqravQ==", + "requires": { + "denque": "1.3.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.4.24", + "long": "^4.0.0", + "lru-cache": "4.1.3", + "named-placeholders": "1.1.1", + "seq-queue": "0.0.5", + "sqlstring": "2.3.1" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "named-placeholders": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz", + "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", + "requires": { + "lru-cache": "2.5.0" + }, + "dependencies": { + "lru-cache": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz", + "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" + } + } + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -379,6 +503,11 @@ "ipaddr.js": "1.8.0" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -410,6 +539,15 @@ "util-deprecate": "^1.0.1" } }, + "retry-as-promised": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-2.3.2.tgz", + "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", + "requires": { + "bluebird": "^3.4.6", + "debug": "^2.6.9" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -420,6 +558,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -440,6 +583,50 @@ "statuses": "~1.4.0" } }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "sequelize": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-4.42.0.tgz", + "integrity": "sha512-qxAYnX4rcv7PbNtEidb56REpxNJCdbN0qyk1jb3+e6sE7OrmS0nYMU+MFVbNTJtZfSpOEEL1TX0TkMw+wzZBxg==", + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^3.1.0", + "depd": "^1.1.0", + "dottie": "^2.0.0", + "generic-pool": "^3.4.0", + "inflection": "1.12.0", + "lodash": "^4.17.1", + "moment": "^2.20.0", + "moment-timezone": "^0.5.14", + "retry-as-promised": "^2.3.2", + "semver": "^5.5.0", + "terraformer-wkt-parser": "^1.1.2", + "toposort-class": "^1.0.1", + "uuid": "^3.2.1", + "validator": "^10.4.0", + "wkx": "^0.4.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", @@ -456,6 +643,16 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, "statuses": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", @@ -469,6 +666,28 @@ "safe-buffer": "~5.1.0" } }, + "terraformer": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/terraformer/-/terraformer-1.0.9.tgz", + "integrity": "sha512-YlmQ1fsMWTkKGDGibCRWgmLzrpDRUr63Q025LJ/taYQ6j1Yb8q9McKF7NBi6ACAyUXO6F/bl9w6v4MY307y5Ag==", + "requires": { + "@types/geojson": "^1.0.0" + } + }, + "terraformer-wkt-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/terraformer-wkt-parser/-/terraformer-wkt-parser-1.2.0.tgz", + "integrity": "sha512-QU3iA54St5lF8Za1jg1oj4NYc8sn5tCZ08aNSWDeGzrsaV48eZk1iAVWasxhNspYBoCqdHuoot1pUTUrE1AJ4w==", + "requires": { + "@types/geojson": "^1.0.0", + "terraformer": "~1.0.5" + } + }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", @@ -493,10 +712,33 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "wkx": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.6.tgz", + "integrity": "sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==", + "requires": { + "@types/node": "*" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } } diff --git a/backend/package.json b/backend/package.json index 026a041..4657662 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,6 +11,8 @@ "dependencies": { "cheerio": "^1.0.0-rc.2", "express": "^4.16.4", - "node-fetch": "^2.3.0" + "mysql2": "^1.6.4", + "node-fetch": "^2.3.0", + "sequelize": "^4.42.0" } } diff --git a/frontend-react/src/components/App.js b/frontend-react/src/components/App.js index 4a9a176..40f4963 100644 --- a/frontend-react/src/components/App.js +++ b/frontend-react/src/components/App.js @@ -1,7 +1,11 @@ import React from "react"; import Select from "react-select"; import { connect } from "react-redux"; -import { CATEGORY_SELECT, ITEMS_CHANGED } from "constants/actionTypes"; +import { + CATEGORY_SELECT, + ITEMS_CHANGED, + USER_DATA_CHANGED +} from "constants/actionTypes"; import { hoc, areObjectEqual } from "utils/helpers"; import { createOlxLink } from "utils/createOlxLink"; import axios from "axios"; @@ -23,13 +27,15 @@ const mapStateToProps = state => { category: state.category, options: state.options, subcategory: state.subcategory, - items: state.items + items: state.items, + userdata: state.userdata }; }; const mapDispatchToProps = dispatch => ({ onCategoryChanged: option => dispatch({ type: CATEGORY_SELECT, option }), - onItemsChanged: items => dispatch({ type: ITEMS_CHANGED, items }) + onItemsChanged: items => dispatch({ type: ITEMS_CHANGED, items }), + onUserDataChange: change => dispatch({ type: USER_DATA_CHANGED, ...change }) }); let lastUpdateTime = null; @@ -38,13 +44,26 @@ class App extends React.Component { componentDidMount() { interval = setInterval(() => { if (lastUpdateTime && Date.now() - lastUpdateTime > 2000) { - const { category, options, subcategory, onItemsChanged } = this.props; + const { + category, + options, + subcategory, + onItemsChanged, + onUserDataChange + } = this.props; let url = createOlxLink(category, subcategory, options); url = encodeURI(url); + onUserDataChange({ info: "olx_url", value: url }); if (url) { axios .get(`/api/${url}`) - .then(response => onItemsChanged(response.data)) + .then(response => { + onItemsChanged(response.data.items); + onUserDataChange({ + info: "last_date", + value: response.data.last_date + }); + }) .catch(error => console.log(error)); } lastUpdateTime = null; @@ -84,7 +103,6 @@ class App extends React.Component { Nekretnine: })} - {items.length ? : null} ); diff --git a/frontend-react/src/components/NotificationModal.js b/frontend-react/src/components/NotificationModal.js index ad3a146..d8831e2 100644 --- a/frontend-react/src/components/NotificationModal.js +++ b/frontend-react/src/components/NotificationModal.js @@ -1,9 +1,10 @@ import React from "react"; import { notificationmodalwrapper } from "utils/notificationmodalwrapper"; +import axios from "axios"; const modalStyle = function() { - let top = 50; - let left = 50; + let top = 20; + let left = 20; return { position: "absolute", @@ -26,6 +27,24 @@ class NotificationModal extends React.Component { this.props.onModalClose(); }; + handleInput = e => { + this.props.onUserDataChange({ info: "email", value: e.target.value }); + }; + + handleSaveMarketAlert = () => { + const { + userdata: { email, last_date, olx_url } + } = this.props; + axios + .post("/api/marketalerts", { + email, + last_date, + olx_url + }) + .then(response => console.log(response.data)) + .catch(error => console.log(error)); + }; + render() { const { modal } = this.props; @@ -35,12 +54,14 @@ class NotificationModal extends React.Component { diff --git a/frontend-react/src/constants/actionTypes.js b/frontend-react/src/constants/actionTypes.js index 5799205..3a6bd9c 100644 --- a/frontend-react/src/constants/actionTypes.js +++ b/frontend-react/src/constants/actionTypes.js @@ -4,3 +4,4 @@ export const OPTION_CHANGE = "OPTION_CHANGE"; export const ITEMS_CHANGED = "ITEMS_CHANGED"; export const MODAL_CLOSE = "MODAL_CLOSE"; export const MODAL_OPEN = " MODAL_OPEN"; +export const USER_DATA_CHANGED = "USER_DATA_CHANGED"; diff --git a/frontend-react/src/reducer.js b/frontend-react/src/reducer.js index 67fedbb..f06cbac 100644 --- a/frontend-react/src/reducer.js +++ b/frontend-react/src/reducer.js @@ -3,6 +3,7 @@ import subcategory from "./reducers/subcategory"; import options from "./reducers/options"; import items from "./reducers/items"; import modal from "./reducers/modal"; +import userdata from "./reducers/userdata"; import { combineReducers } from "redux"; export default combineReducers({ @@ -10,5 +11,6 @@ export default combineReducers({ subcategory, options, items, - modal + modal, + userdata }); diff --git a/frontend-react/src/reducers/userdata.js b/frontend-react/src/reducers/userdata.js new file mode 100644 index 0000000..e8e1046 --- /dev/null +++ b/frontend-react/src/reducers/userdata.js @@ -0,0 +1,10 @@ +import { USER_DATA_CHANGED } from "constants/actionTypes"; + +export default (state = {}, action) => { + switch (action.type) { + case USER_DATA_CHANGED: + return { ...state, [action.info]: action.value }; + default: + return state; + } +}; diff --git a/frontend-react/src/utils/notificationmodalwrapper.js b/frontend-react/src/utils/notificationmodalwrapper.js index d96ff5e..60f0ba3 100644 --- a/frontend-react/src/utils/notificationmodalwrapper.js +++ b/frontend-react/src/utils/notificationmodalwrapper.js @@ -1,15 +1,21 @@ import { connect } from "react-redux"; -import { MODAL_CLOSE, MODAL_OPEN } from "constants/actionTypes"; +import { + MODAL_CLOSE, + MODAL_OPEN, + USER_DATA_CHANGED +} from "constants/actionTypes"; const mapStateToProps = state => { return { - modal: state.modal + modal: state.modal, + userdata: state.userdata }; }; const mapDispatchToProps = dispatch => ({ onModalOpen: () => dispatch({ type: MODAL_OPEN }), - onModalClose: () => dispatch({ type: MODAL_CLOSE }) + onModalClose: () => dispatch({ type: MODAL_CLOSE }), + onUserDataChange: change => dispatch({ type: USER_DATA_CHANGED, ...change }) }); export const notificationmodalwrapper = component => diff --git a/package-lock.json b/package-lock.json index 48e341a..895a28b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3 +1,101 @@ { - "lockfileVersion": 1 + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "denque": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.3.0.tgz", + "integrity": "sha512-4SRaSj+PqmrS1soW5/Avd7eJIM2JJIqLLmwhRqIGleZM/8KwZq80njbSS2Iqas+6oARkSkLDHEk4mm78q3JlIg==" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "mysql2": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.4.tgz", + "integrity": "sha512-ZYbYgK06HKfxU45tYYLfwW5gKt8BslfE7FGyULNrf2K2fh+DuEX+e0QKsd2ObpZkMILefaVn8hsakVsTFqravQ==", + "requires": { + "denque": "1.3.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.4.24", + "long": "^4.0.0", + "lru-cache": "4.1.3", + "named-placeholders": "1.1.1", + "seq-queue": "0.0.5", + "sqlstring": "2.3.1" + } + }, + "named-placeholders": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz", + "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", + "requires": { + "lru-cache": "2.5.0" + }, + "dependencies": { + "lru-cache": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz", + "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" + } + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } }