feat: add CountryHistogram and AnalyticsMap components and update build script to use legacy-peer-deps

This commit is contained in:
2026-05-10 22:01:03 +02:00
parent 197594f84f
commit 1b47498f6e
3 changed files with 72 additions and 49 deletions

View File

@@ -60,6 +60,12 @@ const countryToISO: Record<string, string> = {
};
export default function AnalyticsMap({ data, title }: AnalyticsMapProps) {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
const maxCount = useMemo(() => {
if (data.length === 0) return 1;
return Math.max(...data.map((d) => d.count));
@@ -132,53 +138,60 @@ export default function AnalyticsMap({ data, title }: AnalyticsMapProps) {
</div>
</div>
<div className="p-4 flex justify-center bg-slate-950/20 h-[600px]">
<ComposableMap
projectionConfig={{
rotate: [-10, 0, 0],
scale: 147
}}
width={800}
height={600}
style={{ width: "100%", height: "100%" }}
>
<ZoomableGroup
zoom={position.zoom}
center={position.coordinates as [number, number]}
onMoveEnd={handleMoveEnd}
<div className="p-4 flex justify-center bg-slate-950/20 h-[600px] items-center">
{!mounted ? (
<div className="flex flex-col items-center gap-4 animate-pulse">
<div className="w-16 h-16 border-4 border-indigo-500/20 border-t-indigo-500 rounded-full animate-spin"></div>
<p className="text-slate-500 text-xs font-bold uppercase tracking-widest">Chargement de la carte...</p>
</div>
) : (
<ComposableMap
projectionConfig={{
rotate: [-10, 0, 0],
scale: 147
}}
width={800}
height={600}
style={{ width: "100%", height: "100%" }}
>
<Sphere stroke="#334155" strokeWidth={0.5} id="sphere" fill="transparent" />
<Graticule stroke="#334155" strokeWidth={0.5} />
{data.length > 0 && (
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => {
const countryName = geo.properties.name;
const countryId = geo.id;
const countryISO = geo.properties.iso_a3;
const count = mappedData[countryName] || mappedData[countryISO] || mappedData[countryId] || 0;
return (
<Geography
key={geo.rsmKey}
geography={geo}
fill={count > 0 ? colorScale(count) : "#0f172a"}
stroke="#1e293b"
strokeWidth={0.5}
style={{
default: { outline: "none" },
hover: { fill: "#4f46e5", outline: "none", cursor: "pointer" },
pressed: { outline: "none" }
}}
/>
);
})
}
</Geographies>
)}
</ZoomableGroup>
</ComposableMap>
<ZoomableGroup
zoom={position.zoom}
center={position.coordinates as [number, number]}
onMoveEnd={handleMoveEnd}
>
<Sphere stroke="#334155" strokeWidth={0.5} id="sphere" fill="transparent" />
<Graticule stroke="#334155" strokeWidth={0.5} />
{data.length > 0 && (
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map((geo) => {
const countryName = geo.properties.name;
const countryId = geo.id;
const countryISO = geo.properties.iso_a3;
const count = mappedData[countryName] || mappedData[countryISO] || mappedData[countryId] || 0;
return (
<Geography
key={geo.rsmKey}
geography={geo}
fill={count > 0 ? colorScale(count) : "#0f172a"}
stroke="#1e293b"
strokeWidth={0.5}
style={{
default: { outline: "none" },
hover: { fill: "#4f46e5", outline: "none", cursor: "pointer" },
pressed: { outline: "none" }
}}
/>
);
})
}
</Geographies>
)}
</ZoomableGroup>
</ComposableMap>
)}
</div>
{/* Legend / Instructions */}

View File

@@ -19,6 +19,12 @@ interface CountryHistogramProps {
}
export default function CountryHistogram({ data, title }: CountryHistogramProps) {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
// Take top 10 for readability
const chartData = data.slice(0, 10).map(item => ({
name: item.country || 'Inconnu',
@@ -32,8 +38,11 @@ export default function CountryHistogram({ data, title }: CountryHistogramProps)
{title}
</h2>
<div className="h-[400px] w-full">
<ResponsiveContainer width="100%" height="100%">
<div className="h-[400px] w-full flex items-center justify-center">
{!mounted ? (
<p className="text-slate-500 text-xs font-bold uppercase tracking-widest animate-pulse">Chargement du graphique...</p>
) : (
<ResponsiveContainer width="100%" height="100%">
<BarChart
data={chartData}
margin={{
@@ -91,6 +100,7 @@ export default function CountryHistogram({ data, title }: CountryHistogramProps)
/>
</BarChart>
</ResponsiveContainer>
)}
</div>
</div>
);