fixed product section of the reports page

This commit is contained in:
2ManyProjects 2025-04-28 21:09:36 -05:00
parent 3d4d876283
commit b88fb93637

View file

@ -235,6 +235,11 @@ const ReportsPage = () => {
.slice(0, 8); // Top 8 locations .slice(0, 8); // Top 8 locations
}, [filteredOrders]); }, [filteredOrders]);
// Debug - log filtered orders
useEffect(() => {
console.log("Filtered orders:", filteredOrders);
}, [filteredOrders]);
// Prepare time series data for revenue chart // Prepare time series data for revenue chart
const revenueTimeSeriesData = useMemo(() => { const revenueTimeSeriesData = useMemo(() => {
if (!orders) return []; if (!orders) return [];
@ -293,9 +298,41 @@ const ReportsPage = () => {
return Array.from(dataMap.values()); return Array.from(dataMap.values());
}, [filteredOrders, timelineType, fromDate, toDate]); }, [filteredOrders, timelineType, fromDate, toDate]);
// Fetch order details for product analysis
const { data: orderDetails, isLoading: orderDetailsLoading } = useQuery({
queryKey: ['admin-order-details', filteredOrders.map(order => order.id)],
queryFn: async () => {
// Only fetch if we have filtered orders
if (!filteredOrders.length) return [];
// Fetch details for each order in parallel
const detailPromises = filteredOrders.map(order =>
apiClient.get(`/admin/orders/${order.id}`)
.then(response => response.data)
.catch(error => {
console.error(`Error fetching details for order ${order.id}:`, error);
return null;
})
);
const results = await Promise.all(detailPromises);
return results.filter(Boolean); // Remove any failed requests
},
enabled: filteredOrders.length > 0
});
// Debug - log order details
useEffect(() => {
if (orderDetails) {
console.log("Order details:", orderDetails);
}
}, [orderDetails]);
// Prepare product sales data // Prepare product sales data
const productSalesData = useMemo(() => { const productSalesData = useMemo(() => {
if (!orders || !products) return []; if (!products || !orderDetails) return [];
const productSales = {}; const productSales = {};
@ -310,13 +347,23 @@ const ReportsPage = () => {
}; };
}); });
// Aggregate sales data from orders // Aggregate sales data from order details
filteredOrders.forEach(order => { orderDetails.forEach(order => {
if (order.items && Array.isArray(order.items)) { if (order.items && Array.isArray(order.items)) {
order.items.forEach(item => { order.items.forEach(item => {
if (productSales[item.product_id]) { if (productSales[item.product_id]) {
productSales[item.product_id].quantity += item.quantity; productSales[item.product_id].quantity += parseInt(item.quantity) || 0;
productSales[item.product_id].revenue += parseFloat(item.price_at_purchase) * item.quantity; productSales[item.product_id].revenue += parseFloat(item.price_at_purchase || 0) * (parseInt(item.quantity) || 0);
} else {
// Handle case where product might exist in orders but not in current products list
console.log(`Product ${item.product_id} found in orders but not in products list`);
productSales[item.product_id] = {
id: item.product_id,
name: item.product_name || `Product ${item.product_id.substring(0, 8)}...`,
category: item.product_category || 'Unknown',
quantity: parseInt(item.quantity) || 0,
revenue: parseFloat(item.price_at_purchase || 0) * (parseInt(item.quantity) || 0)
};
} }
}); });
} }
@ -326,7 +373,7 @@ const ReportsPage = () => {
return Object.values(productSales) return Object.values(productSales)
.filter(product => product.quantity > 0) .filter(product => product.quantity > 0)
.sort((a, b) => b.quantity - a.quantity); .sort((a, b) => b.quantity - a.quantity);
}, [filteredOrders, products]); }, [products, orderDetails]);
// Top selling products for the chart // Top selling products for the chart
const topSellingProducts = useMemo(() => { const topSellingProducts = useMemo(() => {
@ -358,7 +405,7 @@ const ReportsPage = () => {
}, [productSalesData]); }, [productSalesData]);
// Loading state // Loading state
const isLoading = ordersLoading || productsLoading; const isLoading = ordersLoading || productsLoading || orderDetailsLoading;
// Handle export reports // Handle export reports
const handleExportCSV = () => { const handleExportCSV = () => {
@ -629,6 +676,7 @@ const ReportsPage = () => {
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
Top Selling Products Top Selling Products
</Typography> </Typography>
{topSellingProducts.length > 0 ? (
<Box sx={{ height: 400 }}> <Box sx={{ height: 400 }}>
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<BarChart <BarChart
@ -639,7 +687,7 @@ const ReportsPage = () => {
<XAxis dataKey="name" /> <XAxis dataKey="name" />
<YAxis /> <YAxis />
<Tooltip formatter={(value, name) => { <Tooltip formatter={(value, name) => {
return name === 'revenue' ? `$${value.toFixed(2)}` : value; return name === 'revenue' ? `${value.toFixed(2)}` : value;
}} /> }} />
<Legend /> <Legend />
<Bar dataKey="quantity" name="Units Sold" fill="#8884d8" /> <Bar dataKey="quantity" name="Units Sold" fill="#8884d8" />
@ -647,6 +695,13 @@ const ReportsPage = () => {
</BarChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</Box> </Box>
) : (
<Box sx={{ p: 4, textAlign: 'center', bgcolor: 'background.paper', borderRadius: 1 }}>
<Typography variant="body1" color="text.secondary">
No product sales data available for the selected time period.
</Typography>
</Box>
)}
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
@ -654,6 +709,7 @@ const ReportsPage = () => {
Product Sales Details Product Sales Details
</Typography> </Typography>
<Box sx={{ overflowX: 'auto' }}> <Box sx={{ overflowX: 'auto' }}>
{productSalesData.length > 0 ? (
<table style={{ width: '100%', borderCollapse: 'collapse' }}> <table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead> <thead>
<tr> <tr>
@ -674,8 +730,24 @@ const ReportsPage = () => {
))} ))}
</tbody> </tbody>
</table> </table>
) : (
<Box sx={{ p: 4, textAlign: 'center', bgcolor: 'background.paper', borderRadius: 1 }}>
<Typography variant="body1" color="text.secondary">
No product sales data available for the selected time period.
</Typography>
</Box>
)}
</Box> </Box>
</Grid> </Grid>
{orderDetailsLoading && (
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
<CircularProgress size={28} />
<Typography variant="body2" color="text.secondary" sx={{ ml: 2 }}>
Loading product data...
</Typography>
</Grid>
)}
</Grid> </Grid>
)} )}