opencand.ui/src/components/StatisticsSection.tsx
José Henrique 98b104b573
Some checks failed
Frontend Build and Deploy / build (push) Failing after 11s
partido + melhorias
2025-05-31 20:45:39 -03:00

145 lines
4.7 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { openCandApi, type PlatformStats, ApiError } from '../api';
interface StatCardProps {
title: string;
value: string;
description: string;
isLoading?: boolean;
}
const StatCard: React.FC<StatCardProps> = ({ title, value, description, isLoading = false }) => {
return (
<div className="bg-gray-800/10 backdrop-blur-xs p-6 rounded-lg shadow-xl hover:shadow-indigo-500/30 transform hover:-translate-y-1 transition-all duration-300">
<h3 className="text-indigo-400 text-xl font-semibold mb-2">{title}</h3>
{isLoading ? (
<div className="h-12 flex items-center">
<div className="animate-spin rounded-full h-8 w-8 border-2 border-white border-t-transparent"></div>
</div>
) : (
<p className="text-4xl font-bold text-white mb-3">{value}</p>
)}
<p className="text-gray-400 text-sm">{description}</p>
</div>
);
};
const StatisticsSection: React.FC = () => {
const [stats, setStats] = useState<PlatformStats | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchStats = async () => {
try {
setIsLoading(true);
setError(null);
const platformStats = await openCandApi.getStats();
setStats(platformStats);
} catch (err) {
console.error('Error fetching platform stats:', err);
if (err instanceof ApiError) {
setError(`Erro ao carregar estatísticas: ${err.message}`);
} else {
setError('Erro inesperado ao carregar estatísticas');
}
// Use default stats as fallback
setStats({
totalCandidatos: 0,
totalBemCandidatos: 0,
totalEleicoes: 0,
totalValorBemCandidatos: 0,
totalRedesSociais: 0
});
} finally {
setIsLoading(false);
}
};
fetchStats();
}, []);
const formatNumber = (num: number): string => {
if (num >= 1000000000000) {
return `${(num / 1000000000000).toFixed(1)} trilhão`;
} else if (num >= 1000000000) {
return `${(num / 1000000000).toFixed(1)} bilhão`;
} else if (num >= 1000000) {
return `${(num / 1000000).toFixed(1)} milhão`;
} else if (num >= 1000) {
return `${(num / 1000).toFixed(0)}K`;
}
return num.toLocaleString('pt-BR');
};
const formatCurrency = (value: number): string => {
return new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL',
notation: 'compact',
maximumSignificantDigits: 3
}).format(value);
};
const statisticsData = [
{
title: "Total de Candidatos",
value: isLoading ? "" : `+${formatNumber(stats?.totalCandidatos || 0)}`,
description: "Registros de candidaturas na plataforma"
},
{
title: "Total de Bens Registrados",
value: isLoading ? "" : `+${formatNumber(stats?.totalBemCandidatos || 0)}`,
description: isLoading ? "" : `Somando ${formatCurrency(stats?.totalValorBemCandidatos || 0)} em Patrimônio agregado declarado pelos candidatos`
},
{
title: "Total de Redes Sociais",
value: isLoading ? "" : formatNumber(stats?.totalRedesSociais || 0),
description: "Redes sociais conectadas aos candidatos"
},
{
title: "Total de Eleições",
value: isLoading ? "" : formatNumber(stats?.totalEleicoes || 0),
description: "Eleições processadas no sistema"
}
];
return (
<section id="stats" className="py-20 bg-gray-800/30">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold text-center text-white mb-12">
Dados em Números
</h2>
<div className="flex flex-wrap justify-center gap-8 mx-auto">
{statisticsData.slice(0, 3).map((stat, index) => (
<div key={index} className="w-full md:w-80 lg:w-96">
<StatCard
title={stat.title}
value={stat.value}
description={stat.description}
isLoading={isLoading}
/>
</div>
))}
{statisticsData.length > 3 && (
<div className="w-full flex flex-wrap justify-center gap-8">
{statisticsData.slice(3).map((stat, index) => (
<div key={index + 3} className="w-full md:w-80 lg:w-96">
<StatCard
title={stat.title}
value={stat.value}
description={stat.description}
isLoading={isLoading}
/>
</div>
))}
</div>
)}
</div>
</div>
</section>
);
};
export default StatisticsSection;