fix: hide empty demographic data in marketing page

- Filter out NOT_SPECIFIED and empty values from charts
- Show placeholder message when no demographic data available
- Hide city/gender filters when no valid data
- Remove debug console.log statements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
soufiane 2025-12-01 15:55:29 +01:00
parent 51ec802131
commit f2d4bb3c5f

View File

@ -66,10 +66,6 @@ export default function MarketingPage() {
setLoading(true);
const token = localStorage.getItem('auth_token') || localStorage.getItem('token');
console.log('Loading marketing stats...');
console.log('API URL:', API_BASE_URL);
console.log('Token present:', !!token);
const response = await fetch(
`${API_BASE_URL}/admin/marketing/stats`,
{
@ -80,22 +76,18 @@ export default function MarketingPage() {
}
);
console.log('Response status:', response.status);
if (!response.ok) {
let errorMessage = 'Erreur lors du chargement';
try {
const errorData = await response.json();
errorMessage = errorData.error || errorData.message || errorMessage;
console.error('Error from API:', errorData);
} catch (e) {
console.error('Failed to parse error response');
} catch {
// Ignore parse error
}
throw new Error(errorMessage);
}
const data = await response.json();
console.log('Marketing stats loaded:', data);
setStats(data.data);
} catch (error: any) {
console.error('Error loading marketing stats:', error);
@ -216,6 +208,22 @@ export default function MarketingPage() {
);
}
// Filtrer les données vides/non spécifiées pour les graphiques
const filteredGenderData = stats.byGender.filter(
(g) => g.gender && !g.gender.toLowerCase().includes('not_specified') && !g.gender.toLowerCase().includes('non spécifié') && g.count > 0
);
const filteredAgeData = stats.byAge.filter(
(a) => a.range && !a.range.toLowerCase().includes('non spécifié') && a.count > 0
);
const filteredCityData = stats.byCity.filter(
(c) => c.city && c.city.trim() !== '' && !c.city.toLowerCase().includes('non spécifié') && c.count > 0
);
// Vérifier s'il y a des données démographiques valides
const hasDemographicData = filteredGenderData.length > 0 || filteredAgeData.length > 0 || filteredCityData.length > 0;
return (
<div className="p-6 max-w-7xl mx-auto">
{/* En-tête */}
@ -287,9 +295,12 @@ export default function MarketingPage() {
</Card>
</div>
{/* Graphiques */}
{/* Graphiques - Affichés uniquement s'il y a des données valides */}
{hasDemographicData ? (
<>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
{/* Répartition par genre */}
{filteredGenderData.length > 0 && (
<Card className="p-6">
<h2 className="text-xl font-bold mb-4 flex items-center gap-2">
<BarChart3 className="w-6 h-6 text-blue-600" />
@ -298,7 +309,7 @@ export default function MarketingPage() {
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={stats.byGender}
data={filteredGenderData}
dataKey="count"
nameKey="gender"
cx="50%"
@ -306,7 +317,7 @@ export default function MarketingPage() {
outerRadius={100}
label={(entry: any) => `${entry.gender}: ${entry.count}`}
>
{stats.byGender.map((entry, index) => (
{filteredGenderData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
@ -315,15 +326,17 @@ export default function MarketingPage() {
</PieChart>
</ResponsiveContainer>
</Card>
)}
{/* Répartition par âge */}
{filteredAgeData.length > 0 && (
<Card className="p-6">
<h2 className="text-xl font-bold mb-4 flex items-center gap-2">
<BarChart3 className="w-6 h-6 text-green-600" />
Répartition par Âge
</h2>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={stats.byAge}>
<BarChart data={filteredAgeData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="range" />
<YAxis />
@ -333,16 +346,18 @@ export default function MarketingPage() {
</BarChart>
</ResponsiveContainer>
</Card>
)}
</div>
{/* Top villes */}
{filteredCityData.length > 0 && (
<Card className="p-6 mb-6">
<h2 className="text-xl font-bold mb-4 flex items-center gap-2">
<MapPin className="w-6 h-6 text-purple-600" />
Top Villes ({stats.byCity.length})
Top Villes ({filteredCityData.length})
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
{stats.byCity.slice(0, 10).map((city, index) => (
{filteredCityData.slice(0, 10).map((city, index) => (
<div
key={index}
className="bg-gradient-to-br from-purple-50 to-blue-50 p-4 rounded-lg border border-purple-200"
@ -354,6 +369,21 @@ export default function MarketingPage() {
))}
</div>
</Card>
)}
</>
) : (
<Card className="p-6 mb-6">
<div className="text-center py-8">
<BarChart3 className="w-16 h-16 text-gray-300 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-gray-600 mb-2">
Données démographiques non disponibles
</h3>
<p className="text-gray-500">
Les informations sur le genre, l'âge et la ville des participants ne sont pas encore renseignées.
</p>
</div>
</Card>
)}
{/* Section Export */}
<Card className="p-6">
@ -385,8 +415,10 @@ export default function MarketingPage() {
</select>
</div>
{/* Filtres additionnels */}
{/* Filtres additionnels - Affichés uniquement si données disponibles */}
{(filteredCityData.length > 0 || filteredGenderData.length > 0) && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{filteredCityData.length > 0 && (
<div>
<label className="block text-sm text-gray-700 mb-1">Ville</label>
<select
@ -395,14 +427,16 @@ export default function MarketingPage() {
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
>
<option value="">Toutes les villes</option>
{stats.byCity.slice(0, 10).map((city) => (
{filteredCityData.slice(0, 10).map((city) => (
<option key={city.city} value={city.city}>
{city.city} ({city.count})
</option>
))}
</select>
</div>
)}
{filteredGenderData.length > 0 && (
<div>
<label className="block text-sm text-gray-700 mb-1">Genre</label>
<select
@ -411,14 +445,16 @@ export default function MarketingPage() {
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
>
<option value="">Tous les genres</option>
{stats.byGender.map((g) => (
{filteredGenderData.map((g) => (
<option key={g.gender} value={g.gender}>
{g.gender} ({g.count})
</option>
))}
</select>
</div>
)}
</div>
)}
{/* Boutons d'action */}
<div className="flex gap-3 pt-4">