doli-front/src/components/dashboard.js

271 lines
7.4 KiB
JavaScript

import { renderInvoiceStatusChart } from './charts/InvoiceStatusChart.js';
import { renderBarChart } from './charts/BarChart.js';
// Configuración de las tarjetas de estadísticas
const statsConfig = [
{
id: 'totalFacturado',
title: 'Total Facturado',
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
<line x1="8" y1="21" x2="16" y2="21"></line>
<line x1="12" y1="17" x2="12" y2="21"></line>
</svg>`,
iconBg: '#374151',
valueColor: '#1f2937',
subtitle: 'Este mes',
formatValue: (val) => `${val.toLocaleString('es-ES', { minimumFractionDigits: 2 })} €`
},
{
id: 'facturasEmitidas',
title: 'Facturas Emitidas',
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="12" y1="18" x2="12" y2="12"></line>
<line x1="9" y1="15" x2="15" y2="15"></line>
</svg>`,
iconBg: '#22c55e',
valueColor: '#1f2937',
subtitle: 'Este mes',
formatValue: (val) => val.toString()
},
{
id: 'clientesActivos',
title: 'Clientes Activos',
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>`,
iconBg: '#f59e0b',
valueColor: '#1f2937',
subtitle: 'Con factura este mes',
formatValue: (val) => val.toString()
},
{
id: 'pendienteCobro',
title: 'Pendiente de Cobro',
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>`,
iconBg: '#8b5cf6',
valueColor: '#1f2937',
subtitle: 'Facturas vencidas',
formatValue: (val) => val.toString()
}
];
// Función para crear una tarjeta individual
function createStatCard(config, value) {
return `
<div class="stat-card" data-stat-id="${config.id}">
<div class="stat-icon" style="background-color: ${config.iconBg}">
${config.icon}
</div>
<div class="stat-content">
<span class="stat-title">${config.title}</span>
<span class="stat-value" style="color: ${config.valueColor}">${config.formatValue(value)}</span>
<span class="stat-subtitle">${config.subtitle}</span>
</div>
</div>
`;
}
// Función para renderizar todas las tarjetas
export function renderStatsCards(data = {}) {
const defaultData = {
totalFacturado: 0,
facturasEmitidas: 0,
clientesActivos: 0,
pendienteCobro: 0
};
const statsData = { ...defaultData, ...data };
return statsConfig
.map(config => createStatCard(config, statsData[config.id]))
.join('');
}
// Función para actualizar un valor específico
export function updateStatValue(containerId, statId, newValue) {
const container = document.querySelector(`#${containerId} [data-stat-id="${statId}"] .stat-value`);
if (container) {
const config = statsConfig.find(c => c.id === statId);
if (config) {
container.textContent = config.formatValue(newValue);
}
}
}
// Dashboard completo con estilos incluidos
export function renderDashboard(initialData = {}) {
const container = document.createElement('div');
container.className = 'dashboard-container';
// Datos por defecto (puedes pasarlos como parámetro)
const data = {
totalFacturado: 50.00,
facturasEmitidas: 0,
clientesActivos: 0,
pendienteCobro: 0,
...initialData
};
container.innerHTML = /*html*/`
<style>
.dashboard-container {
padding: 24px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.dashboard-text h2 {
margin: 0 0 8px 0;
font-size: 24px;
font-weight: 600;
color: #1f2937;
}
.dashboard-text p {
margin: 0 0 24px 0;
color: #6b7280;
font-size: 14px;
}
.data-container {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 24px;
}
.stat-card {
display: flex;
align-items: center;
gap: 16px;
background: #ffffff;
border-radius: 16px;
padding: 20px 24px;
flex: 1;
min-width: 200px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
border: 1px solid #f3f4f6;
transition: box-shadow 0.2s ease;
}
.stat-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.stat-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
flex-shrink: 0;
}
.stat-icon svg {
width: 24px;
height: 24px;
}
.stat-content {
display: flex;
flex-direction: column;
gap: 2px;
}
.stat-title {
font-size: 13px;
color: #6b7280;
font-weight: 500;
}
.stat-value {
font-size: 24px;
font-weight: 700;
line-height: 1.2;
}
.stat-subtitle {
font-size: 12px;
color: #9ca3af;
}
.charts-row {
display: flex;
gap: 16px;
}
.chart-wrapper {
flex: 1;
background: #ffffff;
border-radius: 16px;
padding: 24px;
border: 1px solid #f3f4f6;
min-width: 0;
}
.chart-title {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
@media (max-width: 768px) {
.data-container {
flex-direction: column;
}
.stat-card {
min-width: 100%;
}
.charts-row {
flex-direction: column;
}
}
</style>
<div class="dashboard-text">
<h2>Dashboard</h2>
<p>Resumen de facturación y estado de tus facturas</p>
</div>
<div class="data-container" id="stats-container">
${renderStatsCards(data)}
</div>
<div class="charts-row" id="charts-row">
</div>
`;
const chartsRow = container.querySelector('#charts-row');
chartsRow.appendChild(renderInvoiceStatusChart());
chartsRow.appendChild(renderBarChart());
return container;
}
// Ejemplo de uso:
// import { renderDashboard, updateStatValue } from './dashboard-stats.js';
//
// // Renderizar con datos iniciales
// const dashboard = renderDashboard({
// totalFacturado: 50.00,
// facturasEmitidas: 0,
// clientesActivos: 0,
// pendienteCobro: 0
// });
// document.body.appendChild(dashboard);
//
// // Actualizar un valor dinámicamente
// updateStatValue('stats-container', 'totalFacturado', 1500.50);