From b5a354a1de0df13205fca48e2aaf43a85677917f Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 18 Jan 2025 01:12:44 -0500 Subject: [PATCH] Fix and restyle salesmetrics component --- inventory-server/src/routes/dashboard.js | 114 +++++------------- .../src/components/dashboard/BestSellers.tsx | 2 +- .../components/dashboard/ForecastMetrics.tsx | 4 +- .../src/components/dashboard/SalesMetrics.tsx | 61 +++------- 4 files changed, 52 insertions(+), 129 deletions(-) diff --git a/inventory-server/src/routes/dashboard.js b/inventory-server/src/routes/dashboard.js index a4d8224..1bdb86d 100644 --- a/inventory-server/src/routes/dashboard.js +++ b/inventory-server/src/routes/dashboard.js @@ -640,95 +640,47 @@ router.get('/best-sellers', async (req, res) => { router.get('/sales/metrics', async (req, res) => { const { startDate, endDate } = req.query; try { - const [dailyData] = await executeQuery(` - SELECT JSON_ARRAYAGG( - JSON_OBJECT( - 'date', sale_date, - 'orders', COALESCE(total_orders, 0), - 'units', COALESCE(total_units, 0), - 'revenue', COALESCE(total_revenue, 0), - 'cogs', COALESCE(total_cogs, 0), - 'profit', COALESCE(total_profit, 0) - ) - ) as daily_data - FROM ( - SELECT - DATE(o.date) as sale_date, - COUNT(DISTINCT o.order_number) as total_orders, - SUM(o.quantity) as total_units, - SUM(o.price * o.quantity) as total_revenue, - SUM(p.cost_price * o.quantity) as total_cogs, - SUM((o.price - p.cost_price) * o.quantity) as total_profit - FROM orders o - JOIN products p ON o.product_id = p.product_id - WHERE o.canceled = false - AND o.date BETWEEN ? AND ? - GROUP BY DATE(o.date) - ) d - `, [startDate, endDate]); - - const [categoryData] = await executeQuery(` - SELECT JSON_ARRAYAGG( - JSON_OBJECT( - 'category', category_name, - 'orders', COALESCE(category_orders, 0), - 'units', COALESCE(category_units, 0), - 'revenue', COALESCE(category_revenue, 0) - ) - ) as category_data - FROM ( - SELECT - c.name as category_name, - COUNT(DISTINCT o.order_number) as category_orders, - SUM(o.quantity) as category_units, - SUM(o.price * o.quantity) as category_revenue - FROM orders o - JOIN products p ON o.product_id = p.product_id - JOIN product_categories pc ON p.product_id = pc.product_id - JOIN categories c ON pc.category_id = c.id - WHERE o.canceled = false - AND o.date BETWEEN ? AND ? - GROUP BY c.id, c.name - ) c - `, [startDate, endDate]); - - const [metrics] = await executeQuery(` + // Get daily sales data + const [dailyRows] = await executeQuery(` SELECT - COALESCE(COUNT(DISTINCT DATE(o.date)), 0) as days_with_sales, - COALESCE(COUNT(DISTINCT o.order_number), 0) as total_orders, - COALESCE(SUM(o.quantity), 0) as total_units, - COALESCE(SUM(o.price * o.quantity), 0) as total_revenue, - COALESCE(SUM(p.cost_price * o.quantity), 0) as total_cogs, - COALESCE(SUM((o.price - p.cost_price) * o.quantity), 0) as total_profit, - COALESCE(AVG(daily.orders), 0) as avg_daily_orders, - COALESCE(AVG(daily.units), 0) as avg_daily_units, - COALESCE(AVG(daily.revenue), 0) as avg_daily_revenue + DATE(o.date) as sale_date, + COUNT(DISTINCT o.order_number) as total_orders, + SUM(o.quantity) as total_units, + SUM(o.price * o.quantity) as total_revenue, + SUM(p.cost_price * o.quantity) as total_cogs, + SUM((o.price - p.cost_price) * o.quantity) as total_profit + FROM orders o + JOIN products p ON o.product_id = p.product_id + WHERE o.canceled = false + AND o.date BETWEEN ? AND ? + GROUP BY DATE(o.date) + ORDER BY sale_date + `, [startDate, endDate]); + + // Get summary metrics + const [metrics] = await executeQuery(` + SELECT + COUNT(DISTINCT o.order_number) as total_orders, + SUM(o.quantity) as total_units, + SUM(o.price * o.quantity) as total_revenue, + SUM(p.cost_price * o.quantity) as total_cogs, + SUM((o.price - p.cost_price) * o.quantity) as total_profit FROM orders o JOIN products p ON o.product_id = p.product_id - LEFT JOIN ( - SELECT - DATE(date) as sale_date, - COUNT(DISTINCT order_number) as orders, - SUM(quantity) as units, - SUM(price * quantity) as revenue - FROM orders - WHERE canceled = false - GROUP BY DATE(date) - ) daily ON DATE(o.date) = daily.sale_date WHERE o.canceled = false AND o.date BETWEEN ? AND ? `, [startDate, endDate]); const response = { - totalOrders: parseInt(metrics.total_orders) || 0, - totalUnitsSold: parseInt(metrics.total_units) || 0, - totalRevenue: parseFloat(metrics.total_revenue) || 0, - totalCogs: parseFloat(metrics.total_cogs) || 0, - dailySales: JSON.parse(dailyData.daily_data || '[]').map(day => ({ - date: day.date, - units: parseInt(day.units) || 0, - revenue: parseFloat(day.revenue) || 0, - cogs: parseFloat(day.cogs) || 0 + totalOrders: parseInt(metrics[0]?.total_orders) || 0, + totalUnitsSold: parseInt(metrics[0]?.total_units) || 0, + totalCogs: parseFloat(metrics[0]?.total_cogs) || 0, + totalRevenue: parseFloat(metrics[0]?.total_revenue) || 0, + dailySales: dailyRows.map(day => ({ + date: day.sale_date, + units: parseInt(day.total_units) || 0, + revenue: parseFloat(day.total_revenue) || 0, + cogs: parseFloat(day.total_cogs) || 0 })) }; diff --git a/inventory/src/components/dashboard/BestSellers.tsx b/inventory/src/components/dashboard/BestSellers.tsx index ca31dfd..ad17942 100644 --- a/inventory/src/components/dashboard/BestSellers.tsx +++ b/inventory/src/components/dashboard/BestSellers.tsx @@ -66,7 +66,7 @@ export function BestSellers() { - + diff --git a/inventory/src/components/dashboard/ForecastMetrics.tsx b/inventory/src/components/dashboard/ForecastMetrics.tsx index 87fe747..6eb5ab0 100644 --- a/inventory/src/components/dashboard/ForecastMetrics.tsx +++ b/inventory/src/components/dashboard/ForecastMetrics.tsx @@ -115,8 +115,8 @@ export function ForecastMetrics() { type="monotone" dataKey="revenue" name="Revenue" - stroke="#00C49F" - fill="#00C49F" + stroke="#8884D8" + fill="#8884D8" fillOpacity={0.2} /> diff --git a/inventory/src/components/dashboard/SalesMetrics.tsx b/inventory/src/components/dashboard/SalesMetrics.tsx index 671f776..ad1b281 100644 --- a/inventory/src/components/dashboard/SalesMetrics.tsx +++ b/inventory/src/components/dashboard/SalesMetrics.tsx @@ -6,7 +6,7 @@ import config from "@/config" import { formatCurrency } from "@/lib/utils" import { ClipboardList, Package, DollarSign, ShoppingCart } from "lucide-react" import { DateRange } from "react-day-picker" -import { addDays } from "date-fns" +import { addDays, format } from "date-fns" import { DateRangePicker } from "@/components/ui/date-range-picker-narrow" interface SalesData { @@ -45,7 +45,7 @@ export function SalesMetrics() { return ( <> - + Sales Overview
- +

Total Orders

-

{data?.totalOrders.toLocaleString() || 0}

+

{data?.totalOrders.toLocaleString() || 0}

Units Sold

-

{data?.totalUnitsSold.toLocaleString() || 0}

+

{data?.totalUnitsSold.toLocaleString() || 0}

Cost of Goods

-

{formatCurrency(data?.totalCogs || 0)}

+

{formatCurrency(data?.totalCogs || 0)}

Revenue

-

{formatCurrency(data?.totalRevenue || 0)}

+

{formatCurrency(data?.totalRevenue || 0)}

-
+
- + value.toLocaleString()} - /> - formatCurrency(value)} + tick={false} /> [ - name === "units" ? value.toLocaleString() : formatCurrency(value), - name === "units" ? "Units" : name === "revenue" ? "Revenue" : "COGS" - ]} - labelFormatter={(label) => `Date: ${label}`} + formatter={(value: number) => [formatCurrency(value), "Revenue"]} + labelFormatter={(date) => format(new Date(date), 'MMM d, yyyy')} /> - -