Actualiser js/public.js

This commit is contained in:
2026-06-19 20:40:30 +02:00
parent f8c651334c
commit d9a40a405e
+34 -52
View File
@@ -7,40 +7,34 @@ let searchQuery = '';
let currentPage = 1; let currentPage = 1;
const itemsPerPage = 12; const itemsPerPage = 12;
async function loadPublicData() { // ── GÉNÉRATEUR D'ÉTOILES ─
try { function getStarsHTML(rating) {
const response = await fetch(`${API_URL}?action=get_films`); const r = parseFloat(rating) || 0;
films = await response.json(); const full = Math.floor(r);
generateStreamingSelect(); // Remplit le menu déroulant const hasHalf = (r - full) >= 0.5;
renderPublicGrid(); const empty = 5 - Math.ceil(r);
} catch (error) { let html = '★'.repeat(full);
console.error("Erreur de récupération :", error); if (hasHalf) html += '<span class="half-star">★</span>';
} html += `<span class="stars-muted">${'☆'.repeat(empty)}</span>`;
return html;
} }
// ── GÉNÉRATION DU MENU DÉROULANT STREAMING ── // ── GÉNÉRATION MENU STREAMING ──
function generateStreamingSelect() { function generateStreamingSelect() {
const select = document.getElementById('pub-streaming-select'); const select = document.getElementById('pub-streaming-select');
if (!select) return; if (!select) return;
// Extraire toutes les plateformes uniques
const platforms = new Set(); const platforms = new Set();
films.forEach(f => { films.forEach(f => {
if (f.type === 'critique' && f.streaming && if (f.type === 'critique' && f.streaming &&
f.streaming !== 'Disponible en support physique ou Cinéma' && f.streaming !== 'Disponible en support physique ou Cinéma' &&
f.streaming.trim() !== '') { f.streaming.trim() !== '') {
// Séparer par virgule si plusieurs plateformes
f.streaming.split(',').forEach(p => { f.streaming.split(',').forEach(p => {
const platform = p.trim(); const platform = p.trim();
if (platform.length > 0) platforms.add(platform); if (platform.length > 0) platforms.add(platform);
}); });
} }
}); });
// Trier alphabétiquement
const sortedPlatforms = Array.from(platforms).sort(); const sortedPlatforms = Array.from(platforms).sort();
// Conserver l'option "Toutes" et ajouter les plateformes
select.innerHTML = '<option value="">Toutes les plateformes</option>'; select.innerHTML = '<option value="">Toutes les plateformes</option>';
sortedPlatforms.forEach(platform => { sortedPlatforms.forEach(platform => {
const option = document.createElement('option'); const option = document.createElement('option');
@@ -48,8 +42,6 @@ function generateStreamingSelect() {
option.textContent = platform; option.textContent = platform;
select.appendChild(option); select.appendChild(option);
}); });
// Écouteur d'événement
select.addEventListener('change', (e) => { select.addEventListener('change', (e) => {
activeStreamingFilter = e.target.value; activeStreamingFilter = e.target.value;
currentPage = 1; currentPage = 1;
@@ -57,38 +49,43 @@ function generateStreamingSelect() {
}); });
} }
// ── CHARGEMENT ──
async function loadPublicData() {
try {
const response = await fetch(`${API_URL}?action=get_films`);
films = await response.json();
generateStreamingSelect();
renderPublicGrid();
} catch (error) {
console.error("Erreur de récupération :", error);
}
}
// ── NAVIGATION ONGLETS ──
function switchPubTab(tabName) { function switchPubTab(tabName) {
currentPubTab = tabName; currentPubTab = tabName;
activeRatingFilter = 0; activeRatingFilter = 0;
activeStreamingFilter = ''; activeStreamingFilter = '';
currentPage = 1; currentPage = 1;
// Reset le select
const select = document.getElementById('pub-streaming-select'); const select = document.getElementById('pub-streaming-select');
if (select) select.value = ''; if (select) select.value = '';
const ratingBar = document.getElementById('rating-filter-bar'); const ratingBar = document.getElementById('rating-filter-bar');
if (ratingBar) ratingBar.style.display = (tabName === 'critique') ? 'flex' : 'none'; if (ratingBar) ratingBar.style.display = (tabName === 'critique') ? 'flex' : 'none';
// Cacher le select sur l'onglet vidéothèque
if (select) select.style.display = (tabName === 'critique') ? 'block' : 'none'; if (select) select.style.display = (tabName === 'critique') ? 'block' : 'none';
document.querySelectorAll('.rating-filter-btn').forEach(btn => { document.querySelectorAll('.rating-filter-btn').forEach(btn => {
btn.classList.remove('active'); btn.classList.remove('active');
btn.querySelectorAll('.rf-star').forEach(s => s.classList.remove('filled')); btn.querySelectorAll('.rf-star').forEach(s => s.classList.remove('filled'));
}); });
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active')); document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
const activeBtn = document.getElementById(`tab-pub-${tabName}s`); const activeBtn = document.getElementById(`tab-pub-${tabName}s`);
if (activeBtn) activeBtn.classList.add('active'); if (activeBtn) activeBtn.classList.add('active');
renderPublicGrid(); renderPublicGrid();
} }
// ── FILTRE PAR NOTE (regroupement : 5★ = 4.5+5, 4★ = 3.5+4, etc.) ──
function filterByRating(stars) { function filterByRating(stars) {
if (currentPubTab !== 'critique') return; if (currentPubTab !== 'critique') return;
activeRatingFilter = (activeRatingFilter === stars) ? 0 : stars; activeRatingFilter = (activeRatingFilter === stars) ? 0 : stars;
document.querySelectorAll('.rating-filter-btn').forEach(btn => { document.querySelectorAll('.rating-filter-btn').forEach(btn => {
const n = parseInt(btn.dataset.stars); const n = parseInt(btn.dataset.stars);
btn.classList.toggle('active', n === activeRatingFilter); btn.classList.toggle('active', n === activeRatingFilter);
@@ -99,6 +96,7 @@ function filterByRating(stars) {
renderPublicGrid(); renderPublicGrid();
} }
// ── RENDU GRILLE ──
function renderPublicGrid() { function renderPublicGrid() {
const grid = document.getElementById('grid'); const grid = document.getElementById('grid');
const emptyState = document.getElementById('empty-state'); const emptyState = document.getElementById('empty-state');
@@ -106,10 +104,8 @@ function renderPublicGrid() {
if (!grid) return; if (!grid) return;
grid.innerHTML = ''; grid.innerHTML = '';
// 1. Filtrage par type
let filtered = films.filter(f => f.type === currentPubTab); let filtered = films.filter(f => f.type === currentPubTab);
// Filtre par note (regroupement : 5★ inclut 4.5, 4★ inclut 3.5, etc.)
if (currentPubTab === 'critique' && activeRatingFilter > 0) { if (currentPubTab === 'critique' && activeRatingFilter > 0) {
filtered = filtered.filter(f => { filtered = filtered.filter(f => {
const rating = parseFloat(f.rating) || 0; const rating = parseFloat(f.rating) || 0;
@@ -117,18 +113,15 @@ function renderPublicGrid() {
}); });
} }
// 3. Filtre par plateforme (avec normalisation)
if (currentPubTab === 'critique' && activeStreamingFilter) { if (currentPubTab === 'critique' && activeStreamingFilter) {
const filterLower = activeStreamingFilter.toLowerCase(); const filterLower = activeStreamingFilter.toLowerCase();
filtered = filtered.filter(f => { filtered = filtered.filter(f => {
if (!f.streaming || f.streaming === 'Disponible en support physique ou Cinéma') return false; if (!f.streaming || f.streaming === 'Disponible en support physique ou Cinéma') return false;
// On vérifie si la plateforme sélectionnée est présente dans le champ streaming
const platforms = f.streaming.split(',').map(p => p.trim().toLowerCase()); const platforms = f.streaming.split(',').map(p => p.trim().toLowerCase());
return platforms.includes(filterLower); return platforms.includes(filterLower);
}); });
} }
// 4. Recherche textuelle
if (searchQuery) { if (searchQuery) {
const q = searchQuery.toLowerCase(); const q = searchQuery.toLowerCase();
filtered = filtered.filter(f => filtered = filtered.filter(f =>
@@ -148,13 +141,11 @@ function renderPublicGrid() {
} }
if (emptyState) emptyState.style.display = 'none'; if (emptyState) emptyState.style.display = 'none';
// 5. Pagination
const totalPages = Math.ceil(filtered.length / itemsPerPage) || 1; const totalPages = Math.ceil(filtered.length / itemsPerPage) || 1;
if (currentPage > totalPages) currentPage = totalPages; if (currentPage > totalPages) currentPage = totalPages;
const startIdx = (currentPage - 1) * itemsPerPage; const startIdx = (currentPage - 1) * itemsPerPage;
const pageItems = filtered.slice(startIdx, startIdx + itemsPerPage); const pageItems = filtered.slice(startIdx, startIdx + itemsPerPage);
// 6. Rendu
pageItems.forEach(f => { pageItems.forEach(f => {
const card = document.createElement('div'); const card = document.createElement('div');
card.className = 'card'; card.className = 'card';
@@ -169,17 +160,12 @@ function renderPublicGrid() {
if (f.streaming && f.streaming !== 'Disponible en support physique ou Cinéma') { if (f.streaming && f.streaming !== 'Disponible en support physique ou Cinéma') {
streamingBadge = `<div class="card-streaming-badge" title="${f.streaming}">📺 ${f.streaming.split(',')[0]}</div>`; streamingBadge = `<div class="card-streaming-badge" title="${f.streaming}">📺 ${f.streaming.split(',')[0]}</div>`;
} else { } else {
streamingBadge = `<div class="card-physical-badge"> Physique / Cinéma</div>`; streamingBadge = `<div class="card-physical-badge">🎟 Physique / Cinéma</div>`;
} }
} }
if (f.type === 'critique') { if (f.type === 'critique') {
const rating = parseFloat(f.rating) || 0; const starsHTML = getStarsHTML(f.rating) + `<span class="card-rating-badge">${parseFloat(f.rating).toFixed(1)}</span>`;
const fullStars = Math.floor(rating);
const emptyStars = 5 - Math.ceil(rating);
const starsHTML = '★'.repeat(fullStars) + `<span class="stars-muted">${'☆'.repeat(emptyStars)}</span>`;
const ratingNum = `<span class="card-rating-badge">${rating.toFixed(1)}</span>`;
card.innerHTML = ` card.innerHTML = `
${posterHTML} ${posterHTML}
${streamingBadge} ${streamingBadge}
@@ -187,7 +173,7 @@ function renderPublicGrid() {
<h3 class="card-title" title="${f.title}">${f.title}</h3> <h3 class="card-title" title="${f.title}">${f.title}</h3>
<p class="card-director">${f.director || 'Réalisateur inconnu'}</p> <p class="card-director">${f.director || 'Réalisateur inconnu'}</p>
<p class="card-meta">${f.year || '-'}</p> <p class="card-meta">${f.year || '-'}</p>
<div class="card-stars">${starsHTML}${ratingNum}</div> <div class="card-stars">${starsHTML}</div>
</div>`; </div>`;
} else { } else {
card.innerHTML = ` card.innerHTML = `
@@ -208,11 +194,11 @@ function renderPublicGrid() {
renderPagination(totalPages); renderPagination(totalPages);
} }
// ── PAGINATION ──
function renderPagination(totalPages) { function renderPagination(totalPages) {
const container = document.getElementById('pub-pagination'); const container = document.getElementById('pub-pagination');
if (!container) return; if (!container) return;
container.innerHTML = ''; container.innerHTML = '';
if (totalPages <= 1) return; if (totalPages <= 1) return;
const info = document.createElement('span'); const info = document.createElement('span');
@@ -232,7 +218,6 @@ function renderPagination(totalPages) {
if (endPage - startPage + 1 < maxButtons) { if (endPage - startPage + 1 < maxButtons) {
startPage = Math.max(1, endPage - maxButtons + 1); startPage = Math.max(1, endPage - maxButtons + 1);
} }
if (startPage > 1) { if (startPage > 1) {
container.appendChild(createPubPageBtn(1)); container.appendChild(createPubPageBtn(1));
if (startPage > 2) container.appendChild(createPubEllipsis()); if (startPage > 2) container.appendChild(createPubEllipsis());
@@ -244,7 +229,6 @@ function renderPagination(totalPages) {
if (endPage < totalPages - 1) container.appendChild(createPubEllipsis()); if (endPage < totalPages - 1) container.appendChild(createPubEllipsis());
container.appendChild(createPubPageBtn(totalPages)); container.appendChild(createPubPageBtn(totalPages));
} }
const nextBtn = document.createElement('button'); const nextBtn = document.createElement('button');
nextBtn.innerHTML = '<i class="ti ti-chevron-right"></i>'; nextBtn.innerHTML = '<i class="ti ti-chevron-right"></i>';
nextBtn.disabled = currentPage === totalPages; nextBtn.disabled = currentPage === totalPages;
@@ -268,6 +252,7 @@ function createPubEllipsis() {
return span; return span;
} }
// ── DÉTAIL ──
function openDetail(id) { function openDetail(id) {
const f = films.find(item => item.id == id); const f = films.find(item => item.id == id);
if (!f) return; if (!f) return;
@@ -296,12 +281,9 @@ function openDetail(id) {
if (dBody) { if (dBody) {
if (f.type === 'critique') { if (f.type === 'critique') {
const rating = parseFloat(f.rating) || 0; const stars = getStarsHTML(f.rating) + `<span style="font-size:1rem; color:var(--muted); margin-left:0.5rem;">${parseFloat(f.rating).toFixed(1)}/5</span>`;
const fullStars = Math.floor(rating);
const emptyStars = 5 - Math.ceil(rating);
const stars = '★'.repeat(fullStars) + `<span class="stars-muted">${'☆'.repeat(emptyStars)}</span>`;
dBody.innerHTML = ` dBody.innerHTML = `
<div class="detail-stars">${stars} <span style="font-size:1rem; color:var(--muted); margin-left:0.5rem;">${rating.toFixed(1)}/5</span></div> <div class="detail-stars">${stars}</div>
<div class="pub-review-card"> <div class="pub-review-card">
<div class="pub-review-quote-icon"><i class="ti ti-quote"></i></div> <div class="pub-review-quote-icon"><i class="ti ti-quote"></i></div>
<p class="pub-review-text">${f.review ? f.review : 'Aucun texte rédigé pour le moment.'}</p> <p class="pub-review-text">${f.review ? f.review : 'Aucun texte rédigé pour le moment.'}</p>
@@ -344,9 +326,9 @@ function closeDetail() {
if (detailOverlay) detailOverlay.classList.remove('open'); if (detailOverlay) detailOverlay.classList.remove('open');
} }
// ── INITIALISATION ──
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
loadPublicData(); loadPublicData();
const searchInput = document.getElementById('pub-search-input'); const searchInput = document.getElementById('pub-search-input');
if (searchInput) { if (searchInput) {
searchInput.addEventListener('input', (e) => { searchInput.addEventListener('input', (e) => {