From 3a988fc7be1e8851eb1d6d99a6b207515dfab8ba Mon Sep 17 00:00:00 2001 From: Ratmir Mukazhanov Date: Sun, 14 Jan 2024 11:19:45 +0000 Subject: [PATCH] Calculation delete and restore to interface works History accessibility improvements Tab icon added --- .../calculation/CalculationController.java | 12 +- .../calculation/CalculationService.java | 22 ++- src/main/resources/i18n/messages.properties | 3 +- .../resources/static/assets/css/simulator.css | 32 ++-- src/main/resources/static/assets/img/icon.png | Bin 0 -> 2073 bytes .../resources/static/assets/js/simulator.js | 163 +++++++++++++----- src/main/resources/templates/index.html | 3 +- src/main/resources/templates/login.html | 1 + src/main/resources/templates/register.html | 1 + src/main/resources/templates/simulator.html | 26 +-- 10 files changed, 175 insertions(+), 88 deletions(-) create mode 100644 src/main/resources/static/assets/img/icon.png diff --git a/src/main/java/com/prospero/simulator/calculation/CalculationController.java b/src/main/java/com/prospero/simulator/calculation/CalculationController.java index a505561..fe12f89 100644 --- a/src/main/java/com/prospero/simulator/calculation/CalculationController.java +++ b/src/main/java/com/prospero/simulator/calculation/CalculationController.java @@ -52,11 +52,11 @@ public ResponseEntity createCalculation(@RequestBody Calculation calculation) } -// @PutMapping("/update/{id}") -// public void updateCalculation(@PathVariable Integer id) { -// Calculation calculation = calculationService.getCalculation(id); -// calculation.setName("Updated name"); -// calculationService.updateCalculation(id, calculation); -// } + @PutMapping("/update/{id}") + public ResponseEntity updateCalculation(@PathVariable Integer id, @RequestBody Calculation calculation) { + // Logic to save the calculation + Calculation savedCalculation = calculationService.updateCalculation(id, calculation); + return ResponseEntity.ok(savedCalculation); + } } diff --git a/src/main/java/com/prospero/simulator/calculation/CalculationService.java b/src/main/java/com/prospero/simulator/calculation/CalculationService.java index 31fd45c..251d7e9 100644 --- a/src/main/java/com/prospero/simulator/calculation/CalculationService.java +++ b/src/main/java/com/prospero/simulator/calculation/CalculationService.java @@ -41,12 +41,18 @@ public Calculation saveCalculation(Calculation calculation) { return calculation; } -// public void updateCalculation(Integer id, Calculation calculation) { -// Calculation calculationToUpdate = calculationRepository.findById(id).orElseThrow(); -// calculationToUpdate.setName(calculation.getName()); -// calculationToUpdate.setInitialAmount(calculation.getInitialAmount()); -// calculationToUpdate.setContributionAmount(calculation.getContributionAmount()); -// calculationToUpdate.setContributionFrequency(calculation.getContributionFrequency()); -// calculationRepository.save(calculationToUpdate); -// } + public Calculation updateCalculation(Integer id, Calculation calculation) { + Calculation calculationToUpdate = calculationRepository.findById(id).orElseThrow(); + calculationToUpdate.setName(calculation.getName()); + calculationToUpdate.setContributionAmount(calculation.getContributionAmount()); + calculationToUpdate.setContributionFrequency(calculation.getContributionFrequency()); + calculationToUpdate.setCapitalizationFrequency(calculation.getCapitalizationFrequency()); + calculationToUpdate.setInterestRate(calculation.getInterestRate()); + calculationToUpdate.setCreatedAt(calculation.getCreatedAt()); + calculationToUpdate.setIncomeTaxRate(calculation.getIncomeTaxRate()); + calculationToUpdate.setInflationRate(calculation.getInflationRate()); + calculationToUpdate.setInitialDeposit(calculation.getInitialDeposit()); + calculationRepository.save(calculationToUpdate); + return calculationToUpdate; + } } diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index aa03535..492cf87 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -128,9 +128,10 @@ simulator.tax=Tax simulator.maxValueReached=Maximum value reached simulator.enterCalculationName=Enter calculation name simulator.alreadyExists=Already exists -simulator.Delete=Delete +simulator.delete=Delete simulator.calculationNameRequired=Calculation name is required simulator.inflation=Inflation +history.delete=Delete # History history.title=History diff --git a/src/main/resources/static/assets/css/simulator.css b/src/main/resources/static/assets/css/simulator.css index c46d605..2ce9072 100644 --- a/src/main/resources/static/assets/css/simulator.css +++ b/src/main/resources/static/assets/css/simulator.css @@ -39,7 +39,7 @@ label { } #sub-container-history { - width: 85%; + width: 100%; margin: auto; } @@ -50,10 +50,6 @@ label { margin-top: 1.5em; } -#btn-export-csv { - /*float: right;*/ -} - /*////////// Responsiveness /////////////////*/ /* Laptop */ @@ -108,13 +104,13 @@ label { margin: auto; } - #btn-export-csv { - margin-bottom: 2em; - } - .container-export { width: 100%; } + + .history-additional-info-tablet { + display: none; + } } /* Smartphones in landscape mode */ @@ -138,13 +134,13 @@ label { margin: auto; } - #btn-export-csv { - margin-bottom: 2em; - } - .container-export { width: 100%; } + + .history-additional-info-tablet { + display: none; + } } /* Smartphones in portrait mode */ @@ -182,7 +178,15 @@ label { width: 100%; } - .history-additional-info { + .history-additional-info-smartphone { + display: none; + } + + .history-additional-info-tablet { + display: none; + } + + .button-history-delete { display: none; } } \ No newline at end of file diff --git a/src/main/resources/static/assets/img/icon.png b/src/main/resources/static/assets/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..21c32be8bfe0380b24269c5b0b4eed64b6b06a56 GIT binary patch literal 2073 zcmd6odoa{%7{{HgT#j6F*@+Z#n9hmqv~pXwpKMDPaxIo@h@~xIk+pHG%7jgYCAV4Q z77mAYZCJNVTanA=l5#IK*0QdPTJ1W&E&YGaoS8GtyqB5xedm3i_xt(2?|b`<6Ka>7 zhMa_i#4bk%dsnbu5?7fWU|VMz&ytXko^rGY+^?PIjrD}7MX4q)%W6Q615k`^CgC8f zzalHgU)TLZt8pTxy;MgT|5LTP8&p3O6QJs&EZA|oS=Hs8^IftgMQKY?8B5j;Cl@)$ z7ov4x@N$c_UY~` zsneud-inGPW%4iLepfNJS28a7(F^|5`;o3f{W`DCS;Je@q>VtnooYSOC2pAlOCg;6 ztxGFBBKbAI)pe^KZ{rL*#^?E(^n9*Fh@G$VnT_m#km-gXzKDDZsVgn5!pcWA5MSnXS3D` zhmgN0)03%5NcKLGf;tc3l-#+?vPW5c|@xPiGF<7i%a4BqZujKew0xE$ zF=lQ;0gOUUttwUfh;&&bVLb#Y1&wH>YNBpR2I31%7Er+#pD2x(=}P3yC@A{%V6VUo2u&jyng zMhSxAaVSa}rZqASvC-0Kj=&0&nH1#Q{p{2#XB3Rru*90ms{7#f4R@Jo-5SmjJ*4hr zlfx9eY%>c@u8q{o4%q`hd@m(faz`T>mV_2dYqxz&mxkpBT~GI0p%pVJQ89R%PkZ_s z7?vr54QCI9$y3%I@?X8hO?r3~-AAE&rkQKOwR5NH~1WT?coUoCoKau1~%-5n@F8LGuvEcmECm@ zJzJiF0m;t~qXvNIjFRfy_(~-ec=Qg$je;bq<|BWPgkYb!E&lV7SEKc?)R_0{wZ<_d;RR910 literal 0 HcmV?d00001 diff --git a/src/main/resources/static/assets/js/simulator.js b/src/main/resources/static/assets/js/simulator.js index 39de084..7f3f9ec 100644 --- a/src/main/resources/static/assets/js/simulator.js +++ b/src/main/resources/static/assets/js/simulator.js @@ -89,7 +89,8 @@ function initializeInvestmentSimulator() { // Update the descriptions updateDescriptions(_initial_deposit, _contribution_frequency, _contribution_amount, - _estimated_return * 100, _estimatedTax * 100, _estimatedInflation * 100, _investment_duration, balance.toFixed(2) + '€'); + _estimated_return * 100, _estimatedTax * 100, _estimatedInflation * 100, _investment_duration, balance.toFixed(2)); + console.log('After descriptions updated in getChartData()') return { labels: labels, @@ -115,21 +116,16 @@ function initializeInvestmentSimulator() { function updateDescriptions(principalAmount, contributionFrequency, contributionAmount, annualInterestRate, taxRate, inflationRate, investmentDuration, futureBalance) { - // Update text content of each div - document.getElementById('principal-amount').textContent = - `The base sum of your investment, initially set to ${principalAmount} with additional ${contributionFrequency} contributions of ${contributionAmount}. It represents the core capital on which interest is calculated.`; + console.log(`#{simulator.explanation.principalAmount("234", "234", "324")}`) - document.getElementById('interest-earned').textContent = - `Earnings on your investment, calculated at an ${annualInterestRate} annual return rate. This is the profit generated from your principal over time.`; + document.getElementById('simulator-results-explanation').innerHTML = ` +
+
+
+
+
+ `; - document.getElementById('tax-deduction').textContent = - `Deductions from your earnings at an estimated tax rate of ${taxRate}. It indicates the amount of interest earned that you'll pay as taxes.`; - - document.getElementById('inflation-effect').textContent = - `The decrease in purchasing power of your money, assuming a ${inflationRate} annual inflation rate. It reflects the cost of rising prices and its impact on the real value of your investment.`; - - document.getElementById('future-balance').textContent = - `After ${investmentDuration} years, your investment's future balance is projected to be ${futureBalance}. This includes your principal amount, the interest earned, and is adjusted for taxes and inflation.`; } @@ -422,9 +418,10 @@ function initializeInvestmentSimulator() { // Add this function to a button's click event document.getElementById('btn-export-csv').addEventListener('click', exportToCSV); -} -function initializeHistorySection() { + + + ////////////////////////////////////////////// HISTORY /////////////////////////////////////////////////// // Save calculation to history document.getElementById('button-save').addEventListener('click', function() { @@ -440,14 +437,14 @@ function initializeHistorySection() { const calculationData = { name: prompt(simulator.enterCalculationName), //description: prompt(simulator.enterCalculationName), - initialDeposit: document.getElementById('initial_deposit').value, - contributionAmount: document.getElementById('contribution_amount').value, + initialDeposit: document.getElementById('initial_deposit').dataset.value, + contributionAmount: document.getElementById('contribution_amount').dataset.value, contributionFrequency: contributionFrequency, durationYears: parseInt(document.getElementById('investment_timespan').value), - interestRate: document.getElementById('estimated_return').value, + interestRate: document.getElementById('estimated_return').dataset.value, capitalizationFrequency: capitalizationFrequency, - incomeTaxRate: document.getElementById('estimated_tax').value, - inflationRate: document.getElementById('estimated_inflation').value, + incomeTaxRate: document.getElementById('estimated_tax').dataset.value, + inflationRate: document.getElementById('estimated_inflation').dataset.value, finalAmount: parseFloat(document.getElementById('future_balance').innerHTML.replace(/€/, '').replace(/,/, '.')), createdAt: Date.now(), createdBy: {id: userDetails.userId, email: userDetails.userEmail} @@ -471,9 +468,10 @@ function initializeHistorySection() { 'Authorization': "Bearer " + authToken }, data: JSON.stringify(calculationData), - success: function(data) { + success: function (data) { console.log('Success calculation POST:', data); getCalculations(); + updateHistory(); }, error: function(error) { console.error('Error calculation POST:', error); @@ -492,7 +490,7 @@ function initializeHistorySection() { headers: { 'Authorization': "Bearer " + authToken }, - success: function(data) { + success: function (data) { console.log('Success:', data); replaceCalculationsLocally(data); }, @@ -514,58 +512,133 @@ function initializeHistorySection() { const history = JSON.parse(localStorage.getItem('calculationHistory')); // Get the history section - const historySection = document.getElementById('history-content-table-body'); + const tableContent = document.getElementById('history-content-table-body'); // Clear the history section - historySection.innerHTML = ''; + tableContent.innerHTML = ''; // If there are no calculations, hide the history section if (history.length === 0) { - historySection.style.display = 'none'; + document.getElementById('container-history').setAttribute("style", "display: none;") return; + } else { + document.getElementById('container-history').setAttribute("style", "display: block;") } // Show the history section - historySection.style.display = 'block'; + //historySection.style.display = 'block'; + var calculationNumber = 0; // Loop through the calculations history.forEach(function(calculation) { + // Increment the calculation number + calculationNumber++; + var date = new Date(calculation.createdAt).toLocaleDateString('en-GB'); // Create a row for each calculation var row = document.createElement('tr'); + row.style.cursor = 'pointer'; + //set class + row.setAttribute("class", "calculation-row"); + row.setAttribute("class", "align-middle"); + row.setAttribute("data-calculation-id", calculation.id); row.innerHTML = '' + - '' + calculation.id + '' + + '' + calculationNumber + '' + '' + calculation.name + '' + - '' + date + '' + - '' + calculation.initialDeposit + '' + - '' + calculation.finalAmount + '' + - '' + + '' + date + '' + + '' + calculation.initialDeposit + '€' + + '' + calculation.finalAmount + '€' + + '' + ''; // Add a click event listener to the historySection - historySection.addEventListener('click', function(event) { - if (event.target.classList.contains('btn-danger')) { - var calculationId = event.target.getAttribute('data-calculation-id'); - deleteCalculation(calculationId); - } - }); + // row.addEventListener('click', function(event) { + // var calculationId = event.target.getAttribute('data-calculation-id'); + // + // // Add a click event listener to the delete button + // row.querySelector('.btn-danger').addEventListener('click', function() { + // var calculationId = event.target.getAttribute('data-calculation-id'); + // deleteCalculation(calculationId); + // }); + // + // var calculation = history.find(c => c.id === calculationId); + // if (calculation) { + // restoreCalculationValues(calculation); + // console.log('Calculation restored') + // } else { + // console.log('Calculation not found on restore') + // } + // }); + // Add the calculation to the history section - historySection.appendChild(row); + tableContent.appendChild(row); + + console.log('History updated'); + }); + + // Delegate the click event to the table + tableContent.addEventListener('click', function(event) { + const calculationId = event.target.closest('tr').getAttribute('data-calculation-id'); + + // Check if the clicked element is a delete button + if (event.target.classList.contains('btn-danger')) { + deleteCalculation(calculationId); + } else { + // Handle row click for restore calculation + var calculation = history.find(c => c.id == calculationId); + if (calculation) { + restoreCalculationValues(calculation); + console.log('Calculation restored'); + } else { + console.log('Calculation not found on restore'); + } + } }); } + function restoreCalculationValues(calculation) { + // Update the input fields + document.getElementById('initial_deposit').value = calculation.initialDeposit + '€'; + document.getElementById('initial_deposit').dataset.value = calculation.initialDeposit; + document.getElementById('contribution_amount').value = calculation.contributionAmount + '€'; + document.getElementById('contribution_amount').dataset.value = calculation.contributionAmount; + if (calculation.contributionFrequency === 'ANNUAL') { + document.getElementById('contribution_period_annually').checked = true; + } else if (calculation.contributionFrequency === 'MONTHLY') { + document.getElementById('contribution_period_monthly').checked = true; + } + document.getElementById('investment_timespan').value = calculation.durationYears; + document.getElementById('investment_timespan_text').innerHTML = calculation.durationYears; + document.getElementById('estimated_return').value = calculation.interestRate + '%'; + document.getElementById('estimated_return').dataset.value = calculation.interestRate; + document.getElementById('estimated_inflation').value = calculation.inflationRate + '%'; + document.getElementById('estimated_inflation').dataset.value = '3.00'; + document.getElementById('estimated_tax').value = calculation.incomeTaxRate + '%'; + document.getElementById('estimated_tax').dataset.value = calculation.incomeTaxRate; + if (calculation.capitalizationFrequency === 'ANNUAL') { + document.getElementById('compound_period_annually').checked = true; + } else if (calculation.capitalizationFrequency === 'MONTHLY') { + document.getElementById('compound_period_monthly').checked = true; + } + + // Update the chart and other UI elements + updateChart(); + // Any other updates required... + } + - // Function to delete a calculation + // Function to delete a calculation function deleteCalculation(id) { console.log('Delete calculation'); // Fetch function to delete data from your API fetch(apiBaseUrl + '/calculation/' + id, { method: 'DELETE', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + authToken }, body: JSON.stringify({id: id}) }) @@ -573,23 +646,21 @@ function initializeHistorySection() { .then(data => { console.log('Success:', data); getCalculations(); - updateHistory(); + //updateHistory(); }) .catch((error) => { console.error('Error:', error); }); - getCalculations(); - updateHistory(); + // getCalculations(); + // updateHistory(); } // getCalculations(); updateHistory(); - } // Initialize the simulator when the DOM is fully loaded document.addEventListener('DOMContentLoaded', function () { initializeInvestmentSimulator(); - initializeHistorySection(); }); \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index b5efd74..406394c 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -3,12 +3,13 @@ + Compound Interest Simulator + - Compound Interest Simulator diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 9a0b091..f5b7848 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -5,6 +5,7 @@ + <link rel="icon" href="/assets/img/icon.png"> <script src="/assets/js/jquery.min.js"></script> <script src="/assets/js/bootstrap.bundle.min.js"></script> <script src="/assets/js/main.js"></script> diff --git a/src/main/resources/templates/register.html b/src/main/resources/templates/register.html index cbdff14..192b193 100644 --- a/src/main/resources/templates/register.html +++ b/src/main/resources/templates/register.html @@ -5,6 +5,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/assets/css/main.css" /> <title th:text="#{register.title}"/> + <link rel="icon" href="/assets/img/icon.png"> <script src="/assets/js/jquery.min.js"></script> <script src="/assets/js/bootstrap.bundle.min.js"></script> <script src="/assets/js/main.js"></script> diff --git a/src/main/resources/templates/simulator.html b/src/main/resources/templates/simulator.html index a270a9d..a69d0bb 100644 --- a/src/main/resources/templates/simulator.html +++ b/src/main/resources/templates/simulator.html @@ -3,11 +3,12 @@ <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.75, maximum-scale=1.5, user-scalable=yes"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.75, maximum-scale=1.5, user-scalable=false"> <title th:text="#{simulator.title}"/> - <link rel="icon" href="/assets/img/budget.png"> + <link rel="icon" href="/assets/img/icon.png"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.3/css/bootstrap.css"> <link rel="stylesheet" href="/assets/css/simulator.css"> + <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <script src="/assets/js/jquery.min.js"></script> <script src="/assets/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> @@ -66,12 +67,13 @@ <h2 id="title-simulator" class="mb-5" th:text="#{simulator.title}"/> <!-- Graphic section --> <div id="container-graphic"> <div id="simulator-results-explanation"> - <div id="principal-amount" th:text="#{simulator.explanation.principalAmount}"></div> - <div id="interest-earned" th:text="#{simulator.explanation.interest}"></div> - <div id="tax-deduction" th:text="#{simulator.explanation.tax}"></div> - <div id="inflation-effect" th:text="#{simulator.explanation.inflation}"></div> - <div id="future-balance" th:text="#{simulator.explanation.futureBalance}"></div> + <div id="principal-amount" th:text="#{simulator.explanation.principalAmount(${principalAmount}, ${contributionFrequency}, ${contributionAmount})}"></div> + <div id="interest-earned" th:text="#{simulator.explanation.interest(${annualInterestRate})}"></div> + <div id="tax-deduction" th:text="#{simulator.explanation.tax(${taxRate})}"></div> + <div id="inflation-effect" th:text="#{simulator.explanation.inflation(${inflationRate})}"></div> + <div id="future-balance" th:text="#{simulator.explanation.futureBalance(${investmentDuration}, ${futureBalance})}"></div> </div> + <div id="sub-container-graphic" class="text-center"> <div th:text="#{simulator.futureBalance}"/> <div class="h3" id="future_balance">?</div> @@ -223,7 +225,7 @@ <h2 id="title-simulator" class="mb-5" th:text="#{simulator.title}"/> </div> <!-- History section --> -<div id="container-history" style="margin-top: 50px"> +<div id="container-history" class="" style="margin-top: 50px"> <div id="sub-container-history"> <div id="history"> <div id="history-title"> @@ -234,10 +236,10 @@ <h2 th:text="#{history.title}"/> <table class="table table-striped table-bordered table-hover"> <thead> <tr> - <th scope="col" >#</th> + <th scope="col">#</th> <th scope="col" th:text="#{history.calculation.name}"/> - <th scope="col" th:text="#{history.calculation.date}"/> - <th scope="col" th:text="#{history.calculation.initialDeposit}"/> + <th scope="col" class="history-additional-info-tablet" th:text="#{history.calculation.date}"/> + <th scope="col" class="history-additional-info-smartphone" th:text="#{history.calculation.initialDeposit}"/> <th scope="col" th:text="#{history.calculation.futureBalance}"/> <th scope="col" th:text="#{history.calculation.action}"/> </tr> @@ -266,7 +268,7 @@ <h2 th:text="#{history.title}"/> alreadyExists: /*[[#{simulator.alreadyExists}]]*/ 'default', delete: /*[[#{simulator.delete}]]*/ 'default', calculationNameRequired: /*[[#{simulator.calculationNameRequired}]]*/ 'default', - years: /*[[#{simulator.years}]]*/ 'default' + years: /*[[#{simulator.years}]]*/ 'default', // ... add other properties as needed };