feat: initial dashboard implementation and robust attendance parsing

- Added a Makefile to easily run project scripts (fees, match, web, image)
- Modified attendance.py to dynamically handle a variable number of header rows from the Google Sheet
- Updated both attendance calculations and calculate_fees terminal output to show actual attendance counts (e.g., '750 CZK (3)')
- Created a Flask web dashboard (app.py and templates/fees.html) to view member fees in an attractive, condensed, terminal-like UI
- Bound the Flask server to port 5000 and added a routing alias from '/' to '/fees'
- Configured Python virtual environment (.venv) creation directly into the Makefile to resolve global pip install errors on macOS

Co-authored-by: Antigravity <antigravity@deepmind.com>
This commit is contained in:
Jan Novak
2026-02-27 13:19:00 +01:00
commit 3bfea4e0a4
16 changed files with 1322 additions and 0 deletions

141
templates/fees.html Normal file
View File

@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FUJ Fees Dashboard</title>
<style>
body {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
background-color: #0c0c0c;
/* Deeper black */
color: #cccccc;
/* Base gray terminal text */
padding: 10px;
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
font-size: 11px;
/* Even smaller font */
line-height: 1.2;
}
h1 {
color: #00ff00;
/* Terminal green */
font-family: inherit;
/* Use monospace for header too */
margin-top: 10px;
margin-bottom: 20px;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 14px;
}
.table-container {
background-color: transparent;
/* Remove the card background */
border: 1px solid #333;
/* Just a thin outline if needed, or none */
box-shadow: none;
overflow-x: auto;
width: 100%;
max-width: 1200px;
}
table {
border-collapse: collapse;
width: 100%;
table-layout: auto;
}
th,
td {
padding: 2px 8px;
/* Extremely tight padding */
text-align: right;
border-bottom: 1px dashed #222;
/* Dashed lines for terminal feel */
white-space: nowrap;
}
th:first-child,
td:first-child {
text-align: left;
}
th {
background-color: transparent;
color: #888888;
font-weight: normal;
border-bottom: 1px solid #555;
/* Stronger border for header */
text-transform: lowercase;
}
tr:hover {
background-color: #1a1a1a;
/* Very subtle hover */
}
.total {
font-weight: bold;
background-color: transparent;
color: #00ff00;
/* Highlight total row */
border-top: 1px solid #555;
}
.total:hover {
background-color: transparent;
}
.cell-empty {
color: #444444;
/* Darker gray for empty cells */
}
.cell-paid {
color: #aaaaaa;
/* Light gray for normal cells */
}
</style>
</head>
<body>
<h1>FUJ Fees Dashboard</h1>
<div class="table-container">
<table>
<thead>
<tr>
<th>Member</th>
{% for m in months %}
<th>{{ m }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in results %}
<tr>
<td>{{ row.name }}</td>
{% for cell in row.months %}
<td class="{% if cell == '-' %}cell-empty{% else %}cell-paid{% endif %}">{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr class="total">
<td>TOTAL</td>
{% for t in totals %}
<td>{{ t }}</td>
{% endfor %}
</tr>
</tfoot>
</table>
</div>
</body>
</html>