dimensionalpulsar's picture
Upload 49 files
28b0bde verified
import React, { useState, useEffect } from 'react';
import { db } from '../../firebase/config';
import { ref, onValue } from 'firebase/database';
import {
Chart as ChartJS, CategoryScale, LinearScale, PointElement,
LineElement, Title, Tooltip, Legend, BarElement
} from 'chart.js';
import { Line, Bar } from 'react-chartjs-2';
import { TrendingUp, Package, Users as UsersIcon, Calendar } from 'lucide-react';
ChartJS.register(
CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, BarElement
);
export default function Reports() {
const [salesData, setSalesData] = useState([0, 0, 0, 0, 0, 0, 0]);
const [topProducts, setTopProducts] = useState({ labels: [], data: [] });
const [stats, setStats] = useState({ totalSales: 0, orderCount: 0, avgTicket: 0 });
useEffect(() => {
onValue(ref(db, 'orders'), (snapshot) => {
const data = snapshot.val();
if (data) {
const orders = Object.values(data);
const weeklySales = [0, 0, 0, 0, 0, 0, 0];
const productCounts = {};
let total = 0;
orders.forEach(order => {
if (order.status === 'completed') {
total += order.total;
// Simple day mapping (last 7 days logic would be better but this is for demo)
const day = new Date(order.timestamp).getDay(); // 0-6
const index = (day + 6) % 7; // Map Mon-Sun
weeklySales[index] += order.total;
order.items.forEach(item => {
productCounts[item.name] = (productCounts[item.name] || 0) + item.qty;
});
}
});
setSalesData(weeklySales);
setStats({
totalSales: total,
orderCount: orders.filter(o => o.status === 'completed').length,
avgTicket: total / (orders.filter(o => o.status === 'completed').length || 1)
});
const sortedProducts = Object.entries(productCounts)
.sort((a,b) => b[1] - a[1])
.slice(0, 5);
setTopProducts({
labels: sortedProducts.map(p => p[0]),
data: sortedProducts.map(p => p[1])
});
}
});
}, []);
const lineData = {
labels: ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'],
datasets: [{
label: 'Ventas ($)',
data: salesData,
borderColor: '#FF5A5F',
backgroundColor: 'rgba(255, 90, 95, 0.2)',
fill: true,
tension: 0.4
}]
};
const barData = {
labels: topProducts.labels,
datasets: [{
label: 'Unidades Vendidas',
data: topProducts.data,
backgroundColor: 'rgba(0, 166, 153, 0.7)',
borderRadius: 8
}]
};
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { labels: { color: '#9595a8' } } },
scales: {
x: { ticks: { color: '#9595a8' }, grid: { color: 'rgba(255,255,255,0.05)' } },
y: { ticks: { color: '#9595a8' }, grid: { color: 'rgba(255,255,255,0.05)' } }
}
};
return (
<div className="animate-fade-in">
<header style={{ marginBottom: '2.5rem' }}>
<h2 className="text-gradient" style={{ fontSize: '2rem', fontWeight: '800' }}>Análisis de Negocio</h2>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1.5rem', marginTop: '1.5rem' }}>
<div className="glass-card" style={{ padding: '1.25rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', color: 'var(--text-muted)', fontSize: '0.8rem' }}>Ventas Totales <TrendingUp size={16} /></div>
<div style={{ fontSize: '1.5rem', fontWeight: '800', marginTop: '0.5rem' }}>${stats.totalSales.toFixed(2)}</div>
</div>
<div className="glass-card" style={{ padding: '1.25rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', color: 'var(--text-muted)', fontSize: '0.8rem' }}>Pedidos <Package size={16} /></div>
<div style={{ fontSize: '1.5rem', fontWeight: '800', marginTop: '0.5rem' }}>{stats.orderCount}</div>
</div>
<div className="glass-card" style={{ padding: '1.25rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', color: 'var(--text-muted)', fontSize: '0.8rem' }}>Ticket Promedio <Calendar size={16} /></div>
<div style={{ fontSize: '1.5rem', fontWeight: '800', marginTop: '0.5rem' }}>${stats.avgTicket.toFixed(2)}</div>
</div>
</div>
</header>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))', gap: '2rem' }}>
<div className="glass-card" style={{ height: '350px', display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '1.5rem', fontSize: '1rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
Ventas por Día de la Semana
</h3>
<div style={{ flex: 1, position: 'relative' }}>
<Line data={lineData} options={options} />
</div>
</div>
<div className="glass-card" style={{ height: '350px', display: 'flex', flexDirection: 'column' }}>
<h3 style={{ marginBottom: '1.5rem', fontSize: '1rem' }}>Productos Estrella</h3>
<div style={{ flex: 1, position: 'relative' }}>
<Bar data={barData} options={options} />
</div>
</div>
</div>
</div>
);
}