Files
administration/wwwroot/js/HelloFresh/historique.js
2025-09-03 20:17:50 +02:00

175 lines
5.7 KiB
JavaScript

// ---------- ÉTAT ----------
let HISTORY_CACHE = []; // [{ date, rawDate, items: [...] }]
let HISTORY_SEARCH = "";
// Normalisation basique pour la recherche
const ACCENT_RX = /[\u0300-\u036f]/g;
const norm = s => (s || "").toString().toLowerCase()
.normalize("NFD").replace(ACCENT_RX, "").trim();
// Palette de couleurs (plus large possible pour différencier)
const USER_COLORS = [
"#C0392B", // rouge foncé
"#2980B9", // bleu foncé
"#27AE60", // vert foncé
"#D35400", // orange foncé
"#8E44AD", // violet foncé
"#2C3E50", // gris/bleu très foncé
"#7D3C98", // violet profond
"#1ABC9C" // turquoise foncé
];
// Cache pour assigner une couleur unique par user
const userColorMap = new Map();
let userColorIndex = 0;
function getUserColor(username) {
if (!username) return "#999";
if (!userColorMap.has(username)) {
// Assigne une couleur en cycle
userColorMap.set(username, USER_COLORS[userColorIndex % USER_COLORS.length]);
userColorIndex++;
}
return userColorMap.get(username);
}
function buildUserBadges(usersArr) {
const wrap = document.createElement("div");
wrap.className = "label-container";
(usersArr || []).forEach(u => {
const span = document.createElement("span");
span.className = "label-badge user-badge";
span.textContent = u;
// Couleur dynamique par utilisateur
span.style.backgroundColor = getUserColor(u);
span.style.color = "#fff"; // texte blanc pour lisibilité
wrap.appendChild(span);
});
return wrap;
}
const truncate = (s, m) => (s && s.length > m ? s.slice(0, m) + "…" : (s ?? ""));
function buildRecipeCardHistory(rec) {
const card = document.createElement("div");
card.className = "card";
card.id = `hist-${rec.id}`;
const name = rec.name || `Recette ${rec.id}`;
const imgSrc = rec.image || "/images/recipe-placeholder.png"; // mets un vrai fichier ici
card.innerHTML = `
<div class="image-container">
<img src="${imgSrc}" alt="${truncate(name, 10)}"
onerror="this.onerror=null;this.src='/images/recipe-placeholder.png'">
<div class="badge-portions">${rec.portions} portion${rec.portions > 1 ? 's' : ''}</div>
</div>
<div class="card-content"><h3>${name}</h3></div>
`;
// badges utilisateurs (JSON camelCase => "users")
const users = Array.isArray(rec.users) ? rec.users : Array.isArray(rec.Users) ? rec.Users : [];
if (users.length) {
card.querySelector(".image-container")?.appendChild(buildUserBadges(users));
}
return card;
}
function buildDateSection(dateStr, items) {
const sec = document.createElement("section");
sec.className = "history-section";
const h = document.createElement("h3");
h.className = "history-date";
h.textContent = dateStr;
sec.appendChild(h);
const grid = document.createElement("div");
grid.className = "hf-grid";
if (Array.isArray(items) && items.length) {
items.forEach(r => grid.appendChild(buildRecipeCardHistory(r)));
} else {
grid.innerHTML = `<p class="placeholder">Aucune recette pour cette date.</p>`;
}
sec.appendChild(grid);
return sec;
}
// Applique la recherche sur le cache et rend
function renderHistoryFiltered() {
const container = document.getElementById("historyContainer");
if (!container) return;
const q = norm(HISTORY_SEARCH);
const groups = [];
for (const g of (HISTORY_CACHE || [])) {
if (!q) {
groups.push(g);
continue;
}
const filteredItems = (g.items || []).filter(it => norm(it.name).includes(q));
if (filteredItems.length) {
groups.push({ date: g.date, rawDate: g.rawDate, items: filteredItems });
}
}
container.innerHTML = "";
if (!groups.length) {
container.innerHTML = `<p class="placeholder">Aucun résultat pour “${HISTORY_SEARCH}”.</p>`;
return;
}
groups.forEach(group => container.appendChild(buildDateSection(group.date, group.items)));
}
// ---------- CHARGEMENT ----------
async function loadHistory(scope = "mine") {
const container = document.getElementById("historyContainer");
if (!container) return;
container.innerHTML = "Chargement…";
try {
const isUserImportant = (scope !== "all");
const res = await fetch(`/HelloFresh/GetHistory?isUserImportant=${isUserImportant ? "true" : "false"}&search=${encodeURIComponent(HISTORY_SEARCH)}`, { credentials: "same-origin" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json(); // [{ date, rawDate, items }]
HISTORY_CACHE = Array.isArray(data) ? data : [];
renderHistoryFiltered(); // premier rendu (avec éventuel terme déjà saisi)
} catch (e) {
console.error("loadHistory error:", e);
container.innerHTML = `<p class="placeholder">Erreur de chargement.</p>`;
}
}
// ---------- INIT ----------
document.addEventListener("DOMContentLoaded", () => {
const scopeSel = document.getElementById("historyScope");
const search = document.getElementById("historySearch");
// charge au démarrage
loadHistory(scopeSel?.value || "mine");
// changement de portée
scopeSel?.addEventListener("change", () => loadHistory(scopeSel.value || "mine"));
// recherche (debounce)
let timer;
search?.addEventListener("input", (e) => {
HISTORY_SEARCH = e.target.value || "";
clearTimeout(timer);
timer = setTimeout(renderHistoryFiltered, 200);
});
// Entrée = rendu immédiat
search?.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
e.preventDefault();
clearTimeout(timer);
renderHistoryFiltered();
}
});
});