JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<h1>Inputs</h1>
<form class="input-form">
<label>
Initial investment amount:
<input name="initialInvestmentAmount" type="number" value="1000" step="0.01">
</label>
<label>
Additional yearly contribution:
<input name="additionalYearlyContribution" type="number" value="100" step="0.01">
</label>
<label>
Rate of return (%):
<input name="rateOfReturn" type="number" value="5" step="0.01">
</label>
</form>
<div class="output">
<h1>Results</h1>
Capital at the end of term: <span class="capitalAtTheEnd">-</span>
<div class="details">
</div>
</div>
CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
body {
font-family: Inter;
}
h1 {
font-weight: 600;
}
.input-form label {
display: block;
}
.input-form label+label {
margin-top: 10px;
}
.input-form label input {
padding: 5px 10px;
background: #FFFFFF;
border: 1px solid #B4B7D1;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.output {
transition: opacity 0.2s ease-in-out;
}
.output.loading {
opacity: 0.2;
}
.output table {
margin-top: 20px;
border-collapse: collapse;
}
.output table thead {
background: #F1F2F8;
font-weight: 600;
padding: 15px 10px;
}
.output table thead tr th {
border: 1px solid #DEE0EF;
}
.output table tbody th,
.output table tbody td {
padding: 10px;
font-weight: 400;
background: #FFFFFF;
border: 1px solid #DEE0EF;
}
JavaScript
/**
* Summary
* =======
* When an input control in the DOM changes, the /simulate API is executed to calculate
* the the results of the Investment Growth Calculator.
*
* Details
* =======
* - onFormUpdate(): when the inputs in the DOM change, this event handler is called. It
* executes the /simulate API via a call to simulate()
* - updateDOM(): writes the result of the /simulate API to the DOM
*/
let lastRequestId = 0;
function onFormUpdate() {
const requestId = lastRequestId + 1;
lastRequestId = requestId;
const inputs = readInputs();
startLoading();
simulate(
inputs.initialInvestmentAmount,
inputs.additionalYearlyContribution,
inputs.rateOfReturn,
)
.then(({
capitalAtTheEnd,
details
}) => {
if (lastRequestId === requestId) {
updateDOM(capitalAtTheEnd, details);
}
})
.catch((error) => {
console.error('Could not get simulation results', error);
})
.finally(() => {
if (lastRequestId === requestId) {
stopLoading();
}
});
}
onFormUpdate();
document.querySelector('.input-form').addEventListener(
'input',
_.debounce((event) => {
onFormUpdate();
}, 600),
);
async function simulate(initialInvestmentAmount, additionalYearlyContribution, rateOfReturn) {
// Suresheet: https://www.equalto.com/suresheet/view/abc7cbef-2491-4787-94f8-6542fab12a4e
const workbookId = 'abc7cbef-2491-4787-94f8-6542fab12a4e';
const simulateUrl = `https://www.equalto.com/suresheet/api/v1/simulate/${workbookId}`;
const response = await fetch(simulateUrl, {
method: 'POST',
body: JSON.stringify({
inputs: {
"Sheet1": {
C6: initialInvestmentAmount,
C7: additionalYearlyContribution,
C8: rateOfReturn,
},
},
outputs: {
"Sheet1": ['C13', "B20:F41"],
},
}),
headers: {
'Content-Type': 'application/json',
},
});
const responseJson =...