Files
finplan/templates/index.html

256 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<style>
.col-form-label {
width:170px;
}
</style>
</head>
<body>
<div class="container-fluid">
<h3 align="center">Finance Tracker</h3>
<form id="vals_form" class="mt-3" action="/update" method="POST">
{% for r in DISP %}
<div class="row align-items-center">
{% for el in r %}
<div class="{{el.cl}}">
<div class="input-group">
{% if el.display=="select" %}
<label for="{{el.varname}}" class="input-group-text">{{el.label}}</label>
<select class="form-select border border-primary text-primary" id="{{el.varname}}" name="{{el.varname}}" 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>
{% elif el.display=="date" %}
<label for="{{el.varname}}" class="col-form-label me-2 text-end float-end">{{el.label}}</label>
<input type="number" step="any" class="form-control text-end float-end border border-primary" onchange="this.form.submit()"
id="{{el.varname}}" name="{{el.varname}}" value="{{ finance[el.varname] }}" {{el.display}}>
<input type="date" class="form-control text-end float-end border border-primary" id="{{el.datevarname}}"
name="{{el.datevarname}}" value="{{ finance[el.datevarname] }}" onchange="this.form.submit()">
{% else %}
<label for="{{el.varname}}" class="col-form-label me-2 text-end float-end">{{el.label}}</label>
{% if el.display== "readonly" %}
{% set bg="bg-light" %}
{% set bd="" %}
{% else %}
{% set bg="" %}
{% set bd="border-1 border-primary" %}
{% endif %}
<input type="number" step="any" class="{{bg}} form-control text-end float-end {{bd}}" onchange="this.form.submit()"
id="{{el.varname}}" name="{{el.varname}}" value="{{ finance[el.varname] }}" {{el.display}}>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</form>
<h5 align="center" class="mt-4">Fortnighthly Savings data:
{% if COMP %}
<font color="blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: value in blue below is value we should have been at when comparing to saved values</font>
{% endif %}
</h5>
<div class="row">
<div class="col-auto"> <div class="pt-1 pb-1 mb-0 alert text-center" style="background:lemonchiffon">2025</div>
{# get comparison date so we can use it below in loop to know when to print it out #}
{% set comp_yr=COMP['date'][:4] %}
{% set comp_mon=COMP['date'][5:7] %}
{% set comp_day=COMP['date'][8:10 ] %}
{% set comp_done=namespace( val=0 ) %}
{% set first_yr=2025 %}
{% for date, dollars in savings %}
{% set yr=date[:4] %}
{% set mon=date[5:7] %}
{% set day=date[8:10 ] %}
{% if yr|int > first_yr|int and mon == '01' and day|int <= 14 %}
</div><div class="col-auto">
<div class="pt-1 pb-1 mb-0 alert text-center" style="background:lemonchiffon">{{yr}}</div>
{% endif %}
<font color="black">
{{ date }}:&nbsp;
{{ '$%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'] }}:&nbsp;
{{ '$%0.2f' % COMP['amount']|float }}<br>
</font>
{% set comp_done.val=1 %}
{% endif %}
{% endfor %}
{% 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 %}
</div>
<div class="col-auto">
<div class="alert alert-warning">
<h6 class="alert-heading">SUMMARY/BUDGET</h6>
{% for label, value in BUDGET %}
<div>
{{label}} {{value}}
</div>
{% endfor %}
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary" onClick="$('#vals_form').submit()">Update</button>
</div>
<div class="col-auto">
<div class="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>
<div class="col-auto">
<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>
<div class="row mt-4" id="container" style="width:100%; height:400px;"></div>
<script type="text/javascript">
window.onload = function() {
document.getElementById("Sell_shares").value = {{finance['Sell_shares']}};
};
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>