add dashboard
This commit is contained in:
@ -1,35 +1,142 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
<head>
|
<head>
|
||||||
<title>Iceberg Price Tracker</title>
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>🧊 Iceberg Price Tracker</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-900 text-white p-10">
|
<body class="bg-gray-900 text-gray-100 min-h-screen p-6 md:p-12">
|
||||||
<h1 class="text-3xl font-bold mb-6">🧊 Iceberg Dashboard</h1>
|
|
||||||
|
|
||||||
<form action="/add" method="POST" class="mb-10">
|
<div class="max-w-6xl mx-auto">
|
||||||
<input type="text" name="name" placeholder="Nom Produit..." class="p-2 rounded bg-gray-800 border border-gray-700 w-1/2">
|
<header class="mb-10 flex justify-between items-center">
|
||||||
<input type="text" name="link" placeholder="Lien Amazon..." class="p-2 rounded bg-gray-800 border border-gray-700 w-1/2">
|
<h1 class="text-4xl font-extrabold tracking-tight text-white">
|
||||||
<button type="submit" class="bg-blue-600 px-4 py-2 rounded">Ajouter</button>
|
🧊 Iceberg <span class="text-blue-500">Tracker</span>
|
||||||
</form>
|
</h1>
|
||||||
|
<div class="text-sm text-gray-400 bg-gray-800 px-3 py-1 rounded-full border border-gray-700">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
Statut : <span class="text-green-400">Connecté</span>
|
||||||
<div th:each="product : ${products}" class="bg-gray-800 p-4 rounded-xl shadow-lg">
|
|
||||||
<div class="flex items-center gap-4 mb-4">
|
|
||||||
<img th:src="${product.imageUrl}" class="w-16 h-16 object-contain rounded">
|
|
||||||
<h2 class="flex-1 font-semibold text-sm" th:text="${product.name}">Nom du produit</h2>
|
|
||||||
<a th:href="@{'/delete/' + ${product.id}}" class="text-red-500">🗑️</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
<canvas th:id="'chart-' + ${product.id}"></canvas>
|
<section class="bg-gray-800 p-6 rounded-2xl border border-gray-700 shadow-xl mb-10">
|
||||||
|
<h2 class="text-xl font-semibold mb-4 text-gray-200">Ajouter un produit à surveiller</h2>
|
||||||
|
<form th:action="@{/add}" method="POST" class="flex flex-col md:flex-row gap-4">
|
||||||
|
<input type="text" name="name" required placeholder="Nom du produit (ex: Station Soudure)"
|
||||||
|
class="flex-1 p-3 rounded-lg bg-gray-900 border border-gray-600 focus:border-blue-500 focus:outline-none transition">
|
||||||
|
<input type="url" name="link" required placeholder="Lien Amazon (https://...)"
|
||||||
|
class="flex-1 p-3 rounded-lg bg-gray-900 border border-gray-600 focus:border-blue-500 focus:outline-none transition">
|
||||||
|
<button type="submit" class="bg-blue-600 hover:bg-blue-500 text-white font-bold py-3 px-8 rounded-lg transition duration-200 transform hover:scale-105">
|
||||||
|
Démarrer le tracking
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
<script th:inline="javascript">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-8">
|
||||||
/* Code pour générer le graphique Chart.js pour chaque produit */
|
|
||||||
</script>
|
<div th:each="product : ${products}" th:if="${product != null}"
|
||||||
|
class="bg-gray-800 rounded-2xl border border-gray-700 overflow-hidden shadow-lg hover:border-gray-500 transition duration-300">
|
||||||
|
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex items-start gap-4 mb-6">
|
||||||
|
<div class="bg-white p-2 rounded-lg w-24 h-24 flex items-center justify-center shrink-0">
|
||||||
|
<img th:src="${product.imageUrl ?: 'https://via.placeholder.com/150'}"
|
||||||
|
class="max-w-full max-h-full object-contain" alt="Image produit">
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 overflow-hidden">
|
||||||
|
<h3 class="text-lg font-bold text-white truncate" th:text="${product.name}">Nom</h3>
|
||||||
|
<a th:href="${product.link}" target="_blank" class="text-blue-400 text-xs hover:underline truncate block mb-2 italic">
|
||||||
|
Voir sur le site ↗
|
||||||
|
</a>
|
||||||
|
<a th:href="@{'/delete/' + ${product.id}}"
|
||||||
|
onclick="return confirm('Arrêter de suivre ce produit ?')"
|
||||||
|
class="text-red-400 text-xs font-semibold hover:text-red-300 transition">
|
||||||
|
🗑️ Supprimer le tracking
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative h-64 w-full bg-gray-900/50 rounded-xl p-2">
|
||||||
|
<canvas th:id="'chart-' + ${product.id}"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script th:inline="javascript">
|
||||||
|
(function() {
|
||||||
|
const productId = [[${product.id}]];
|
||||||
|
const ctx = document.getElementById('chart-' + productId);
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
fetch('/api/prices/' + productId)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
// Optionnel : afficher un message si pas de données
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extraction des labels (dates) et des prix
|
||||||
|
const labels = data.map(d => {
|
||||||
|
const date = new Date(d.dateCheck);
|
||||||
|
return date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short' });
|
||||||
|
});
|
||||||
|
const prices = data.map(d => d.price);
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Prix (€)',
|
||||||
|
data: prices,
|
||||||
|
borderColor: '#3b82f6', // Bleu
|
||||||
|
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
||||||
|
borderWidth: 3,
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4, // Courbe lisse
|
||||||
|
pointRadius: 4,
|
||||||
|
pointBackgroundColor: '#3b82f6'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: { display: false },
|
||||||
|
tooltip: {
|
||||||
|
backgroundColor: '#1f2937',
|
||||||
|
titleColor: '#9ca3af',
|
||||||
|
bodyColor: '#ffffff',
|
||||||
|
borderColor: '#374151',
|
||||||
|
borderWidth: 1,
|
||||||
|
displayColors: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: false,
|
||||||
|
grid: { color: 'rgba(255, 255, 255, 0.05)' },
|
||||||
|
ticks: { color: '#9ca3af' }
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
grid: { display: false },
|
||||||
|
ticks: { color: '#9ca3af' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => console.error("Erreur API:", err));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div th:if="${#lists.isEmpty(products)}" class="text-center py-20 bg-gray-800 rounded-3xl border-2 border-dashed border-gray-700">
|
||||||
|
<p class="text-gray-400 text-xl italic">Aucun produit en cours de surveillance. Ajoutez-en un au-dessus !</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user