/* ============================================================ KeS Metas — Painel (Dashboard) do usuário / equipe ============================================================ */ const { useState, useEffect } = React; const KESM_ = window.KESM; function fonteLabel(fonte) { if (fonte === "usuario") return { txt: "Preenchido por você", icon: "user" }; if (fonte === "admin") return { txt: "Preenchido pelo admin", icon: "lock" }; return { txt: "Automático · Google Agenda", icon: "calendarCheck" }; } /* ---- Cartão de META (topo) ---- */ function GoalCard({ rotulo, periodMeta, base }) { return (
Meta
{rotulo}
{periodMeta}
{base} · no período
); } /* ---- Cartão de INDICADOR (realizado x meta) ---- */ function MetricCard({ ind, data, canEdit, onEdit }) { const K = window.KES; const pct = Math.round(data.pct); const tone = window.tonePct(data.pct); const f = fonteLabel(ind.fonte); const valTxt = ind.tipo === "moeda" ? K.fmtMoeda(data.realizado) : K.fmtNum(data.realizado); const metaTxt = ind.tipo === "moeda" ? K.fmtMoeda(data.meta) : K.fmtNum(data.meta); return (
{ind.rotulo}
{ind.fonte === "auto" ? ( ) : canEdit ? ( ) : ( )}
{valTxt} / {metaTxt} {pct}%
{f.txt} {tone === "ok" ? "Meta batida" : tone === "warn" ? "Quase lá" : "Abaixo"}
); } /* ---- Modal: registrar atividade do dia ---- */ function RegisterModal({ subjectUser, editableKeys, state, dispatch, onClose }) { const K = window.KES; const todayISO = K.iso(K.SIM_TODAY); const [date, setDate] = useState(todayISO); const existing = state.activities.find((a) => a.userId === subjectUser.id && a.date === date) || {}; const [vals, setVals] = useState({}); // recarrega valores quando muda a data useEffect(() => { const ex = state.activities.find((a) => a.userId === subjectUser.id && a.date === date) || {}; const v = {}; editableKeys.forEach((k) => { v[k] = ex[k] != null ? ex[k] : ""; }); setVals(v); }, [date]); const labels = { ligacoes: "Ligações realizadas", conexoes: "Conexões feitas", reunioesRealizadas: "Reuniões realizadas", reunioesQualificadas: "Reuniões qualificadas", vendas: "Vendas realizadas", valorVendas: "Valor das vendas (R$)", }; function save() { const patch = {}; editableKeys.forEach((k) => { patch[k] = Math.max(0, parseInt(vals[k], 10) || 0); }); // // AQUI: integrar com backend/banco de dados (persistir atividade) dispatch({ type: "UPSERT_ACTIVITY", userId: subjectUser.id, date, patch }); onClose(`Atividade de ${K.fmtBR(date)} registrada.`); } return ( onClose()} footer={<> onClose()}>CancelarSalvar}>
{subjectUser.nome}
Lançamento diário de atividade
setDate(e.target.value)} />
{editableKeys.map((k) => ( setVals((s) => ({ ...s, [k]: e.target.value }))} /> ))}

