import React, { useMemo } from 'react'; import { Users, DollarSign, TrendingUp, Megaphone, Calendar, ChevronRight, ArrowUpRight, ArrowDownRight, Plus, Clock, ArrowRight } from 'lucide-react'; import { PageHeader } from '../components/PageHeader.tsx'; import { useHybridBackend } from '../hooks/useHybridBackend.ts'; import { HybridBackend } from '../services/backend.ts'; import { NotificationCenter } from '../components/NotificationCenter.tsx'; const StatCard: React.FC<{ title: string; value: string | number; icon: React.ReactNode; trend?: string; isPositive?: boolean; color: 'blue' | 'green' | 'purple' | 'amber'; onClick?: () => void; }> = ({ title, value, icon, trend, isPositive, color, onClick }) => { const bgLight = { blue: 'bg-blue-50 text-blue-600', green: 'bg-emerald-50 text-emerald-600', purple: 'bg-indigo-50 text-indigo-600', amber: 'bg-amber-50 text-amber-600' }; return (
{icon}

{title}

{value}

{trend && (
{isPositive ? : }
{trend}
)}
); }; export const Dashboard: React.FC = () => { const { data, isLoading } = useHybridBackend(HybridBackend.getDashboardStats); const growthData = useMemo(() => { if (!data?.growth || data.growth.length === 0) { return Array(6).fill(null).map((_, i) => ({ label: `MÊS ${i + 1}`, receita: 0, despesa: 0, heightP: '0%', heightR: '0%' })); } const maxVal = Math.max(...data.growth.map((g: any) => Math.max(parseFloat(g.receita), parseFloat(g.despesa))), 1000); return data.growth.map((g: any) => { const [year, month] = g.mes.split('-'); const date = new Date(parseInt(year), parseInt(month) - 1); const label = date.toLocaleString('pt-BR', { month: 'short' }).toUpperCase(); return { label, receita: parseFloat(g.receita), despesa: parseFloat(g.despesa), // Proporção para o gráfico heightR: `${(parseFloat(g.receita) / maxVal) * 100}%`, heightD: `${(parseFloat(g.despesa) / maxVal) * 100}%` }; }).slice(-6); // Garantir últimos 6 }, [data]); const currentRole = HybridBackend.getCurrentRole(); const showFinancials = ['admin', 'donoclinica', 'funcionario'].includes(currentRole); if (isLoading) { return (
); } const stats = data?.stats || { totalPacientes: 0, totalAgendamentos: 0, totalLeads: 0, faturamentoTotal: 0, despesasTotal: 0 }; const recent = data?.recentAgendamentos || []; return (
{(currentRole === 'admin' || currentRole === 'donoclinica' || currentRole === 'funcionario') && ( )}
{/* Stats Grid */}
} trend="+12% este mês" isPositive={true} color="blue" onClick={() => window.location.hash = '#/pacientes'} /> {showFinancials && ( } trend="+5.4% vs mês ant." isPositive={true} color="green" onClick={() => window.location.hash = '#/financeiro'} /> )} } trend="82% de ocupação" isPositive={true} color="purple" onClick={() => window.location.hash = '#/agenda'} /> {showFinancials && ( } trend="-2% vs ontem" isPositive={false} color="amber" onClick={() => window.location.hash = '#/leads'} /> )}
{/* Growth Chart Area */} {showFinancials && (

Crescimento Mensal

Receitas vs Despesas Reais

{growthData.map((d: any, i: number) => (
{/* Barra Despesa */}
{/* Barra Receita */}
{d.label}
))}
Receitas
Despesas
)} {/* Recent Activity */}

Últimos Agendamentos

{recent.length > 0 ? recent.map((app: any) => (
window.location.hash = '#/agenda'} className="flex items-center gap-4 group cursor-pointer" >
{app.pacienteNome || 'Paciente'}
{app.dentistaNome || 'Dr. Dentista'} • {new Date(app.start_time).toLocaleDateString('pt-BR')} {new Date(app.start_time).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}
)) : (

Nenhum agendamento recente.

)}
); };