Files
weight-tracker/backend/target/classes/templates/dashboard.html
2025-07-15 18:34:27 +02:00

199 lines
8.7 KiB
HTML

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dashboard | Weight Tracker</title>
<link th:href="@{/vendor/fontawesome-free/css/all.min.css}" rel="stylesheet">
<link th:href="@{/css/sb-admin-2.min.css}" rel="stylesheet">
<link rel="icon" href="data:,">
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Daterangepicker -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
</head>
<body id="page-top">
<div id="wrapper">
<div th:replace="~{fragments/fragment-menu :: menu}"></div>
<div id="content-wrapper" class="d-flex flex-column">
<div id="content" class="p-4">
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<h1 class="h4 mb-0 text-gray-800">Dashboard</h1>
</nav>
<div class="container-fluid">
<div class="row gx-3 gy-4">
<!-- Últimos registros -->
<div class="col-12 col-lg-6">
<div class="card shadow mb-4 h-100">
<div class="card-header">Últimos 10 registros</div>
<div class="card-body">
<table class="table table-sm">
<thead>
<tr>
<th>Fecha</th>
<th>Peso (kg)</th>
</tr>
</thead>
<tbody>
<tr th:each="r : ${ultimos}">
<td th:text="${#temporals.format(r.date, 'yyyy-MM-dd HH:mm')}">2025-07-10</td>
<td th:text="${r.weight}">70.5</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Gráfica -->
<div class="col-12 col-lg-6 mt-3 mt-lg-0">
<div class="card shadow mb-4 h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<span id="chart-title">Evolución del peso</span>
<div class="dropdown">
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" id="metricDropdown"
data-bs-toggle="dropdown" aria-expanded="false">
Métricas
</button>
<ul class="dropdown-menu dropdown-menu-end p-2" aria-labelledby="metricDropdown"
style="min-width: 200px;">
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="weight" id="metricWeight" checked><label class="form-check-label" for="metricWeight">Peso (kg)</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="bodyFat" id="metricBodyFat"><label class="form-check-label" for="metricBodyFat">% Grasa</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="muscleMass" id="metricMuscleMass"><label class="form-check-label" for="metricMuscleMass">Masa muscular</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="waterPercent" id="metricWater"><label class="form-check-label" for="metricWater">% Agua</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="bmi" id="metricBMI"><label class="form-check-label" for="metricBMI">IMC</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="metabolicAge" id="metricMetAge"><label class="form-check-label" for="metricMetAge">Edad metabólica</label></div></li>
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="visceralFat" id="metricVisceral"><label class="form-check-label" for="metricVisceral">Grasa visceral</label></div></li>
</ul>
</div>
</div>
<div class="card-body">
<div class="mb-2">
<label for="chartDateRange">Filtrar por fecha:</label>
<input type="text" id="chartDateRange" class="form-control form-control-sm w-auto d-inline-block">
</div>
<canvas id="chart" class="w-100" style="max-height: 300px;"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery, Bootstrap y plugins -->
<script th:src="@{/vendor/jquery/jquery.min.js}"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<script th:src="@{/js/sb-admin-2.min.js}"></script>
<!-- Script Chart -->
<script th:inline="javascript">
$(document).ready(function () {
// Datos desde el controlador
const labels = /*[[${labels}]]*/[];
const dataMap = {
weight: /*[[${pesos}]]*/[],
bodyFat: /*[[${grasa}]]*/[],
muscleMass: /*[[${musculo}]]*/[],
waterPercent: /*[[${agua}]]*/[],
bmi: /*[[${bmi}]]*/[],
metabolicAge: /*[[${edadMetabolica}]]*/[],
visceralFat: /*[[${grasaVisceral}]]*/[]
};
const metricColors = {
weight: 'rgba(78, 115, 223, 1)',
bodyFat: 'rgba(231, 74, 59, 1)',
muscleMass: 'rgba(28, 200, 138, 1)',
waterPercent: 'rgba(54, 185, 204, 1)',
bmi: 'rgba(246, 194, 62, 1)',
metabolicAge: 'rgba(133, 135, 150, 1)',
visceralFat: 'rgba(106, 90, 205, 1)'
};
const ctx = document.getElementById('chart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Peso (kg)',
data: dataMap.weight,
borderColor: metricColors.weight,
borderWidth: 2,
fill: false,
tension: 0.3,
pointRadius: 3
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
ticks: {
maxRotation: 45,
minRotation: 45
}
},
y: {
beginAtZero: false
}
}
}
});
// Filtro por métricas
$('.metric-check').on('change', function () {
const selected = $('.metric-check:checked').map(function () {
return this.value;
}).get();
chart.data.datasets = selected.map(metric => ({
label: $(`label[for="metric${metric.charAt(0).toUpperCase() + metric.slice(1)}"]`).text(),
data: dataMap[metric],
borderColor: metricColors[metric],
borderWidth: 2,
fill: false,
tension: 0.3,
pointRadius: 3
}));
chart.update();
});
// Rango de fechas
$('#chartDateRange').daterangepicker({
autoUpdateInput: false,
locale: {
cancelLabel: 'Limpiar',
applyLabel: 'Aplicar',
format: 'YYYY-MM-DD'
}
});
$('#chartDateRange').on('apply.daterangepicker', function (ev, picker) {
const start = picker.startDate.format('YYYY-MM-DD');
const end = picker.endDate.format('YYYY-MM-DD');
window.location.href = `/?start=${start}&end=${end}`;
});
$('#chartDateRange').on('cancel.daterangepicker', function () {
window.location.href = `/`;
});
});
</script>
</div>
</div>
</div>
</body>
</html>