diff --git a/src/Information.js b/src/Information.js index 51763cd..d074b2b 100644 --- a/src/Information.js +++ b/src/Information.js @@ -11,6 +11,7 @@ export default class Information { Log.debug(`Creating information for ${items.length} items...`) for (const itemNode of items) { const item = new Item(itemNode); + item.extractAsyncData(); item.refreshData(); } } diff --git a/src/Item.js b/src/Item.js index dbbcd14..5c3fb70 100644 --- a/src/Item.js +++ b/src/Item.js @@ -1,4 +1,5 @@ import ItemHTML from './ItemHTML.js'; +import Locations from './Locations.js'; export default class Item { @@ -14,14 +15,13 @@ 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(); + this.additionalInfo = this._extractAdditionalInfo(); this.hasGarage = this._extractGarage(); this.hasLift = this._extractLift(); @@ -33,6 +33,11 @@ export default class Item { return this._node.nextElementSibling; } + async extractAsyncData() { + this.location = await this._extractLocation(); + this.refreshData(); + } + refreshData() { this.removeData(); this.addData(); @@ -85,9 +90,20 @@ export default class Item { } _extractLocationName() { - return this.name + if (this.name.lastIndexOf(',') != -1) { + return this.name .substring(this.name.lastIndexOf(','), this.name.length) - .replaceAll('.', '').replaceAll(',', ''); + .replaceAll('\n', '').replaceAll('.', '') + .replaceAll(',', '').replaceAll(' ', ''); + } + return this.name + .substring(this.name.lastIndexOf(' en ') + ' en '.length, this.name.length) + .replaceAll('\n', '').replaceAll('.', '') + .replaceAll(' ', ''); + } + + async _extractLocation() { + return Locations.get(this.locationName); } _extractPrice() { @@ -96,10 +112,16 @@ export default class Item { } _extractMeters() { - let metersText = this._node.querySelector(Item.METERS_SELECTOR).textContent; - if (!metersText.includes('m²')) { + let metersNode = this._node.querySelector(Item.METERS_SELECTOR); + + + let metersText; + if (!metersNode || !metersNode.textContent.includes('m²')) { metersText = this._node.querySelector(Item.ROOM_SELECTOR).textContent; + } else { + metersText = metersNode.textContent; } + return Number(metersText .replace('m²', '') .replaceAll('.', '') @@ -115,6 +137,7 @@ export default class Item { if (!additionalInfo) { additionalInfo = this._node.querySelector(Item.METERS_SELECTOR); } + if (!additionalInfo) return null; return additionalInfo.textContent; } diff --git a/src/ItemHTML.js b/src/ItemHTML.js index fc8819b..28170b2 100644 --- a/src/ItemHTML.js +++ b/src/ItemHTML.js @@ -43,20 +43,37 @@ 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._createLocationInformation(item)} -
-
` + let html = `
`; + html += `
`; + html += this._createPercentagePriceHTML(item); + html += this._createPriceHTML(item); + html += this._createPriceMeterHTML(item); + html += this._createGarageHTML(item); + html += this._createLiftHTML(item); + html += this._createExteriorHTML(item); + html += `
`; + + html += `
`; + html += this._createLocationName(item); + + if (item.location && item.location.name) { + html += this._createLocationTrain(item); + html += this._createLocationBus(item); + html += this._createLocationGym(item); + html += this._createLocationPool(item); + html += this._createLocationSupermarket(item); + html += this._createLocationSmoke(item); + html += this._createLocationPharmacy(item); + } else if (item.location && item.location.errorMessage) { + html += this._createError(item.location.errorMessage); + } else { + html += this._createNeutral(`Cargando datos...`); + } + + html += `
`; + html += `
`; + + return html; } static _createPercentagePriceHTML(item) { @@ -162,10 +179,78 @@ export default class ItemHTML { return this._createMissing('Exterior'); } - static _createLocationInformation(item) { + static _createLocationName(item) { return this._createNeutral(item.locationName); } + static _createLocationTrain(item) { + if (!Preferences.get('train')) return ``; + + if (item.location?.train) { + return this._createSuccess('Tren'); + } + return this._createError('Tren'); + } + + static _createLocationBus(item) { + if (!Preferences.get('bus')) return ``; + + if (item.location?.bus) { + return this._createSuccess('Bus'); + } + return this._createError('Bus'); + } + + static _createLocationGym(item) { + if (!Preferences.get('gym')) return ``; + + if (item.location?.gym) { + return this._createSuccess('Gimnasio'); + } + return this._createError('Gimnasio'); + } + + static _createLocationPool(item) { + if (!Preferences.get('pool')) return ``; + + if (item.location?.pool) { + return this._createSuccess('Piscina'); + } + return this._createError('Piscina'); + } + + static _createLocationSupermarket(item) { + if (!Preferences.get('supermarket')) return ``; + + let html = `
`; + if (item.location?.supermarkets.length) { + html += this._createSuccess(`${item.location.supermarkets.length} supermercados`); + } else { + html += this._createError('Supermercado'); + } + html += `
`; + + return html; + } + + static _createLocationSmoke(item) { + if (!Preferences.get('smoke')) return ``; + + if (item.location?.smoke) { + return this._createSuccess('Estanco'); + } + return this._createError('Estanco'); + } + + static _createLocationPharmacy(item) { + if (!Preferences.get('pharmacy')) return ``; + + if (item.location?.pharmacy) { + return this._createSuccess('Farmacia'); + } + return this._createError('Farmacia'); + } + static _shouldCheckExterior(item) { return Preferences.get('exterior') && !item.isHouse(); diff --git a/src/Location.js b/src/Location.js index b3b62bc..ee68b1e 100644 --- a/src/Location.js +++ b/src/Location.js @@ -1,5 +1,29 @@ +import Supermarket from "./Supermarket.js"; + export default class Location { + static fromRaw(raw) { + const location = new Location(); + location.name = raw.name; + location.train = raw.train; + location.bus = raw.bus; + + location.gym = raw.gym; + location.pool = raw.pool; + + location.smoke = raw.smoke; + location.pharmacy = raw.pharmacy; + location.supermarkets = []; + for (const rawSupermarket of raw.supermarkets) { + const supermarket = new Supermarket(); + supermarket.name = rawSupermarket.type; + supermarket.url = rawSupermarket.url; + location.supermarkets.push(supermarket); + } + + return location; + } + name; train; diff --git a/src/Locations.js b/src/Locations.js index 87165c2..7481545 100644 --- a/src/Locations.js +++ b/src/Locations.js @@ -1,42 +1,18 @@ import Location from './Location.js'; -import Supermarket from './Supermarket.js'; +import Log from './Log.js'; export default class Locations { - static get ZARAGOZA() { - const location = new Location(); - location.name = 'Zaragoza'; + static async get(name) { + const response = await fetch(`https://raw.githubusercontent.com/Midefos/idealista-enhancer/main/locations/${name}.json`); + Log.debug(`Requested location '${name}'`); - 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; + if (response.status == 404) { + Log.debug(`Missing information for location: '${name}'`); + return { errorMessage: 'Datos no disponibles...' }; + } + const data = await response.json(); + return Location.fromRaw(data); } } \ No newline at end of file diff --git a/src/Styles.js b/src/Styles.js index ac71a51..8aacd24 100644 --- a/src/Styles.js +++ b/src/Styles.js @@ -22,7 +22,6 @@ export default class Styles { width: 100%; margin-top: -10px; margin-bottom: 10px; - padding: 10px 0; background-color: white; box-shadow: 0 3px 6px rgba(225, 245, 110, 0.16), 0 3px 6px rgba(225, 245, 110, 0.23); @@ -35,8 +34,14 @@ export default class Styles { justify-content: space-around; width: 100%; + padding: 0.5rem 0; + border-bottom: 1px solid gray; } + .${ItemHTML.INFORMATION_CONTAINER_CLASS_NAME}:last-of-type { + border-bottom: none; + } + .${ItemHTML.INFORMATION_CLASS_NAME} { display: flex; flex-direction: column; diff --git a/src/Supermarket.js b/src/Supermarket.js index 4922887..1208103 100644 --- a/src/Supermarket.js +++ b/src/Supermarket.js @@ -3,45 +3,4 @@ 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