feat: add total revenue card to dashboard metrics
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 55s Details

This commit is contained in:
Sidney Gomes 2026-07-22 20:16:33 -03:00
parent 7599b6bc2e
commit 64a78495d9
2 changed files with 23 additions and 2 deletions

View File

@ -793,6 +793,11 @@ app.get('/api/admin/dashboard', authenticateToken, requireAdmin, (req: Authentic
} }
} }
// Total Revenue Calculation
const totalRevenue = db.payments
.filter(p => p.status === 'CONFIRMED' || p.status === 'RECEIVED')
.reduce((sum, p) => sum + p.value, 0);
// Generate Revenue Data for Charts (Last 30 Days) // Generate Revenue Data for Charts (Last 30 Days)
const thirtyDaysAgo = new Date(); const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
@ -858,6 +863,7 @@ app.get('/api/admin/dashboard', authenticateToken, requireAdmin, (req: Authentic
res.json({ res.json({
stats: { stats: {
mrr, mrr,
totalRevenue,
activeSubscribers: totalActive, activeSubscribers: totalActive,
trialSubscribers: totalTrial, trialSubscribers: totalTrial,
overdueSubscribers: totalOverdue, overdueSubscribers: totalOverdue,

View File

@ -48,6 +48,7 @@ interface PaymentLog {
interface DashboardStats { interface DashboardStats {
mrr: number; mrr: number;
totalRevenue: number;
activeSubscribers: number; activeSubscribers: number;
trialSubscribers: number; trialSubscribers: number;
overdueSubscribers: number; overdueSubscribers: number;
@ -340,8 +341,22 @@ export default function AdminDashboard({ token }: AdminDashboardProps) {
</button> </button>
</div> </div>
{/* METRICS ROW (MRR, Actives, Overdue, Cancelled) */} {/* METRICS ROW (Total, MRR, Actives, Overdue, Cancelled) */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-6">
{/* Total Revenue Card */}
<div className="glass-card p-6 rounded-2xl flex items-center justify-between">
<div className="space-y-1">
<p className="text-xs text-zinc-500 font-bold uppercase tracking-wider">Faturamento Total</p>
<p className="text-2xl md:text-3xl font-display font-black text-emerald-500 tracking-tight">
R$ {stats.totalRevenue ? stats.totalRevenue.toLocaleString('pt-BR', { minimumFractionDigits: 2 }) : '0,00'}
</p>
<p className="text-[10px] text-zinc-400 font-medium">Soma de todos os pagamentos</p>
</div>
<div className="bg-emerald-500/10 text-emerald-500 p-3 rounded-xl border border-emerald-500/20">
<DollarSign className="w-6 h-6" />
</div>
</div>
{/* MRR Card */} {/* MRR Card */}
<div className="glass-card p-6 rounded-2xl flex items-center justify-between"> <div className="glass-card p-6 rounded-2xl flex items-center justify-between">