From 9098f42a937ea0be772daed8780f263e44d48951 Mon Sep 17 00:00:00 2001 From: Jorge Bolois Guerrero Date: Sat, 15 Oct 2022 18:46:49 +0200 Subject: [PATCH] WIP - Information for locations. Better configuration menu. Testing retrieving JSON from GitHub (uploading). --- locations/Bielsa.json | 15 ++++ locations/Zaragoza.json | 15 ++++ src/Configuration.js | 32 ++++++++- src/ConfigurationHTML.js | 148 ++++++++++++++++++++++++++++----------- src/Event.js | 14 +++- src/Item.js | 19 ++++- src/ItemHTML.js | 50 +++++++++---- src/Location.js | 14 ++++ src/Locations.js | 42 +++++++++++ src/Preferences.js | 26 ++++++- src/StringUtil.js | 7 ++ src/Styles.js | 31 ++++++-- src/Supermarket.js | 47 +++++++++++++ 13 files changed, 388 insertions(+), 72 deletions(-) create mode 100644 locations/Bielsa.json create mode 100644 locations/Zaragoza.json create mode 100644 src/Location.js create mode 100644 src/Locations.js create mode 100644 src/StringUtil.js create mode 100644 src/Supermarket.js diff --git a/locations/Bielsa.json b/locations/Bielsa.json new file mode 100644 index 0000000..6dd3d8e --- /dev/null +++ b/locations/Bielsa.json @@ -0,0 +1,15 @@ +{ + "name": "Bielsa", + "bus": true, + "train": false, + "pharmacy": null, + "smoke": true, + "supermarkets": [ + { + "type": "SPAR", + "url": "https://goo.gl/maps/KGhqH8SwMJrcwPse8" + } + ], + "pool": false, + "gym": true +} \ No newline at end of file diff --git a/locations/Zaragoza.json b/locations/Zaragoza.json new file mode 100644 index 0000000..852ff9e --- /dev/null +++ b/locations/Zaragoza.json @@ -0,0 +1,15 @@ +{ + "name": "Zaragoza", + "bus": true, + "train": true, + "pharmacy": true, + "smoke": true, + "supermarkets": [ + { + "type": "DIA", + "url": "https://goo.gl/maps/NLCXd7GdYWS2wgBMA" + } + ], + "pool": true, + "gym": true +} \ No newline at end of file diff --git a/src/Configuration.js b/src/Configuration.js index d915815..13f333b 100644 --- a/src/Configuration.js +++ b/src/Configuration.js @@ -8,8 +8,9 @@ export default class Configuration { constructor() { document.querySelector('#main-header').innerHTML += ConfigurationHTML.create(); - this._initEvents(); + + this._initData(); } _initEvents() { @@ -18,6 +19,23 @@ export default class Configuration { Information.create(); Configuration.toggle(); }); + + Event.change('#max-price-per-meter', (element) => { + const pricePerMeter = element.value + this._updateItemMeterPrices(pricePerMeter); + }); + } + + _initData() { + const maxPricePerMeter = document.querySelector('#max-price-per-meter'); + this._updateItemMeterPrices(maxPricePerMeter.value); + } + + _updateItemMeterPrices(pricePerMeter) { + if (!pricePerMeter) return; + document.querySelector('#fiftyMetersPrice').textContent = pricePerMeter * 50; + document.querySelector('#seventyFiveMetersPrice').textContent = pricePerMeter * 75; + document.querySelector('#hundredMetersPrice').textContent = pricePerMeter * 100; } _extractConfiguration() { @@ -25,11 +43,21 @@ export default class Configuration { return { enabled: container.querySelector('#enabled').checked, percentages: container.querySelector('#percentages').checked, + percentages_20: container.querySelector('#percentages_20').checked, + percentages_30: container.querySelector('#percentages_30').checked, + percentages_50: container.querySelector('#percentages_50').checked, garage: container.querySelector('#garage').checked, exterior: container.querySelector('#exterior').checked, lift: container.querySelector('#lift').checked, 'max-price': container.querySelector('#max-price').value, - 'max-price-per-meter': container.querySelector('#max-price-per-meter').value + 'max-price-per-meter': container.querySelector('#max-price-per-meter').value, + bus: container.querySelector('#bus').checked, + train: container.querySelector('#train').checked, + supermarket: container.querySelector('#supermarket').checked, + smoke: container.querySelector('#smoke').checked, + pharmacy: container.querySelector('#pharmacy').checked, + gym: container.querySelector('#gym').checked, + pool: container.querySelector('#pool').checked } } diff --git a/src/ConfigurationHTML.js b/src/ConfigurationHTML.js index 9bbe594..2dafb1c 100644 --- a/src/ConfigurationHTML.js +++ b/src/ConfigurationHTML.js @@ -24,50 +24,114 @@ export default class ConfigurationHTML {

Midefos Idealista

-

Configuración global:

- - -

Busqueda:

+
+

Configuración global

+ +
- -
- - -
- - -
- - -
- - -
- - -
+
+

Precios

+ + + + +
    +
  • 50 metros: 150000
  • +
  • 75 metros: 150000
  • +
  • 100 metros: 150000
  • +
+ + + + + + + + +
+ +
+

Dispone de:

+ + + + + +
+ +
+

Lugar dispone de:

+ +

Transporte público:

+ + + + +

Comercio:

+ + + + + + +

Deporte:

+ + + +
+
diff --git a/src/Event.js b/src/Event.js index 00512ae..a3f795f 100644 --- a/src/Event.js +++ b/src/Event.js @@ -1,11 +1,21 @@ import Log from "./Log.js"; +import StringUtil from "./StringUtil.js"; export default class Event { static click(selector, callback) { - document.addEventListener('click', (event) => { + this._addEvent('click', selector, callback) + } + + static change(selector, callback) { + this._addEvent('change', selector, callback) + } + + static _addEvent(eventName, selector, callback) { + Log.debug(`Adding event: ${eventName} to: ${selector}`); + document.addEventListener(eventName, (event) => { if (!event.target.matches(selector)) return; - Log.debug(`Click on: ${selector}`) + Log.debug(`${StringUtil.capitalizeFirstLetter(eventName)} on: ${selector}`); callback(event.target); }); } diff --git a/src/Item.js b/src/Item.js index 3b77629..dbbcd14 100644 --- a/src/Item.js +++ b/src/Item.js @@ -14,6 +14,10 @@ export default class Item { this._node = htmlNode; this.name = this._extractName(); + + this.locationName = this._extractLocationName(); + //this.location = this._extractLocation(); + this.price = this._extractPrice(); this.meters = this._extractMeters(); this.priceMeter = this._extractPriceMeter(); @@ -77,12 +81,18 @@ export default class Item { } _extractName() { - return this._node.querySelector(Item.NAME_SELECTOR).textContent;; + return this._node.querySelector(Item.NAME_SELECTOR).textContent; + } + + _extractLocationName() { + return this.name + .substring(this.name.lastIndexOf(','), this.name.length) + .replaceAll('.', '').replaceAll(',', ''); } _extractPrice() { const priceText = this._node.querySelector(Item.PRICE_SELECTOR).textContent; - return Number(priceText.replace('€', '').replace('.', '').replace(',', '')); + return Number(priceText.replace('€', '').replaceAll('.', '').replaceAll(',', '')); } _extractMeters() { @@ -90,7 +100,10 @@ export default class Item { if (!metersText.includes('m²')) { metersText = this._node.querySelector(Item.ROOM_SELECTOR).textContent; } - return Number(metersText.replace('m²', '')); + return Number(metersText + .replace('m²', '') + .replaceAll('.', '') + ); } _extractPriceMeter() { diff --git a/src/ItemHTML.js b/src/ItemHTML.js index e3fd29a..fc8819b 100644 --- a/src/ItemHTML.js +++ b/src/ItemHTML.js @@ -7,6 +7,7 @@ export default class ItemHTML { static ERROR_CLASS_NAME = 'error'; static CONTAINER_CLASS_NAME = 'midefos-idealista-container'; + static INFORMATION_CONTAINER_CLASS_NAME = 'midefos-idealista-information-container'; static get CONTAINER_SELECTOR() { return `.${this.CONTAINER_CLASS_NAME}`; } @@ -44,27 +45,42 @@ export default class ItemHTML { static createInformation(item) { return `
- ${this._createPercentagePriceHTML(item)} - ${this._createPriceHTML(item)} - ${this._createPriceMeterHTML(item)} - ${this._createGarageHTML(item)} - ${this._createLiftHTML(item)} - ${this._createExteriorHTML(item)} +
+ ${this._createPercentagePriceHTML(item)} + ${this._createPriceHTML(item)} + ${this._createPriceMeterHTML(item)} + ${this._createGarageHTML(item)} + ${this._createLiftHTML(item)} + ${this._createExteriorHTML(item)} +
+
+ ${this._createLocationInformation(item)} +
` } static _createPercentagePriceHTML(item) { if (!Preferences.get('percentages')) return ``; - const twentyPercent = Math.round(item.price * 20 / 100); - const thirtyPercent = Math.round(item.price * 30 / 100); - const fiftyPercent = Math.round(item.price * 50 / 100); - return ` -
- ${this._createIndividual('20%', twentyPercent)} - ${this._createIndividual('30%', thirtyPercent)} - ${this._createIndividual('50%', fiftyPercent)} -
`; + + let html = `
`; + if (Preferences.get('percentages_20')) { + const twentyPercent = Math.round(item.price * 20 / 100); + html += this._createIndividual('20%', twentyPercent); + } + + if (Preferences.get('percentages_30')) { + const thirtyPercent = Math.round(item.price * 30 / 100); + html += this._createIndividual('30%', thirtyPercent) + } + + if (Preferences.get('percentages_50')) { + const fiftyPercent = Math.round(item.price * 50 / 100); + html += this._createIndividual('50%', fiftyPercent) + } + html += `
`; + + return html; } static _createPriceHTML(item) { @@ -146,6 +162,10 @@ export default class ItemHTML { return this._createMissing('Exterior'); } + static _createLocationInformation(item) { + return this._createNeutral(item.locationName); + } + static _shouldCheckExterior(item) { return Preferences.get('exterior') && !item.isHouse(); diff --git a/src/Location.js b/src/Location.js new file mode 100644 index 0000000..b3b62bc --- /dev/null +++ b/src/Location.js @@ -0,0 +1,14 @@ +export default class Location { + + name; + + train; + bus; + + pool; + gym; + + supermarkets; + smoke; + +} \ No newline at end of file diff --git a/src/Locations.js b/src/Locations.js new file mode 100644 index 0000000..87165c2 --- /dev/null +++ b/src/Locations.js @@ -0,0 +1,42 @@ +import Location from './Location.js'; +import Supermarket from './Supermarket.js'; + +export default class Locations { + + static get ZARAGOZA() { + const location = new Location(); + location.name = 'Zaragoza'; + + location.bus = true; + location.train = true; + + location.pool = true; + location.gym = true; + + location.supermarkets = [ + Supermarket.DIA('https://goo.gl/maps/NLCXd7GdYWS2wgBMA') + ]; + location.smoke = true; + + return location; + } + + static get BIELSA() { + const location = new Location(); + location.name = 'Bielsa'; + + location.bus = true; + location.train = false; + + location.pool = false; + location.gym = true; + + location.supermarkets = [ + Supermarket.SPAR('https://goo.gl/maps/KGhqH8SwMJrcwPse8') + ]; + location.smoke = true; + + return location; + } + +} \ No newline at end of file diff --git a/src/Preferences.js b/src/Preferences.js index efab382..e25ac9f 100644 --- a/src/Preferences.js +++ b/src/Preferences.js @@ -12,7 +12,9 @@ export default class Preferences { static get(key) { const config = this._getConfig(); - return config[key]; + const value = config[key]; + if (value === undefined) return this._getFromDefault(key); + return value; } static save(config) { @@ -33,15 +35,33 @@ export default class Preferences { return JSON.parse(storageConfig); } + static _getFromDefault(key) { + const defaultPreferences = this._default(); + return defaultPreferences[key]; + } + static _default() { return { enabled: true, + + 'max-price': 120_000, + 'max-price-per-meter': 1_500, percentages: true, + percentages_20: true, + percentages_30: true, + percentages_50: false, + garage: false, exterior: true, lift: true, - 'max-price': 120_000, - 'max-price-per-meter': 1_500 + + bus: false, + train: false, + supermarket: true, + smoke: false, + pharmacy: true, + gym: false, + pool: true } } diff --git a/src/StringUtil.js b/src/StringUtil.js new file mode 100644 index 0000000..62ef302 --- /dev/null +++ b/src/StringUtil.js @@ -0,0 +1,7 @@ +export default class StringUtil { + + static capitalizeFirstLetter(string) { + return string[0].toUpperCase() + string.slice(1); + } + +} \ No newline at end of file diff --git a/src/Styles.js b/src/Styles.js index 1ca6804..ac71a51 100644 --- a/src/Styles.js +++ b/src/Styles.js @@ -5,10 +5,19 @@ import MenuHTML from "./MenuHTML.js"; export default class Styles { static APP_STYLES = ` + + .midefos-idealista-card { + box-shadow: 0px 0px 8px -1px rgba(0,0,0,0.35); + background-color: white; + border-radius: 8px; + + padding: 1rem; + margin-bottom: 1rem; + } + .${ItemHTML.CONTAINER_CLASS_NAME} { display: flex; - align-items: center; - justify-content: space-around; + flex-direction: column; width: 100%; margin-top: -10px; @@ -20,12 +29,20 @@ export default class Styles { border: 3px solid transparent; } + .${ItemHTML.INFORMATION_CONTAINER_CLASS_NAME} { + display: flex; + align-items: center; + justify-content: space-around; + + width: 100%; + } + .${ItemHTML.INFORMATION_CLASS_NAME} { display: flex; flex-direction: column; } - .${ItemHTML.SUCCESS_CLASS_NAME} { + span.${ItemHTML.SUCCESS_CLASS_NAME} { color: darkgreen; } @@ -33,11 +50,11 @@ export default class Styles { border-color: rgba(61, 217, 61, 0.3); } - .${ItemHTML.WARNING_CLASS_NAME} { + span.${ItemHTML.WARNING_CLASS_NAME} { color: darkorange; } - .${ItemHTML.ERROR_CLASS_NAME} { + span.${ItemHTML.ERROR_CLASS_NAME} { color: darkred; } @@ -72,6 +89,10 @@ export default class Styles { border: 5px solid rgb(225, 245, 110); border-radius: 8px; } + + .${ConfigurationHTML.CONTAINER_CLASS_NAME} label { + display: block; + } `; static add(style = null) { diff --git a/src/Supermarket.js b/src/Supermarket.js new file mode 100644 index 0000000..4922887 --- /dev/null +++ b/src/Supermarket.js @@ -0,0 +1,47 @@ +export default class Supermarket { + + name; + url; + + constructor(name, url) { + this.name = name; + this.url = url; + } + + static DIA(url) { + return new Supermarket('Dia', url); + } + + static MERCADONA(url) { + return new Supermarket('Mercadona', url); + } + + static LIDL(url) { + return new Supermarket('Lidl', url); + } + + static CARREFOUR(url) { + return new Supermarket('Carrefour', url); + } + + static SPAR(url) { + return new Supermarket('Spar', url); + } + + static EROSKI(url) { + return new Supermarket('Eroski', url); + } + + static SUMA(url) { + return new Supermarket('Suma', url); + } + + static SIMPLY(url) { + return new Supermarket('Simply', url); + } + + static CUSTOM(url) { + return new Supermarket('Custom', url); + } + +} \ No newline at end of file