rinogeek's picture
Update for deployment
62fe6d4
/**
* Composants de graphiques pour AfriDataHub
* Created by BlackBenAI Team - AfriDataHub Platform
*/
import {
BarChart,
Bar,
LineChart,
Line,
PieChart,
Pie,
Cell,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer
} from 'recharts'
// Palette de couleurs AfriDataHub
const COLORS = {
primary: '#7c3aed', // violet
secondary: '#ec4899', // rose
success: '#10b981', // vert
warning: '#f59e0b', // orange
info: '#3b82f6', // bleu
danger: '#ef4444', // rouge
gray: '#6b7280' // gris
}
const CHART_COLORS = [
COLORS.primary,
COLORS.secondary,
COLORS.success,
COLORS.warning,
COLORS.info,
COLORS.danger,
'#8b5cf6',
'#f472b6',
'#34d399',
'#fbbf24'
]
// Composant Tooltip personnalisé
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
<div className="bg-card p-3 border border-border rounded-xl shadow-2xl">
<p className="font-bold text-foreground mb-1">{label}</p>
{payload.map((entry, index) => (
<p key={index} style={{ color: entry.color }} className="text-xs font-black">
{entry.name}: {entry.value?.toLocaleString()}
</p>
))}
</div>
)
}
return null
}
// Graphique en barres pour les données par pays
export const CountryBarChart = ({ data, title, dataKey, xAxisKey = 'country' }) => {
return (
<div className="bg-card rounded-[2rem] border border-border p-6 shadow-lg">
<h3 className="text-lg font-black text-foreground mb-6 uppercase tracking-widest">{title}</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="currentColor" opacity={0.1} vertical={false} />
<XAxis
dataKey={xAxisKey}
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<YAxis
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<Tooltip content={<CustomTooltip />} />
<Bar
dataKey={dataKey}
fill="var(--primary)"
radius={[6, 6, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
</div>
)
}
// Graphique en ligne pour les tendances temporelles
export const TrendLineChart = ({ data, title, lines = [] }) => {
return (
<div className="bg-card rounded-[2rem] border border-border p-6 shadow-lg">
<h3 className="text-lg font-black text-foreground mb-6 uppercase tracking-widest">{title}</h3>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="currentColor" opacity={0.1} />
<XAxis
dataKey="date"
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<YAxis
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<Tooltip content={<CustomTooltip />} />
<Legend wrapperStyle={{ paddingTop: '20px', fontWeight: 'bold', fontSize: '12px' }} />
{lines.map((line, index) => (
<Line
key={line.dataKey}
type="monotone"
dataKey={line.dataKey}
stroke={CHART_COLORS[index % CHART_COLORS.length]}
strokeWidth={3}
dot={{ r: 4, strokeWidth: 2, fill: 'var(--card)' }}
activeDot={{ r: 6, strokeWidth: 0 }}
name={line.name}
/>
))}
</LineChart>
</ResponsiveContainer>
</div>
)
}
// Graphique en secteurs pour la répartition
export const DomainPieChart = ({ data, title }) => {
return (
<div className="bg-card rounded-[2rem] border border-border p-6 shadow-lg">
<h3 className="text-lg font-black text-foreground mb-6 uppercase tracking-widest">{title}</h3>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
outerRadius={80}
stroke="var(--card)"
strokeWidth={2}
fill="#8884d8"
dataKey="value"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={CHART_COLORS[index % CHART_COLORS.length]} />
))}
</Pie>
<Tooltip content={<CustomTooltip />} />
</PieChart>
</ResponsiveContainer>
</div>
)
}
// Graphique de comparaison multi-barres
export const ComparisonBarChart = ({ data, title, bars = [] }) => {
return (
<div className="bg-card rounded-[2rem] border border-border p-6 shadow-lg">
<h3 className="text-lg font-black text-foreground mb-6 uppercase tracking-widest">{title}</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="currentColor" opacity={0.1} />
<XAxis
dataKey="name"
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<YAxis
tick={{ fontSize: 10, fill: 'currentColor', opacity: 0.6, fontWeight: 'bold' }}
axisLine={{ stroke: 'currentColor', opacity: 0.2 }}
/>
<Tooltip content={<CustomTooltip />} />
<Legend wrapperStyle={{ paddingTop: '20px', fontWeight: 'bold', fontSize: '12px' }} />
{bars.map((bar, index) => (
<Bar
key={bar.dataKey}
dataKey={bar.dataKey}
fill={CHART_COLORS[index % CHART_COLORS.length]}
name={bar.name}
radius={[4, 4, 0, 0]}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
)
}
// Graphique de métriques avec indicateurs
export const MetricsChart = ({ data, title, metric }) => {
const formatValue = (value) => {
if (value >= 1000000) {
return `${(value / 1000000).toFixed(1)}M`
} else if (value >= 1000) {
return `${(value / 1000).toFixed(1)}K`
}
return value.toString()
}
return (
<div className="bg-card rounded-[2rem] border border-border p-6 shadow-lg">
<h3 className="text-lg font-black text-foreground mb-6 uppercase tracking-widest">{title}</h3>
<div className="space-y-4">
{data.map((item, index) => (
<div key={index} className="flex items-center justify-between p-3 rounded-2xl hover:bg-muted/50 transition-colors">
<div className="flex items-center">
<div
className="w-4 h-4 rounded mr-3"
style={{ backgroundColor: CHART_COLORS[index % CHART_COLORS.length] }}
/>
<span className="text-sm font-bold text-foreground/80">{item.name}</span>
</div>
<div className="flex items-center">
<span className="text-lg font-black text-foreground mr-3">
{formatValue(item[metric])}
</span>
{item.change && (
<span className={`text-[10px] px-3 py-1 rounded-full font-black ${item.change > 0
? 'bg-emerald-500/10 text-emerald-500'
: 'bg-red-500/10 text-red-500'
}`}>
{item.change > 0 ? '+' : ''}{item.change}%
</span>
)}
</div>
</div>
))}
</div>
</div>
)
}
export default {
CountryBarChart,
TrendLineChart,
DomainPieChart,
ComparisonBarChart,
MetricsChart
}