"Reuniões Agendadas" é calculado automaticamente pelos agendamentos.

); } /* ---- Ranking / Competição da equipe (leaderboard por pessoa) ---- */ function RankingChart({ state, userIds, metricKey, period, hideNumbers, highlightId }) { const K = window.KES, KM = window.KESM; const usersById = {}; state.users.forEach((u) => { usersById[u.id] = u; }); const ind = KM.INDICADORES.find((i) => i.key === metricKey); const fmt = ind && ind.tipo === "moeda" ? K.fmtMoeda : K.fmtNum; const rows = userIds.map((uid) => { const m = KM.userMetrics(state, uid, period)[metricKey]; return { user: usersById[uid], val: m.realizado, pct: m.pct }; }).filter((r) => r.user).sort((a, b) => b.val - a.val); const max = Math.max(1, ...rows.map((r) => r.val)); return (
{rows.map((r, i) => { const tone = window.tonePct(r.pct); const me = r.user.id === highlightId; return (
{i === 0 ? : (i + 1) + "º"}
{r.user.nome} {me && Você} {!hideNumbers && {Math.round(r.pct)}%}
{!hideNumbers &&
{fmt(r.val)}
}
); })}
); } /* ---- Tela principal ---- */ function DashboardScreen({ state, dispatch, viewer, subject, extraActions }) { const K = window.KES, KM = window.KESM; const [chartKey, setChartKey] = useState("ligacoes"); const [chartMode, setChartMode] = useState("rank"); const [reg, setReg] = useState(false); const metrics = subject.isTeam ? KM.teamMetrics(state, subject.userIds, state.period) : KM.userMetrics(state, subject.user.id, state.period); // chaves que o viewer pode editar para este subject let editableKeys = []; if (!subject.isTeam) { if (viewer.papel === "admin") editableKeys = ["ligacoes", "conexoes", "reunioesRealizadas", "reunioesQualificadas", "vendas", "valorVendas"]; else if (subject.user.id === viewer.id) editableKeys = ["ligacoes", "conexoes"]; } const goalDefs = [ { key: "ligacoes", rotulo: "Meta de Ligações" }, { key: "reunioesRealizadas", rotulo: "Meta de Reuniões Realizadas" }, { key: "reunioesQualificadas", rotulo: "Meta de Reuniões Qualificadas" }, { key: "vendas", rotulo: "Meta de Vendas" }, ]; const baseTxt = (key) => { const m = state.metas[key]; return m.unidade === "dia" ? `${K.fmtNum(m.alvo)} / dia útil` : `${K.fmtNum(m.alvo)} / mês`; }; const chartTabs = [ ["ligacoes", "Ligações"], ["conexoes", "Conexões"], ["reunioesAgendadas", "Reuniões agend."], ["reunioesRealizadas", "Reuniões realiz."], ["reunioesQualificadas", "Reuniões qualif."], ["vendas", "Vendas"], ]; const chartLbl = (chartTabs.find(([k]) => k === chartKey) || ["", ""])[1]; const canRank = subject.isTeam || viewer.papel === "comum"; const effMode = canRank ? chartMode : "evo"; const rankIds = subject.isTeam ? subject.userIds : state.users.map((u) => u.id); const rankHideNumbers = !subject.isTeam; // usuário comum vê só posições const series = KM.dailySeries(state, subject.userIds, chartKey, state.period); const targetLine = KM.dailyTargetFor(state, chartKey, subject.userIds.length); const overall = Math.round(KM.overallPct(metrics)); const greeting = subject.isTeam ? "Visão da Equipe" : (subject.user.id === viewer.id ? `Olá, ${viewer.nome.split(" ")[0]}` : subject.user.nome); return (

{greeting}

{subject.isTeam ? `${subject.userIds.length} pessoas · ` : ""}Atingimento médio do período: {overall}%

{extraActions} dispatch({ type: "SET_PERIOD", period: p })} /> {!subject.isTeam && editableKeys.length > 0 && ( setReg(true)}>Registrar dia )}
{/* Metas */}
{goalDefs.map((g) => ( ))}
{/* Indicadores */}
Indicadores de realização
{KM.INDICADORES.map((ind) => ( setReg(ind.key)} /> ))}
{/* Gráfico */}
{effMode === "rank" ? "Competição da equipe" : "Evolução no período"}
{canRank ? (
) : (
Por dia útil
)}
{chartLbl}
{chartTabs.map(([k, lbl]) => ( ))}
{effMode === "rank" ? : } {effMode === "rank" && rankHideNumbers && (

Você vê apenas as posições da competição. Os números da equipe ficam visíveis só para administradores.

)}
{reg && !subject.isTeam && ( { setReg(false); if (msg) dispatch({ type: "TOAST", msg }); }} /> )}
); } window.DashboardScreen = DashboardScreen;