diff --git a/client/src/pages/Analytics.tsx b/client/src/pages/Analytics.tsx index f029786..00423d4 100644 --- a/client/src/pages/Analytics.tsx +++ b/client/src/pages/Analytics.tsx @@ -452,15 +452,28 @@ const Analytics = () => { // Calculate top profitable products based on actual sales performance const topProducts = useMemo(() => { + console.log('=== TOP PRODUCTS CALCULATION ==='); + console.log('Filtered orders for products:', filteredOrders.length); + // Create a map to track sales and profits for each product const productSalesMap = new Map(); - filteredOrders.forEach(order => { + filteredOrders.forEach((order, orderIndex) => { if (order.items && Array.isArray(order.items)) { - order.items.forEach(item => { - const key = item.title || 'Unknown Product'; - const current = productSalesMap.get(key) || { - title: item.title, + console.log(`Order ${orderIndex + 1} items:`, order.items); + order.items.forEach((item, itemIndex) => { + // Try to get a meaningful product identifier + let productKey = item.title || `Order Item ${orderIndex + 1}-${itemIndex + 1}`; + + // If it's still a generic title, try to make it more specific + if (productKey === 'Product from Etsy' || productKey.includes('Product from')) { + productKey = `Product ${orderIndex + 1}-${itemIndex + 1} ($${item.price})`; + } + + console.log(`Processing item: ${productKey}, Price: $${item.price}, Qty: ${item.quantity}`); + + const current = productSalesMap.get(productKey) || { + title: productKey, totalRevenue: 0, totalQuantity: 0, totalPrintingCost: 0, @@ -479,16 +492,23 @@ const Analytics = () => { current.totalCostOfGoods += itemCostOfGoods; current.totalProfit += itemProfit; - productSalesMap.set(key, current); + productSalesMap.set(productKey, current); }); } }); + console.log('Product sales map:', Array.from(productSalesMap.entries())); + // Convert to array and sort by total profit - return Array.from(productSalesMap.values()) + const result = Array.from(productSalesMap.values()) .filter(product => product.totalRevenue > 0) .sort((a, b) => b.totalProfit - a.totalProfit) .slice(0, 5); + + console.log('Top products result:', result); + console.log('==='); + + return result; }, [filteredOrders]); const recentOrders = filteredOrders @@ -697,35 +717,65 @@ const Analytics = () => { {/* Revenue Chart */}

Revenue Trend

-
+
{monthlyData.length > 0 ? ( -
+
{monthlyData.map((data, index) => { const maxRevenue = Math.max(...monthlyData.map(d => d.revenue)); - const height = maxRevenue > 0 ? Math.max((data.revenue / maxRevenue) * 85, 2) : 0; + const height = maxRevenue > 0 ? Math.max((data.revenue / maxRevenue) * 75, 3) : 0; return (
-
+ {/* Value label above bar */} +
+
+ ${data.revenue.toFixed(0)} +
+
+ + {/* Permanent value label for larger values */} + {data.revenue > maxRevenue * 0.3 && ( +
+ ${data.revenue > 1000 ? `${(data.revenue/1000).toFixed(1)}k` : data.revenue.toFixed(0)} +
+ )} + +
0 ? '4px' : '2px', - maxHeight: '200px' + minHeight: data.revenue > 0 ? '8px' : '2px', + maxHeight: '180px' }} - /> - {/* Tooltip */} -
-
-
{data.month}
-
Revenue: ${data.revenue.toFixed(2)}
-
Profit: ${data.profit.toFixed(2)}
+ > + {/* Value label on smaller bars */} + {data.revenue <= maxRevenue * 0.3 && data.revenue > 0 && ( +
+ ${data.revenue > 1000 ? `${(data.revenue/1000).toFixed(1)}k` : data.revenue.toFixed(0)} +
+ )} +
+ + {/* Enhanced Tooltip */} +
+
+
{data.month}
+
+ Revenue: + ${data.revenue.toFixed(2)} +
+
+ Profit: + ${data.profit.toFixed(2)} +
- - {data.month.substring(0, 3)} + + + {data.month.split(' ')[0]}
); @@ -806,8 +856,10 @@ const Analytics = () => {
#{index + 1}
-

{product.title || 'Unknown Product'}

-

Sold: {product.totalQuantity} units

+

+ {product.title || 'Unknown Product'} +

+

Sold: {product.totalQuantity} units • Revenue: ${product.totalRevenue.toFixed(2)}