diff --git a/client/src/pages/ProfitAnalysis.tsx b/client/src/pages/ProfitAnalysis.tsx index c2b3f35..9c6fe58 100644 --- a/client/src/pages/ProfitAnalysis.tsx +++ b/client/src/pages/ProfitAnalysis.tsx @@ -40,6 +40,11 @@ const ProfitAnalysis = () => { return ProfitAnalysisService.calculateProfitMetrics(filteredOrders, products || [], filteredExpenses); }, [filteredOrders, products, filteredExpenses]); + // Monthly revenue / cost / profit trend + const monthlyTrends = useMemo(() => { + return ProfitAnalysisService.calculateMonthlyTrends(filteredOrders, products || [], filteredExpenses); + }, [filteredOrders, products, filteredExpenses]); + // Profit & loss statement + indicative GST summary for the selected period const plData = useMemo(() => { const revenue = filteredOrders.reduce((s, o) => s + orderNetRevenue(o), 0); @@ -456,13 +461,77 @@ const ProfitAnalysis = () => { )} - {/* Placeholder for trends view */} + {/* Monthly trends */} {selectedView === 'trends' && ( -
- -

Profit Trends

-

Interactive charts coming soon...

-
+ monthlyTrends.length === 0 ? ( +
+ +

Profit Trends

+

No data for the selected period.

+
+ ) : ( + <> + {/* Revenue & profit bars */} +
+
+

Revenue & Profit by Month

+ Revenue + Profit +
+ {(() => { + const maxVal = Math.max(...monthlyTrends.map(m => Math.max(m.revenue, m.profit)), 0); + const maxBarPx = 180; + return ( +
+ {monthlyTrends.map((m, i) => { + const revPx = maxVal > 0 ? Math.max((m.revenue / maxVal) * maxBarPx, m.revenue > 0 ? 4 : 0) : 0; + const profitPx = maxVal > 0 ? Math.max((Math.max(m.profit, 0) / maxVal) * maxBarPx, 0) : 0; + return ( +
+
+
+
+
+ {m.month.split(' ')[0]} +
+ ); + })} +
+ ); + })()} +
+ + {/* Monthly breakdown table */} +
+
+ + + + {['Month', 'Orders', 'Revenue', 'Printing', 'Expenses', 'Profit', 'Margin'].map(h => ( + + ))} + + + + {monthlyTrends.map((m, i) => ( + + + + + + + + + + ))} + +
{h}
{m.month}{m.orderCount}{formatCurrency(m.revenue)}{formatCurrency(m.costs)}{formatCurrency(m.expenses)}= 0 ? 'text-green-600' : 'text-red-600'}`}>{formatCurrency(m.profit)}{m.margin.toFixed(1)}%
+
+
+ + ) )} {/* Order Analysis */}