WIP - Information for locations.

Better configuration menu.
Testing retrieving JSON from GitHub (uploading).
This commit is contained in:
Jorge Bolois Guerrero 2022-10-15 18:46:49 +02:00
parent fa25e3c983
commit 9098f42a93
13 changed files with 388 additions and 72 deletions

15
locations/Bielsa.json Normal file
View File

@ -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
}

15
locations/Zaragoza.json Normal file
View File

@ -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
}

View File

@ -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
}
}

View File

@ -24,50 +24,114 @@ export default class ConfigurationHTML {
<div class='${this.CONTAINER_CLASS_NAME}'>
<h2>Midefos Idealista</h2>
<h3>Configuración global:</h3>
<label>
${CheckboxHTML.create('enabled', Preferences.get('enabled'))}
<span>Habilitado</span>
</label>
<h3>Busqueda:</h3>
<div class='midefos-idealista-card'>
<h3>Configuración global</h3>
<label>
${CheckboxHTML.create('enabled', Preferences.get('enabled'))}
<span>Habilitado</span>
</label>
</div>
<label>
${CheckboxHTML.create('percentages', Preferences.get('percentages'))}
<span>Porcentajes</span>
</label>
<br>
<label>
${CheckboxHTML.create('garage', Preferences.get('garage'))}
<span>Garaje</span>
</label>
<br>
<label>
${CheckboxHTML.create('exterior', Preferences.get('exterior'))}
<span>Exterior</span>
</label>
<br>
<label>
${CheckboxHTML.create('lift', Preferences.get('lift'))}
<span>Ascensor</span>
</label>
<br>
<label>
<span>Precio máximo: </span>
<input type='number' id='max-price' value='${Preferences.get('max-price')}' placeholder='0'>
</label>
<br>
<label>
<span>Precio máximo por metro: </span>
<input type='number' id='max-price-per-meter' value='${Preferences.get('max-price-per-meter')}' placeholder='0'>
</label>
<br>
<div class='midefos-idealista-card'>
<h3>Precios</h3>
<label>
<span>Precio máximo: </span>
<input type='number' id='max-price' value='${Preferences.get('max-price')}' placeholder='0'>
</label>
<label>
<span>Precio máximo por metro: </span>
<input type='number' id='max-price-per-meter' value='${Preferences.get('max-price-per-meter')}' placeholder='0'>
</label>
<ul>
<li><strong>50 metros: </strong><span id='fiftyMetersPrice'>150000</span></li>
<li><strong>75 metros: </strong><span id='seventyFiveMetersPrice'>150000</span></li>
<li><strong>100 metros: </strong><span id='hundredMetersPrice'> 150000 </span></li>
</ul>
<label>
${CheckboxHTML.create('percentages', Preferences.get('percentages'))}
<span>Calcular porcentajes</span>
</label>
<label>
${CheckboxHTML.create('percentages_20', Preferences.get('percentages_20'))}
<span>20%</span>
</label>
<label>
${CheckboxHTML.create('percentages_30', Preferences.get('percentages_30'))}
<span>30%</span>
</label>
<label>
${CheckboxHTML.create('percentages_50', Preferences.get('percentages_50'))}
<span>50%</span>
</label>
</div>
<div class='midefos-idealista-card'>
<h3>Dispone de:</h3>
<label>
${CheckboxHTML.create('garage', Preferences.get('garage'))}
<span>Garaje</span>
</label>
<label>
${CheckboxHTML.create('exterior', Preferences.get('exterior'))}
<span>Exterior</span>
</label>
<label>
${CheckboxHTML.create('lift', Preferences.get('lift'))}
<span>Ascensor</span>
</label>
</div>
<div class='midefos-idealista-card'>
<h3>Lugar dispone de:</h3>
<h4>Transporte público:</h4>
<label>
${CheckboxHTML.create('bus', Preferences.get('bus'))}
<span>Bus</span>
</label>
<label>
${CheckboxHTML.create('train', Preferences.get('train'))}
<span>Tren</span>
</label>
<h4>Comercio:</h4>
<label>
${CheckboxHTML.create('supermarket', Preferences.get('supermarket'))}
<span>Supermercado</span>
</label>
<label>
${CheckboxHTML.create('smoke', Preferences.get('smoke'))}
<span>Estanco</span>
</label>
<label>
${CheckboxHTML.create('pharmacy', Preferences.get('pharmacy'))}
<span>Farmacia</span>
</label>
<h4>Deporte:</h4>
<label>
${CheckboxHTML.create('gym', Preferences.get('gym'))}
<span>Gimnasio</span>
</label>
<label>
${CheckboxHTML.create('pool', Preferences.get('pool'))}
<span>Piscina</span>
</label>
</div>
<div>
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.SAVE_CONFIG_CLASS_NAME}'>Guardar</button>
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.OPEN_CONFIG_CLASS_NAME}'>Cerrar</button>

View File

@ -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);
});
}

View File

@ -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() {

View File

@ -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 `
<div class='${this.CONTAINER_CLASS_NAME} ${this.ITEM_STATE_CLASS_NAME(item)}'>
${this._createPercentagePriceHTML(item)}
${this._createPriceHTML(item)}
${this._createPriceMeterHTML(item)}
${this._createGarageHTML(item)}
${this._createLiftHTML(item)}
${this._createExteriorHTML(item)}
<div class='${this.INFORMATION_CONTAINER_CLASS_NAME}'>
${this._createPercentagePriceHTML(item)}
${this._createPriceHTML(item)}
${this._createPriceMeterHTML(item)}
${this._createGarageHTML(item)}
${this._createLiftHTML(item)}
${this._createExteriorHTML(item)}
</div>
<div class='${this.INFORMATION_CONTAINER_CLASS_NAME}'>
${this._createLocationInformation(item)}
</div>
</div>`
}
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 `
<div class='${this.INFORMATION_CLASS_NAME}'>
${this._createIndividual('20%', twentyPercent)}
${this._createIndividual('30%', thirtyPercent)}
${this._createIndividual('50%', fiftyPercent)}
</div>`;
let html = `<div class='${this.INFORMATION_CLASS_NAME}'>`;
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 += `</div>`;
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();

14
src/Location.js Normal file
View File

@ -0,0 +1,14 @@
export default class Location {
name;
train;
bus;
pool;
gym;
supermarkets;
smoke;
}

42
src/Locations.js Normal file
View File

@ -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;
}
}

View File

@ -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
}
}

7
src/StringUtil.js Normal file
View File

@ -0,0 +1,7 @@
export default class StringUtil {
static capitalizeFirstLetter(string) {
return string[0].toUpperCase() + string.slice(1);
}
}

View File

@ -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) {

47
src/Supermarket.js Normal file
View File

@ -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);
}
}