re-vamp of front-end to use less space. Also, first pass at using comparison data from DB, and created a function to find the last comparison value and use that in the table
This commit is contained in:
@@ -6,11 +6,14 @@
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<title>Finance Form</title>
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/annotations.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<h2>Finance Tracker</h2>
|
||||
<form action="/update" method="POST">
|
||||
<h3>Finance Tracker</h3>
|
||||
|
||||
<form id="vals_form" class="mt-3" action="/update" method="POST">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
@@ -24,18 +27,18 @@
|
||||
<input type="number" step="any" class="form-control text-end float-end " id="Savings" name="Savings" value="{{ finance['Savings'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label for="Living_Expenses" class="col-form-label me-2 text-end float-end">Living Expenses</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end " id="Living_Expenses" name="Living_Expenses" value="{{ finance['Living_Expenses'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="Car_loan_via_pay" class="col-form-label me-2 text-end float-end">Car Loan via Pay</label>
|
||||
<input type="number" step="any" class="bg-light form-control text-end float-end" id="Car_loan_via_pay" name="Car_loan_via_pay" value="{{ finance['Car_loan_via_pay'] }}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label for="Living_Expenses" class="col-form-label me-2 text-end float-end">Living Expenses</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end " id="Living_Expenses" name="Living_Expenses" value="{{ finance['Living_Expenses'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="input-group">
|
||||
<label for="Overseas_trip" class="col-form-label me-2 text-end float-end">Overseas Trip</label>
|
||||
@@ -57,18 +60,18 @@
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="Interest_Rate" name="Interest_Rate" value="{{ finance['Interest_Rate'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label for="Inflation" class="col-form-label me-2 text-end float-end">Inflation (%)</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="Inflation" name="Inflation" value="{{ finance['Inflation'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="Car_loan" class="col-form-label me-2 text-end float-end">Car Loan</label>
|
||||
<input type="number" step="any" class="bg-light form-control text-end float-end" id="Car_loan" name="Car_loan" value="{{ finance['Car_loan'] }}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="input-group">
|
||||
<label for="Inflation" class="col-form-label me-2 text-end float-end">Inflation (%)</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="Inflation" name="Inflation" value="{{ finance['Inflation'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="input-group">
|
||||
<label for="Mark_reno" class="col-form-label me-2 text-end float-end">Reno costs</label>
|
||||
@@ -90,7 +93,7 @@
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="M_TLS_shares" name="M_TLS_shares" value="{{ finance['M_TLS_shares'] }}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="offset-2 col-2">
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="Car_balloon" class="col-form-label me-2 text-end float-end">Car Balloon</label>
|
||||
<input type="number" step="any" class="bg-light form-control text-end float-end" id="Car_balloon" name="Car_balloon" value="{{ finance['Car_balloon'] }}" readonly>
|
||||
@@ -110,12 +113,26 @@
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="D_TLS_shares" name="D_TLS_shares" value="{{ finance['D_TLS_shares'] }}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="offset-2 col-2">
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="Mich_present" class="col-form-label me-2 text-end float-end float-end">Mich Present</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end bg-light" id="Mich_present" name="Mich_present" value="{{ finance['Mich_present'] }}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offset-2 col-2">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="Sell_shares">Sell Shares:</label>
|
||||
<select class="form-select border border-primary text-primary" id="Sell_shares" name="Sell_shares" onchange="this.form.submit()">
|
||||
<option value="0">Never</option>
|
||||
<option value="1">1 years</option>
|
||||
<option value="2">2 years</option>
|
||||
<option value="3">3 years</option>
|
||||
<option value="4">4 years</option>
|
||||
<option value="5">5 years</option>
|
||||
<option value="6">6 years</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div class="row">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-2">
|
||||
@@ -130,32 +147,12 @@
|
||||
<input type="number" step="any" class="form-control text-end float-end" id="TLS_price" name="TLS_price" value="{{ finance['TLS_price'] }}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="offset-2 col-2">
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="School_Fees" class="col-form-label me-2 text-end float-end">School Fees</label>
|
||||
<input type="number" step="any" class="bg-light form-control text-end float-end" id="School_Fees" name="School_Fees" value="{{ finance['School_Fees'] }}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-center mt-4">
|
||||
<div class="col-1">
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
<div class="offset-1 col-2">
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="Sell_shares">Sell Shares:</label>
|
||||
<select class="form-select" id="Sell_shares" name="Sell_shares" onchange="this.form.submit()">
|
||||
<option value="0">Never</option>
|
||||
<option value="1">1 years</option>
|
||||
<option value="2">2 years</option>
|
||||
<option value="3">3 years</option>
|
||||
<option value="4">4 years</option>
|
||||
<option value="5">5 years</option>
|
||||
<option value="6">6 years</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="input-group">
|
||||
<label for="CBA_shares" class="col-form-label me-2 text-end float-end">FINAL # of CBA</label>
|
||||
@@ -168,24 +165,9 @@
|
||||
<input type="number" class="form-control text-end float-end bg-light" id="TLS_shares" value="{{TLS}}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button type="button" class="btn btn-primary" onClick="
|
||||
$.ajax( { type: 'GET', url: '/download_csv', xhrFields: { responseType: 'blob' },
|
||||
success: function(res){
|
||||
// Create a link element
|
||||
const link = document.createElement('a');
|
||||
const url = window.URL.createObjectURL(res);
|
||||
link.href = url;
|
||||
link.download = 'finance_data.csv'; // Set the file name
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url); // Clean up the object URL
|
||||
console.log('done') } })
|
||||
"> Export to CSV </button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -200,16 +182,11 @@ window.onload = function() {
|
||||
}
|
||||
</style>
|
||||
|
||||
{% if depletion_date %}
|
||||
<h3 class="mt-3" ><font color="red">Depletion Date: {{ depletion_date }} -- Details:</font></h3>
|
||||
{% else %}
|
||||
<h3 class="mt-3" ><font color="green">We DONT run out of money before super kicks in!!! -- Details:</font></h3>
|
||||
{% endif %}
|
||||
|
||||
<h5 class="mt-4">Fortnighthly Savings data:
|
||||
{% if COMP %}
|
||||
<h5><font color="blue">Note: value in blue below is value we should have been at when comparing to saved values</font></h5>
|
||||
<font color="blue"> Note: value in blue below is value we should have been at when comparing to saved values</font>
|
||||
{% endif %}
|
||||
|
||||
</h5>
|
||||
|
||||
<table>
|
||||
<tr><td valign="top">
|
||||
@@ -225,13 +202,6 @@ window.onload = function() {
|
||||
{% set mon=date[5:7] %}
|
||||
{% set day=date[8:10 ] %}
|
||||
|
||||
{% if comp_done.val == 0 and yr == comp_yr and mon == comp_mon and day|int >= comp_day|int %}
|
||||
<font color="blue">
|
||||
{{ COMP['date'] }}:
|
||||
{{ '$%0.2f' % COMP['amount']|float }}<br>
|
||||
</font>
|
||||
{% set comp_done.val=1 %}
|
||||
{% endif %}
|
||||
{% if yr|int > first_yr|int and mon == '01' and day|int <= 14 %}
|
||||
</td><td> </td><td valign="top">
|
||||
{% endif %}
|
||||
@@ -239,13 +209,157 @@ window.onload = function() {
|
||||
{{ date }}:
|
||||
{{ '$%0.2f' % dollars|float }}<br>
|
||||
</font>
|
||||
{% if comp_done.val == 0 and yr == comp_yr and mon == comp_mon and day|int >= comp_day|int %}
|
||||
<font color="blue">
|
||||
{{ COMP['date'] }}:
|
||||
{{ '$%0.2f' % COMP['amount']|float }}<br>
|
||||
</font>
|
||||
{% set comp_done.val=1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td><td> </td><td valign="top"><b>SUMMARY/BUDGET</b><br>
|
||||
{% if depletion_date %}
|
||||
<div class="alert alert-danger">Run out of $'s:<br>{{depletion_date}}</div>
|
||||
{% else %}
|
||||
<div class="alert alert-success">Super kicks in!!!</div>
|
||||
{% endif %}
|
||||
</td><td> </td><td valign="top"><div style="background:lemonchiffon"><b>SUMMARY/BUDGET</b><br>
|
||||
{% for label, value in BUDGET %}
|
||||
{{label}} {{value}}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td><td> </td><td valign="top">
|
||||
<div class="">
|
||||
<button type="submit" class="btn btn-primary" onClick="$('#vals_form').submit()">Update</button>
|
||||
</div>
|
||||
<div class="mt-3 input-group">
|
||||
<button type="submit" class="disabled btn btn-primary" onClick="$('#vals_form').submit() disabled">Compare with:</button>
|
||||
<select class="form-select border border-primary text-primary" id="comp_set" name="comp_set" onchange="">
|
||||
<option value="0">None</option>
|
||||
<option value="1">something</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<button type="button" class="btn btn-primary" onClick="
|
||||
$.ajax( { type: 'GET', url: '/download_csv', xhrFields: { responseType: 'blob' },
|
||||
success: function(res){
|
||||
// Create a link element
|
||||
const link = document.createElement('a');
|
||||
const url = window.URL.createObjectURL(res);
|
||||
link.href = url;
|
||||
link.download = 'finance_data.csv'; // Set the file name
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url); // Clean up the object URL
|
||||
console.log('done') } })
|
||||
"> Export to CSV </button>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
<div id="container" style="width:100%; height:400px;"></div>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Parse the savings_data from Flask
|
||||
const savingsData = JSON.parse('{{ COMP['savings_data'] | tojson }}');
|
||||
const chartData = savingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
|
||||
|
||||
// Get the legend name and vars for the tooltip
|
||||
const legendName = '{{ COMP["vars"]["name"] }}';
|
||||
const vars = JSON.parse('{{ COMP["vars"] | tojson }}');
|
||||
|
||||
// Tooltip content from vars
|
||||
const tooltipContent = Object.entries(vars).map(([key, value]) => `${key}: ${value}`).join('<br>');
|
||||
|
||||
// Calculate plot bands for each year with alternating background colors
|
||||
const plotBands = [];
|
||||
let year = new Date(savingsData[0][0]).getFullYear();
|
||||
let start = new Date(`${year}-01-01`).getTime();
|
||||
let end;
|
||||
|
||||
for (let i = 1; i < savingsData.length; i++) {
|
||||
const currentYear = new Date(savingsData[i][0]).getFullYear();
|
||||
if (currentYear !== year) {
|
||||
end = new Date(`${year + 1}-01-01`).getTime(); // End of the year
|
||||
plotBands.push({
|
||||
from: start,
|
||||
to: end,
|
||||
color: year % 2 === 0 ? 'white' : 'lemonchiffon' // Alternate colors
|
||||
});
|
||||
year = currentYear;
|
||||
start = new Date(`${year}-01-01`).getTime();
|
||||
}
|
||||
}
|
||||
// Add the final year
|
||||
end = new Date(`${year + 1}-01-01`).getTime();
|
||||
plotBands.push({
|
||||
from: start,
|
||||
to: end,
|
||||
color: year % 2 === 0 ? 'white' : 'lemonchiffon'
|
||||
});
|
||||
|
||||
// Add annotations for changes greater than 5000
|
||||
const annotations = [];
|
||||
for (let i = 1; i < chartData.length; i++) {
|
||||
const previousAmount = chartData[i - 1][1];
|
||||
const currentAmount = chartData[i][1];
|
||||
const difference = Math.abs(currentAmount - previousAmount);
|
||||
if (difference > 5000) {
|
||||
annotations.push({
|
||||
labels: [{
|
||||
point: {
|
||||
x: chartData[i][0], // Time of the data point
|
||||
y: chartData[i][1], // Amount at that point
|
||||
xAxis: 0,
|
||||
yAxis: 0
|
||||
},
|
||||
text: `Change: ${difference.toFixed(2)}` // Annotation text
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Highcharts configuration
|
||||
Highcharts.chart('container', {
|
||||
chart: {
|
||||
type: 'line'
|
||||
},
|
||||
title: {
|
||||
text: 'Savings Over Time'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
title: {
|
||||
text: 'Date'
|
||||
},
|
||||
plotBands: plotBands // Alternating background for years
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: 'Amount ($)'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
labelFormatter: function () {
|
||||
return `<span title="${tooltipContent}">${legendName}</span>`;
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
pointFormat: '{point.x:%Y-%m-%d}: <b>{point.y:.2f}</b>'
|
||||
},
|
||||
annotations: annotations, // Add annotations
|
||||
series: [{
|
||||
name: legendName,
|
||||
data: chartData,
|
||||
marker: {
|
||||
radius: 2, // Smaller points (default is 4)
|
||||
lineWidth: 0, // Optional: thinner border
|
||||
symbol: 'circle' // Optional: shape of the points (default is 'circle')
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user