Spaces:
Running
Running
import React, { useMemo } from "react"; | |
import { Box } from "@mui/material"; | |
import { useLeaderboard } from "../../context/LeaderboardContext"; | |
import SectionHeader from "./components/SectionHeader"; | |
import LanguageList from "./components/LanguageList"; | |
import LeaderboardGrid from "./components/LeaderboardGrid"; | |
import EmptyState from "./components/EmptyState"; | |
import { useLanguageStats } from "./hooks/useLanguageStats"; | |
const ITEMS_PER_PAGE = 4; | |
const LeaderboardSection = ({ | |
title, | |
leaderboards, | |
filteredLeaderboards, | |
id, | |
showEmptyState = false, | |
}) => { | |
const { | |
expandedSections, | |
setExpandedSections, | |
selectedLanguage, | |
setSelectedLanguage, | |
searchQuery, | |
selectedCategories, | |
} = useLeaderboard(); | |
const isExpanded = expandedSections.has(id); | |
const { languages, languageStats, LANGUAGE_FAMILIES, findLanguageFamily } = | |
useLanguageStats(leaderboards, filteredLeaderboards); | |
// Créer un titre enrichi qui inclut les filtres de langue | |
const enrichedTitle = useMemo(() => { | |
let newTitle = title; | |
// Ajouter les langues sélectionnées au titre si elles ne sont pas déjà incluses | |
if (selectedLanguage && selectedLanguage.size > 0) { | |
const languageNames = Array.from(selectedLanguage) | |
.map((lang) => lang.charAt(0).toUpperCase() + lang.slice(1)) | |
.join(", "); | |
// Vérifier si le titre contient déjà "language" | |
if (!newTitle.toLowerCase().includes("language")) { | |
newTitle = `${newTitle} + Language: ${languageNames}`; | |
} else if ( | |
!newTitle.toLowerCase().includes(languageNames.toLowerCase()) | |
) { | |
// Si le titre contient "language" mais pas les noms spécifiques | |
newTitle = newTitle.replace( | |
/language(\s+specific)?/i, | |
`Language: ${languageNames}` | |
); | |
} | |
} | |
// Ajouter le terme de recherche s'il existe | |
if ( | |
searchQuery && | |
!newTitle | |
.toLowerCase() | |
.includes(`matching "${searchQuery.toLowerCase()}"`) | |
) { | |
newTitle = `${newTitle} matching "${searchQuery}"`; | |
} | |
return newTitle; | |
}, [title, selectedLanguage, searchQuery]); | |
// Filtrer pour n'avoir que les leaderboards approuvés | |
const approvedLeaderboards = useMemo(() => { | |
// Filtrer d'abord pour n'avoir que les leaderboards approuvés | |
const approved = filteredLeaderboards.filter( | |
(leaderboard) => leaderboard.approval_status === "approved" | |
); | |
// Trier par trending_score (ordre décroissant) | |
return [...approved].sort((a, b) => { | |
const scoreA = a.trending_score || 0; | |
const scoreB = b.trending_score || 0; | |
return scoreB - scoreA; // Tri décroissant | |
}); | |
}, [filteredLeaderboards]); | |
// On ne retourne null que si on n'a pas de leaderboards bruts | |
if (!leaderboards) return null; | |
// Déterminer si on doit paginer ou montrer tous les leaderboards | |
const shouldShowAll = | |
(selectedCategories.size === 1 && selectedCategories.has(id)) || // Une seule catégorie sélectionnée ET c'est celle-ci | |
(selectedCategories.size > 1 && id === "combined") || // Plusieurs catégories ET c'est la section combinée | |
isExpanded || // Section dépliée (quelle que soit la sélection) | |
id === "search-results"; // Toujours afficher tous les résultats pour la recherche textuelle | |
// Si on doit tout montrer, on ne divise pas la liste | |
const displayedLeaderboards = shouldShowAll | |
? approvedLeaderboards | |
: approvedLeaderboards.slice(0, ITEMS_PER_PAGE); | |
const remainingLeaderboards = shouldShowAll | |
? [] | |
: approvedLeaderboards.slice(ITEMS_PER_PAGE); | |
// Calculate how many skeletons we need (seulement si on ne montre pas tout) | |
const skeletonsNeeded = shouldShowAll | |
? 0 | |
: Math.max(0, 4 - approvedLeaderboards.length); | |
// On affiche le bouton expand seulement quand on n'a pas de sélection et que ce n'est pas une recherche textuelle | |
const showExpandButton = | |
selectedCategories.size === 0 && id !== "search-results"; | |
// Le bouton est actif seulement s'il y a plus de 4 leaderboards | |
const isExpandButtonEnabled = approvedLeaderboards.length > ITEMS_PER_PAGE; | |
const toggleExpanded = () => { | |
setExpandedSections((prev) => { | |
const newSet = new Set(prev); | |
if (isExpanded) { | |
newSet.delete(id); | |
} else { | |
newSet.add(id); | |
} | |
return newSet; | |
}); | |
}; | |
// Déterminer si on doit afficher la liste des langues | |
const showLanguageList = | |
languages && | |
selectedCategories.size > 0 && | |
(id === "language" || | |
(selectedCategories.size > 1 && selectedCategories.has("language"))); | |
return ( | |
<Box sx={{ mb: 6 }}> | |
<SectionHeader | |
title={enrichedTitle} | |
count={approvedLeaderboards.length} | |
isExpanded={isExpanded} | |
onToggleExpand={toggleExpanded} | |
showExpandButton={showExpandButton} | |
isExpandButtonEnabled={isExpandButtonEnabled} | |
/> | |
{showLanguageList && ( | |
<LanguageList | |
languages={languages} | |
languageStats={languageStats} | |
selectedLanguage={selectedLanguage} | |
onLanguageSelect={setSelectedLanguage} | |
LANGUAGE_FAMILIES={LANGUAGE_FAMILIES} | |
findLanguageFamily={findLanguageFamily} | |
/> | |
)} | |
{approvedLeaderboards.length === 0 ? ( | |
// Toujours afficher EmptyState, que showEmptyState soit true ou non | |
<EmptyState title={enrichedTitle} searchQuery={searchQuery} /> | |
) : ( | |
<LeaderboardGrid | |
displayedLeaderboards={displayedLeaderboards} | |
remainingLeaderboards={remainingLeaderboards} | |
isExpanded={isExpanded} | |
skeletonsNeeded={skeletonsNeeded} | |
id={id} | |
/> | |
)} | |
</Box> | |
); | |
}; | |
export default LeaderboardSection; | |