Public
Edited
Mar 20
Insert cell
Insert cell
viewof calculator = {
const container = document.createElement("div");
container.className = "calculator-container";

// Título
const mainTitle = document.createElement("h1");
mainTitle.textContent = "Calculadora de sueldo neto";
mainTitle.style.textAlign = "center";
mainTitle.style.fontSize = "28px";
mainTitle.style.fontFamily = "Helvetica";
mainTitle.style.marginBottom = "-20px";

container.appendChild(mainTitle);

// CSS
const style = document.createElement("style");
style.textContent = `
.calculator-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
gap: 20px;
padding: 20px;
font-family: Helvetica, sans-serif;
box-sizing: border-box;
}

.calculator-panel {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #f9f9f9;
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 500px;
gap: 10px;
}

.right-panel {
align-items: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.calculator-input {
width: 100%;
max-width: 240px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 80px;
font-size: 14px;
text-align: center;
box-sizing: border-box;
margin-bottom: 10px;
}

.calculator-button {
padding: 10px 20px;
font-size: 16px;
background-color: #01f3b3;
color: black;
font-weight: bold;
border: none;
border-radius: 80px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-top: 15px;
}

.calculator-button:hover {
background-color: #00d79e;
}

h1 {
font-size: 20px;
color: #333;
margin-bottom: 10px;
text-align: center;
}

b {
font-size: 14px;
color: black;
text-align: center;
display: block;
margin: 0 auto;
}

div > div {
font-size: 24px;
color: black;
margin-top: 4px;
word-wrap: break-word;
text-align: center;
}

.pays-title-container {
width: 100%;
max-width: 240px;
text-align: center;
margin-top: 15px;
}

.pays-title {
font-size: 18px;
color: #333;
margin-bottom: 5px;
}

.pays-select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 20px;
box-sizing: border-box;
}

.salario-neto-especial-texto {
background-color: #01f3b3;
color: black;
font-size: 18px;
padding: 10px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 5px;
}

.salario-neto-especial-valor {
font-size: 40px;
font-weight: bold;
color: black;
margin-top: 5px;
}
`;
document.head.appendChild(style);

// Contenedor principal para las dos calculadoras
const calculatorContainer = document.createElement("div");
calculatorContainer.className = "calculator-container";
container.appendChild(calculatorContainer);

// Panel izquierdo (Inputs y lógica)
const panelLeft = document.createElement("div");
panelLeft.className = "calculator-panel";
calculatorContainer.appendChild(panelLeft);

// Panel derecho (Valores estáticos)
const panelRight = document.createElement("div");
panelRight.className = "calculator-panel right-panel";
calculatorContainer.appendChild(panelRight);

// Función para crear la calculadora izquierda (Inputs)
function createLeftCalculator(panel) {
const title = document.createElement("h1");
title.textContent = "Introduce tu salario bruto anual";
panel.appendChild(title);

const input = document.createElement("input");
input.type = "number";
input.placeholder = "";
input.className = "calculator-input";
panel.appendChild(input);

// Añadir el título para el selector de pagas
const paysTitle = document.createElement("h2");
paysTitle.textContent = "Elige el número de pagas";
paysTitle.className = "pays-title";
panel.appendChild(paysTitle);

// Crear el selector de pagas
const select = document.createElement("select");
select.className = "calculator-input";
const option12 = document.createElement("option");
option12.value = "12";
option12.textContent = "12 pagas";
const option14 = document.createElement("option");
option14.value = "14";
option14.textContent = "14 pagas";
select.appendChild(option12);
select.appendChild(option14);

// Valor predeterminado: 12
select.value = "12";
panel.appendChild(select);

const button = document.createElement("button");
button.textContent = "Calcular";
button.className = "calculator-button";
panel.appendChild(button);

return {
input,
button,
select,
};
}

// Crear la calculadora izquierda
const calcLeft = createLeftCalculator(panelLeft);

// Panel derecho inicial (Valores estáticos)
function createRightPanel(panel) {
const sections = [
{ label: "Tu salario neto aproximado cada mes", valueElement: null, specialClass: true },
{ label: "Porcentaje de IRPF al mes", valueElement: null, specialClass: false },
{ label: "Total de IRPF al año", valueElement: null, specialClass: false },
{ label: "Salario neto al año", valueElement: null, specialClass: false },
{ label: "Total cuotas a la Segurdad Social", valueElement: null, specialClass: false }
];

sections.forEach(section => {
const div = document.createElement("div");
const label = document.createElement("b");
label.textContent = section.label;
div.appendChild(label);

const value = document.createElement("div");
value.textContent = section.value || 0;
section.valueElement = value;
div.appendChild(value);

if (section.specialClass) {
div.classList.add("salario-neto-especial-texto");
value.classList.add("salario-neto-especial-valor");
}
panel.appendChild(div);
});

return sections;
}

// Crear el panel derecho con contenido estático
const rightPanelValues = createRightPanel(panelRight);

// Función que actualiza los valores al hacer clic en "Calcular"
calcLeft.button.addEventListener("click", () => {
const value = parseFloat(calcLeft.input.value);
const numPagas = parseInt(calcLeft.select.value);

// Si no hay valor o el valor es negativo
if (isNaN(value) || value < 0) {
// Si el valor no es válido, se resetean todos los valores
rightPanelValues.forEach(section => {
section.valueElement.textContent = 0;
});
} else {
// Establecemos las variables
let seguridad_social = value * 0.0647;
if (seguridad_social >= 3811.74) {
seguridad_social = 3811.74;
}
const minimo_personal = 5550;

// Datos pre IRPF
const base_liquidable0 = value - seguridad_social;
const base_liquidable = base_liquidable0 - minimo_personal;

// Cálculo del IRPF con los tramos
let irpf_total = 0;

if (value > 15876) {
let tramo1 = 0, tramo2 = 0, tramo3 = 0, tramo4 = 0, tramo5 = 0, tramo6 = 0;

if (base_liquidable <= 12450) {
irpf_total = base_liquidable * 0.19;
} else if (base_liquidable <= 20199) {
tramo1 = 12450 * 0.19;
tramo2 = (base_liquidable - 12450) * 0.24;
irpf_total = tramo1 + tramo2;
} else if (base_liquidable <= 35199) {
tramo1 = 12450 * 0.19;
tramo2 = (20199 - 12450) * 0.24;
tramo3 = (base_liquidable - 20199) * 0.3;
irpf_total = tramo1 + tramo2 + tramo3;
} else if (base_liquidable <= 59999) {
tramo1 = 12450 * 0.19;
tramo2 = (20199 - 12450) * 0.24;
tramo3 = (35199 - 20199) * 0.3;
tramo4 = (base_liquidable - 35199) * 0.37;
irpf_total = tramo1 + tramo2 + tramo3 + tramo4;
} else if (base_liquidable <= 299999) {
tramo1 = 12450 * 0.19;
tramo2 = (20199 - 12450) * 0.24;
tramo3 = (35199 - 20199) * 0.3;
tramo4 = (59999 - 35199) * 0.37;
tramo5 = (base_liquidable - 59999) * 0.45;
irpf_total = tramo1 + tramo2 + tramo3 + tramo4 + tramo5;
} else {
tramo1 = 12450 * 0.19;
tramo2 = (20199 - 12450) * 0.24;
tramo3 = (35199 - 20199) * 0.3;
tramo4 = (59999 - 35199) * 0.37;
tramo5 = (299999 - 59999) * 0.45;
tramo6 = (base_liquidable - 299999) * 0.47;
irpf_total = tramo1 + tramo2 + tramo3 + tramo4 + tramo5 + tramo6;
}
}

const neto_mes = (value - seguridad_social - irpf_total) / numPagas;
const neto_año = neto_mes * numPagas;

// Función para formatear los números
function formatNumber(number) {
if (isNaN(number)) return '0,00';
// Asegurarse de tener dos decimales
let [integer, decimal] = number.toFixed(2).split('.');

// Separar los miles con puntos
integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, '.');

// Unir la parte entera con los decimales usando coma
return `${integer},${decimal}`;
}

// Actualizamos los valores del panel derecho
rightPanelValues[0].valueElement.textContent =
formatNumber(neto_mes) + " €";
rightPanelValues[1].valueElement.textContent =
formatNumber((irpf_total / value) * 100) + "%";
rightPanelValues[2].valueElement.textContent =
formatNumber(irpf_total) + " €";
rightPanelValues[3].valueElement.textContent =
formatNumber(neto_año) + " €";
rightPanelValues[4].valueElement.textContent =
formatNumber(seguridad_social) + " €";
}
});

return container;
};
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more