|
| 1 | +import { useEffect, useState } from "react"; |
| 2 | +import { useNavigate } from "react-router-dom"; |
| 3 | +import { getUsuarioLogado, getToken } from "../services/authService"; |
| 4 | +import { getClientes } from "../services/clientesService"; |
| 5 | +import { getCarteira } from "../services/EmprestimosService"; |
| 6 | + |
| 7 | +const acoes = [ |
| 8 | + { icon: "👥", label: "Clientes", path: "/clientes", desc: "Gerenciar devedores" }, |
| 9 | + { icon: "💳", label: "Empréstimos", path: "/emprestimos", desc: "Controle de empréstimos" }, |
| 10 | + { icon: "📈", label: "Relatórios", path: "/relatorios", desc: "Visualizar relatórios" }, |
| 11 | + { icon: "⚙️", label: "Configurações", path: "/configuracoes", desc: "Ajustes do sistema" }, |
| 12 | +]; |
| 13 | + |
| 14 | +function calcularStatus(e) { |
| 15 | + if (e.pago) return "pago"; |
| 16 | + const diff = Math.ceil((new Date(e.dataVencimento) - new Date()) / 86400000); |
| 17 | + return diff < 0 ? "atraso" : "emDia"; |
| 18 | +} |
| 19 | + |
| 20 | +export default function Dashboard() { |
| 21 | + const navigate = useNavigate(); |
| 22 | + const usuario = getUsuarioLogado(); |
| 23 | + const cobrador = usuario?.nome ?? ""; |
| 24 | + const nome = cobrador.split(" ")[0] || "Usuário"; |
| 25 | + |
| 26 | + const [hora, setHora] = useState(""); |
| 27 | + const [stats, setStats] = useState({ clientes: "—", emprestimos: "—", emDia: "—", atraso: "—" }); |
| 28 | + const [carregando, setCarregando] = useState(true); |
| 29 | + |
| 30 | + useEffect(() => { |
| 31 | + const h = new Date().getHours(); |
| 32 | + if (h < 12) setHora("Bom dia"); |
| 33 | + else if (h < 18) setHora("Boa tarde"); |
| 34 | + else setHora("Boa noite"); |
| 35 | + }, []); |
| 36 | + |
| 37 | + useEffect(() => { |
| 38 | + if (!cobrador) return; |
| 39 | + async function carregarStats() { |
| 40 | + try { |
| 41 | + const [clientes, carteira] = await Promise.all([ |
| 42 | + getClientes(getToken()), |
| 43 | + getCarteira(cobrador), |
| 44 | + ]); |
| 45 | + |
| 46 | + const totalClientes = Array.isArray(clientes) ? clientes.length : 0; |
| 47 | + const listaCarteira = Array.isArray(carteira) ? carteira : []; |
| 48 | + const totalEmprestimos = listaCarteira.length; |
| 49 | + const emDia = listaCarteira.filter((e) => calcularStatus(e) === "emDia").length; |
| 50 | + const atraso = listaCarteira.filter((e) => calcularStatus(e) === "atraso").length; |
| 51 | + |
| 52 | + setStats({ clientes: totalClientes, emprestimos: totalEmprestimos, emDia, atraso }); |
| 53 | + } catch { |
| 54 | + // mantém "—" se falhar |
| 55 | + } finally { |
| 56 | + setCarregando(false); |
| 57 | + } |
| 58 | + } |
| 59 | + carregarStats(); |
| 60 | + }, [cobrador]); |
| 61 | + |
| 62 | + return ( |
| 63 | + <div style={s.page}> |
| 64 | + <div style={s.header}> |
| 65 | + <div> |
| 66 | + <p style={s.saudacao}>{hora}, {nome} 👋</p> |
| 67 | + <h1 style={s.titulo}>Painel</h1> |
| 68 | + </div> |
| 69 | + </div> |
| 70 | + |
| 71 | + <div style={s.statsGrid}> |
| 72 | + <CardResumo icon="👥" label="Clientes" valor={carregando ? "..." : stats.clientes} cor="#7C3AED" /> |
| 73 | + <CardResumo icon="💳" label="Empréstimos" valor={carregando ? "..." : stats.emprestimos} cor="#2563EB" /> |
| 74 | + <CardResumo icon="✅" label="Em dia" valor={carregando ? "..." : stats.emDia} cor="#16A34A" /> |
| 75 | + <CardResumo icon="⚠️" label="Em atraso" valor={carregando ? "..." : stats.atraso} cor="#DC2626" /> |
| 76 | + </div> |
| 77 | + |
| 78 | + <h2 style={s.secaoTitulo}>Acesso rápido</h2> |
| 79 | + <div style={s.acoesGrid}> |
| 80 | + {acoes.map((a) => ( |
| 81 | + <button key={a.path} style={s.card} onClick={() => navigate(a.path)}> |
| 82 | + <span style={s.cardIcon}>{a.icon}</span> |
| 83 | + <span style={s.cardLabel}>{a.label}</span> |
| 84 | + <span style={s.cardDesc}>{a.desc}</span> |
| 85 | + </button> |
| 86 | + ))} |
| 87 | + </div> |
| 88 | + </div> |
| 89 | + ); |
| 90 | +} |
| 91 | + |
| 92 | +function CardResumo({ icon, label, valor, cor }) { |
| 93 | + return ( |
| 94 | + <div style={{ ...s.statCard, borderTop: `4px solid ${cor}` }}> |
| 95 | + <span style={{ ...s.statIcon, color: cor }}>{icon}</span> |
| 96 | + <div> |
| 97 | + <p style={s.statValor}>{valor}</p> |
| 98 | + <p style={s.statLabel}>{label}</p> |
| 99 | + </div> |
| 100 | + </div> |
| 101 | + ); |
| 102 | +} |
| 103 | + |
| 104 | +const s = { |
| 105 | + page: { padding: "2rem", background: "#F5F3FF", minHeight: "100vh" }, |
| 106 | + header: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "2rem" }, |
| 107 | + saudacao: { margin: 0, fontSize: "0.95rem", color: "#6B7280" }, |
| 108 | + titulo: { margin: "0.25rem 0 0", fontSize: "1.8rem", fontWeight: 700, color: "#1F2937" }, |
| 109 | + statsGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: "1rem", marginBottom: "2rem" }, |
| 110 | + statCard: { background: "#fff", borderRadius: "12px", padding: "1.25rem", display: "flex", alignItems: "center", gap: "1rem", boxShadow: "0 1px 4px rgba(0,0,0,0.07)" }, |
| 111 | + statIcon: { fontSize: "2rem" }, |
| 112 | + statValor: { margin: 0, fontSize: "1.5rem", fontWeight: 700, color: "#1F2937" }, |
| 113 | + statLabel: { margin: 0, fontSize: "0.8rem", color: "#6B7280" }, |
| 114 | + secaoTitulo:{ fontSize: "1.1rem", fontWeight: 600, color: "#374151", marginBottom: "1rem" }, |
| 115 | + acoesGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "1rem" }, |
| 116 | + card: { background: "#fff", border: "none", borderRadius: "12px", padding: "1.5rem", display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "0.4rem", cursor: "pointer", boxShadow: "0 1px 4px rgba(0,0,0,0.07)", textAlign: "left" }, |
| 117 | + cardIcon: { fontSize: "1.8rem" }, |
| 118 | + cardLabel: { fontWeight: 600, fontSize: "1rem", color: "#1F2937" }, |
| 119 | + cardDesc: { fontSize: "0.8rem", color: "#6B7280" }, |
| 120 | +}; |
0 commit comments