/** * Admin Home Dashboard - Fast daily overview * 3 flows: BRL→USD, USD→BRL, USD→USD (balance) */ const { buildHeader, buildFooter, buildHead, getChartJsScript } = require('./ui-template'); function buildAdminHomeHTML(stats, user) { const now = new Date().toLocaleString('pt-BR'); const hoje = new Date().toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long' }); // Support both admin and corporate roles const role = user.role || 'corporate'; const formatBRL = (v) => v.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); const formatUSD = (v) => v.toLocaleString('pt-BR', { style: 'currency', currency: 'USD' }); // Calculate variations const calcVar = (hoje, ontem) => ontem > 0 ? ((hoje - ontem) / ontem * 100).toFixed(1) : (hoje > 0 ? 100 : 0); const brlUsdVar = calcVar(stats.brlUsd.hoje.qtd, stats.brlUsd.ontem.qtd); const usdBrlVar = calcVar(stats.usdBrl.hoje.qtd, stats.usdBrl.ontem.qtd); const usdUsdVar = calcVar(stats.usdUsd.hoje.qtd, stats.usdUsd.ontem.qtd); const totalHoje = stats.brlUsd.hoje.qtd + stats.usdBrl.hoje.qtd + stats.usdUsd.hoje.qtd; const totalOntem = stats.brlUsd.ontem.qtd + stats.usdBrl.ontem.qtd + stats.usdUsd.ontem.qtd; const totalVar = calcVar(totalHoje, totalOntem); const pageScripts = getChartJsScript(); const pageCSS = ` /* Trading Terminal - Live Rates */ .trading-terminal { background: linear-gradient(135deg, #0F1923 0%, #1A2332 50%, #0D1B2A 100%); border-top: 1px solid rgba(0,255,136,0.15); border-bottom: 1px solid rgba(0,255,136,0.15); padding: 16px 40px; position: relative; overflow: hidden; } .trading-terminal::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, rgba(0,255,136,0.3), transparent); } .trading-terminal::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, rgba(0,255,136,0.3), transparent); } .live-rate-bar { display: flex; align-items: center; justify-content: center; gap: 20px; max-width: 1600px; margin: 0 auto; } .terminal-title { font-size: 10px; font-weight: 700; color: rgba(0,255,136,0.6); text-transform: uppercase; letter-spacing: 2px; margin-right: 8px; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; } .live-rate-dot { width: 7px; height: 7px; border-radius: 50%; background: #00FF88; display: inline-block; animation: blink 1.5s infinite; box-shadow: 0 0 6px rgba(0,255,136,0.6); } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } } .rate-pair-group { display: flex; align-items: center; gap: 8px; background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06); border-radius: 8px; padding: 8px 14px; } .rate-pair-label { font-size: 11px; font-weight: 800; color: rgba(255,255,255,0.35); text-transform: uppercase; letter-spacing: 1px; writing-mode: vertical-rl; text-orientation: mixed; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; } .live-rate-btn { display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 8px 18px; border-radius: 6px; border: 1px solid transparent; font-family: inherit; font-size: 14px; font-weight: 700; cursor: default; transition: all 0.25s; min-width: 150px; justify-content: center; position: relative; } .rate-flags { font-size: 9px; opacity: 0.5; letter-spacing: 1px; line-height: 1; } .live-rate-btn.compra { background: rgba(0,255,136,0.08); color: #00FF88; border-color: rgba(0,255,136,0.2); } .live-rate-btn.compra:hover { background: rgba(0,255,136,0.14); } .live-rate-btn.venda { background: rgba(255,68,68,0.08); color: #FF4444; border-color: rgba(255,68,68,0.2); } .live-rate-btn.venda:hover { background: rgba(255,68,68,0.14); } .live-rate-btn .rate-value { font-size: 22px; font-weight: 800; letter-spacing: -0.5px; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-variant-numeric: tabular-nums; text-shadow: 0 0 12px currentColor; } .live-rate-btn .rate-type { font-size: 9px; text-transform: uppercase; letter-spacing: 1.5px; opacity: 0.5; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; } .live-rate-btn.pulse .rate-value { animation: ratePulse 0.4s ease; } @keyframes ratePulse { 0% { transform: scale(1); text-shadow: 0 0 12px currentColor; } 50% { transform: scale(1.06); text-shadow: 0 0 24px currentColor, 0 0 48px currentColor; } 100% { transform: scale(1); text-shadow: 0 0 12px currentColor; } } .live-rate-time { font-size: 10px; color: rgba(255,255,255,0.25); font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; letter-spacing: 0.5px; } .date-banner { background: var(--card); border-radius: 12px; padding: 16px 24px; margin-bottom: 24px; border: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; } .date-banner h2 { font-size: 18px; font-weight: 700; text-transform: capitalize; } .date-banner .time { font-size: 13px; color: var(--text-secondary); } .kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 28px; } .kpi-card { background: var(--card); border-radius: 16px; padding: 24px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04); } .kpi-card.highlight { border-left: 4px solid var(--admin-accent); } .kpi-card.brl-usd { border-left: 4px solid var(--blue); } .kpi-card.usd-brl { border-left: 4px solid var(--green); } .kpi-card.usd-usd { border-left: 4px solid var(--purple); } .kpi-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; } .kpi-label { font-size: 12px; font-weight: 600; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.3px; } .kpi-badge { font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 12px; } .kpi-badge.up { background: var(--green-bg); color: var(--green); } .kpi-badge.down { background: var(--red-bg); color: var(--red); } .kpi-badge.neutral { background: var(--blue-bg); color: var(--blue); } .kpi-value { font-size: 36px; font-weight: 800; color: var(--text); margin-bottom: 4px; } .kpi-sub { font-size: 13px; color: var(--text-muted); } .charts-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-bottom: 28px; } .chart-card { background: var(--card); border-radius: 16px; padding: 24px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04); } .chart-card h3 { font-size: 14px; font-weight: 700; margin-bottom: 20px; color: var(--text); } .chart-wrap { height: 280px; position: relative; } .detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; } .detail-card { background: var(--card); border-radius: 16px; padding: 24px; border: 1px solid var(--border); } .detail-card h3 { font-size: 14px; font-weight: 700; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } .detail-card h3 .icon { width: 28px; height: 28px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 14px; } .detail-card h3 .icon.out { background: var(--blue-bg); } .detail-card h3 .icon.in { background: var(--green-bg); } .detail-card h3 .icon.balance { background: var(--purple-bg); } .detail-row { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #F3F4F6; font-size: 13px; } .detail-row:last-child { border-bottom: none; } .detail-label { color: var(--text-secondary); } .detail-value { font-weight: 600; color: var(--text); } .detail-value.green { color: var(--green); } .detail-value.red { color: var(--red); } @media (max-width: 1200px) { .kpi-grid { grid-template-columns: repeat(2, 1fr); } .detail-grid { grid-template-columns: 1fr; } } @media (max-width: 768px) { .trading-terminal { padding: 12px 16px; } .live-rate-bar { flex-wrap: wrap; gap: 10px; justify-content: center; } .terminal-title { display: none; } .rate-pair-group { padding: 8px 12px; width: 100%; justify-content: center; } .live-rate-btn { min-width: 120px; padding: 8px 14px; flex: 1; } .live-rate-btn .rate-value { font-size: 18px; } .live-rate-time { width: 100%; text-align: center; } .kpi-grid, .charts-grid { grid-template-columns: 1fr; } .date-banner { flex-direction: column; gap: 8px; text-align: center; padding: 14px 16px; } .date-banner h2 { font-size: 16px; } .date-banner .time { font-size: 12px; } .kpi-card { padding: 16px; } .kpi-value { font-size: 28px; } .kpi-label { font-size: 11px; } .kpi-sub { font-size: 12px; } .kpi-badge { font-size: 10px; padding: 3px 8px; } .chart-card { padding: 16px; } .chart-card h3 { font-size: 13px; margin-bottom: 14px; } .chart-wrap { height: 220px; } .detail-card { padding: 16px; } .detail-card h3 { font-size: 13px; } .detail-row { font-size: 12px; padding: 8px 0; } } @media (max-width: 480px) { .trading-terminal { padding: 10px 12px; } .live-rate-bar { gap: 8px; flex-direction: column; align-items: center; } .rate-pair-group { padding: 10px; gap: 6px; } .rate-pair-label { writing-mode: horizontal-tb; font-size: 10px; } .live-rate-btn { min-width: 110px; padding: 8px 12px; } .live-rate-btn .rate-value { font-size: 16px; } .live-rate-btn .rate-type { font-size: 8px; } .rate-flags { font-size: 9px; } .live-rate-time { font-size: 9px; } .kpi-value { font-size: 24px; } .chart-wrap { height: 180px; } .detail-card h3 .icon { width: 24px; height: 24px; font-size: 12px; } .detail-row { font-size: 11px; } } `; return ` ${buildHead('Home', pageCSS, pageScripts)} ${buildHeader({ role: role, userName: user.nome, activePage: 'home' })}
Live Rates
USD
--

${hoje}

Atualizado: ${now}
Total de Ordens Hoje
${Number(totalVar) >= 0 ? '+' : ''}${totalVar}%
${totalHoje}
Ontem: ${totalOntem} ordens
BRL → USD
${Number(brlUsdVar) >= 0 ? '+' : ''}${brlUsdVar}%
${stats.brlUsd.hoje.qtd}
Ontem: ${stats.brlUsd.ontem.qtd}
USD → BRL
${Number(usdBrlVar) >= 0 ? '+' : ''}${usdBrlVar}%
${stats.usdBrl.hoje.qtd}
Ontem: ${stats.usdBrl.ontem.qtd}
USD → USD (Balance)
${Number(usdUsdVar) >= 0 ? '+' : ''}${usdUsdVar}%
${stats.usdUsd.hoje.qtd}
Ontem: ${stats.usdUsd.ontem.qtd}

Quantidade de Ordens por Fluxo

Volume USD por Fluxo

BRL → USD (Remessas)

Ordens Hoje ${stats.brlUsd.hoje.qtd}
Ordens Ontem ${stats.brlUsd.ontem.qtd}
Volume BRL Hoje ${formatBRL(stats.brlUsd.hoje.total_brl)}
Volume USD Hoje ${formatUSD(stats.brlUsd.hoje.total_usd)}
Variacao ${Number(brlUsdVar) >= 0 ? '+' : ''}${brlUsdVar}%

USD → BRL (Recebimentos)

Ordens Hoje ${stats.usdBrl.hoje.qtd}
Ordens Ontem ${stats.usdBrl.ontem.qtd}
Volume BRL Hoje ${formatBRL(stats.usdBrl.hoje.total_brl)}
Volume USD Hoje ${formatUSD(stats.usdBrl.hoje.total_usd)}
Variacao ${Number(usdBrlVar) >= 0 ? '+' : ''}${usdBrlVar}%

USD → USD (Balance)

Ordens Hoje ${stats.usdUsd.hoje.qtd}
Ordens Ontem ${stats.usdUsd.ontem.qtd}
Volume USD Hoje ${formatUSD(stats.usdUsd.hoje.total_usd)}
Volume USD Ontem ${formatUSD(stats.usdUsd.ontem.total_usd)}
Variacao ${Number(usdUsdVar) >= 0 ? '+' : ''}${usdUsdVar}%
${buildFooter()} `; } module.exports = { buildAdminHomeHTML };