|
@@ -443,24 +392,17 @@ const MetaCampaigns = () => {
if (loading) {
return (
-
-
-
-
- Meta Ads Performance
-
-
-
+
+ }
+ />
+
{[...Array(12)].map((_, i) => (
-
+
))}
@@ -473,25 +415,25 @@ const MetaCampaigns = () => {
if (error) {
return (
-
+
-
- {error}
-
+
);
}
return (
-
-
-
-
- Meta Ads Performance
-
+
+
-
+
@@ -502,82 +444,102 @@ const MetaCampaigns = () => {
Last 90 days
-
+ }
+ />
+
- {[
- {
- label: "Active Campaigns",
- value: summaryMetrics?.totalCampaigns,
- options: { icon: Target, iconColor: "text-purple-500" },
- },
- {
- label: "Total Spend",
- value: summaryMetrics?.totalSpend,
- options: { isMonetary: true, decimalPlaces: 0, icon: DollarSign, iconColor: "text-green-500" },
- },
- {
- label: "Total Reach",
- value: summaryMetrics?.totalReach,
- options: { icon: Users, iconColor: "text-blue-500" },
- },
- {
- label: "Total Impressions",
- value: summaryMetrics?.totalImpressions,
- options: { icon: Eye, iconColor: "text-indigo-500" },
- },
- {
- label: "Avg Frequency",
- value: summaryMetrics?.avgFrequency,
- options: { decimalPlaces: 2, icon: Repeat, iconColor: "text-cyan-500" },
- },
- {
- label: "Total Engagements",
- value: summaryMetrics?.totalPostEngagements,
- options: { icon: MessageCircle, iconColor: "text-pink-500" },
- },
- {
- label: "Avg CPM",
- value: summaryMetrics?.avgCpm,
- options: { isMonetary: true, decimalPlaces: 2, icon: DollarSign, iconColor: "text-emerald-500" },
- },
- {
- label: "Avg CTR",
- value: summaryMetrics?.avgCtr,
- options: { isPercentage: true, decimalPlaces: 2, icon: BarChart, iconColor: "text-orange-500" },
- },
- {
- label: "Avg CPC",
- value: summaryMetrics?.avgCpc,
- options: { isMonetary: true, decimalPlaces: 2, icon: MousePointer, iconColor: "text-rose-500" },
- },
- {
- label: "Total Link Clicks",
- value: summaryMetrics?.totalLinkClicks,
- options: { icon: MousePointer, iconColor: "text-amber-500" },
- },
- {
- label: "Total Purchases",
- value: summaryMetrics?.totalPurchases,
- options: { icon: ShoppingCart, iconColor: "text-teal-500" },
- },
- {
- label: "Purchase Value",
- value: summaryMetrics?.totalPurchaseValue,
- options: { isMonetary: true, decimalPlaces: 0, icon: DollarSign, iconColor: "text-lime-500" },
- },
- ].map((card) => (
-
- {summaryCard(card.label, card.value, card.options)}
-
- ))}
+
+
+
+
+
+
+
+
+
+
+
+
-
- |
+ |
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+ |
|
-
+
{sortedCampaigns.map((campaign) => (
{
>
-
+
diff --git a/inventory/src/components/dashboard/MiniEventFeed.jsx b/inventory/src/components/dashboard/MiniEventFeed.jsx
index 1d61cb1..0b8c424 100644
--- a/inventory/src/components/dashboard/MiniEventFeed.jsx
+++ b/inventory/src/components/dashboard/MiniEventFeed.jsx
@@ -22,10 +22,10 @@ import {
ChevronRight,
} from "lucide-react";
import { format } from "date-fns";
-import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Skeleton } from "@/components/ui/skeleton";
import { EventDialog } from "./EventFeed.jsx";
import { Button } from "@/components/ui/button";
+import { DashboardErrorState } from "@/components/dashboard/shared";
const METRIC_IDS = {
PLACED_ORDER: "Y8cqcF",
@@ -439,13 +439,7 @@ const MiniEventFeed = ({
{loading && !events.length ? (
) : error ? (
-
-
- Error
-
- Failed to load event feed: {error}
-
-
+
) : !events || events.length === 0 ? (
diff --git a/inventory/src/components/dashboard/MiniRealtimeAnalytics.jsx b/inventory/src/components/dashboard/MiniRealtimeAnalytics.jsx
index 3f3ed04..61f8cdf 100644
--- a/inventory/src/components/dashboard/MiniRealtimeAnalytics.jsx
+++ b/inventory/src/components/dashboard/MiniRealtimeAnalytics.jsx
@@ -11,41 +11,11 @@ import {
import { AlertTriangle, Users, Activity } from "lucide-react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { format } from "date-fns";
-import {
- summaryCard,
- SkeletonSummaryCard,
- SkeletonBarChart,
- processBasicData,
-} from "./RealtimeAnalytics";
+import { processBasicData } from "./RealtimeAnalytics";
+import { DashboardStatCardMini, DashboardStatCardMiniSkeleton, TOOLTIP_THEMES } from "@/components/dashboard/shared";
import { Skeleton } from "@/components/ui/skeleton";
+import { METRIC_COLORS } from "@/lib/dashboard/designTokens";
-const SkeletonCard = ({ colorScheme = "sky" }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
const MiniRealtimeAnalytics = () => {
const [basicData, setBasicData] = useState({
@@ -119,8 +89,8 @@ const MiniRealtimeAnalytics = () => {
return (
-
-
+
+
@@ -168,34 +138,22 @@ const MiniRealtimeAnalytics = () => {
return (
- {summaryCard(
- "Last 30 Minutes",
- "Active users",
- basicData.last30MinUsers,
- {
- colorClass: "text-sky-200",
- titleClass: "text-sky-100 font-bold text-md",
- descriptionClass: "pt-2 text-sky-200 text-md font-semibold",
- background: "h-[150px] pt-2 bg-gradient-to-br from-sky-900 to-sky-800",
- icon: Users,
- iconColor: "text-sky-900",
- iconBackground: "bg-sky-300"
- }
- )}
- {summaryCard(
- "Last 5 Minutes",
- "Active users",
- basicData.last5MinUsers,
- {
- colorClass: "text-sky-200",
- titleClass: "text-sky-100 font-bold text-md",
- descriptionClass: "pt-2 text-sky-200 text-md font-semibold",
- background: "h-[150px] pt-2 bg-gradient-to-br from-sky-900 to-sky-800",
- icon: Activity,
- iconColor: "text-sky-900",
- iconBackground: "bg-sky-300"
- }
- )}
+
+
@@ -219,28 +177,25 @@ const MiniRealtimeAnalytics = () => {
{
if (active && payload && payload.length) {
+ const styles = TOOLTIP_THEMES.sky;
return (
-
-
-
- {payload[0].payload.timestamp}
-
-
-
- Active Users:
-
-
- {payload[0].value}
-
+
+
+ {payload[0].payload.timestamp}
+
+
+
+ Active Users
+ {payload[0].value}
-
-
+
+
);
}
return null;
}}
/>
-
+
diff --git a/inventory/src/components/dashboard/MiniSalesChart.jsx b/inventory/src/components/dashboard/MiniSalesChart.jsx
index 1ac2ce3..b311484 100644
--- a/inventory/src/components/dashboard/MiniSalesChart.jsx
+++ b/inventory/src/components/dashboard/MiniSalesChart.jsx
@@ -1,12 +1,8 @@
-import React, { useState, useEffect, useCallback, memo } from "react";
-import axios from "axios";
+import React, { useState, useEffect, useCallback } from "react";
import { acotService } from "@/services/dashboard/acotService";
import {
Card,
CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
} from "@/components/ui/card";
import {
LineChart,
@@ -17,141 +13,16 @@ import {
Tooltip,
ResponsiveContainer,
} from "recharts";
-import { DateTime } from "luxon";
-import { Skeleton } from "@/components/ui/skeleton";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
-import { AlertCircle, TrendingUp, DollarSign, ShoppingCart, Truck, PiggyBank, ArrowUp,ArrowDown, Banknote, Package } from "lucide-react";
-import { formatCurrency, CustomTooltip, processData, StatCard } from "./SalesChart.jsx";
-
-const SkeletonChart = () => (
-
-
- {/* Grid lines */}
- {[...Array(5)].map((_, i) => (
-
- ))}
- {/* Y-axis labels */}
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
- {/* X-axis labels */}
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
- {/* Chart lines */}
-
-
-
-);
-
-const MiniStatCard = memo(({
- title,
- value,
- icon: Icon,
- colorClass,
- iconColor,
- iconBackground,
- background,
- previousValue,
- trend,
- trendValue,
- onClick,
- active = true,
- titleClass = "text-sm font-bold text-gray-100",
- descriptionClass = "text-sm font-semibold text-gray-200"
-}) => (
-
-
-
- {title}
-
- {Icon && (
-
- )}
-
-
-
-
-
- {value}
-
-
- Prev: {previousValue}
- {trend && (
-
- {trend === "up" ? (
-
- ) : (
-
- )}
- {trendValue}
-
- )}
-
-
-
-
-
-));
-
-MiniStatCard.displayName = "MiniStatCard";
-
-const SkeletonCard = ({ colorScheme = "emerald" }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
+import { AlertCircle, PiggyBank, Truck } from "lucide-react";
+import { formatCurrency, processData } from "./SalesChart.jsx";
+import { METRIC_COLORS } from "@/lib/dashboard/designTokens";
+import {
+ DashboardStatCardMini,
+ DashboardStatCardMiniSkeleton,
+ ChartSkeleton,
+ TOOLTIP_THEMES,
+} from "@/components/dashboard/shared";
const MiniSalesChart = ({ className = "" }) => {
const [data, setData] = useState([]);
@@ -269,19 +140,46 @@ const MiniSalesChart = ({ className = "" }) => {
);
}
+ // Helper to calculate trend direction
+ const getRevenueTrend = () => {
+ const current = summaryStats.periodProgress < 100
+ ? (projection?.projectedRevenue || summaryStats.totalRevenue)
+ : summaryStats.totalRevenue;
+ return current >= summaryStats.prevRevenue ? "up" : "down";
+ };
+
+ const getRevenueTrendValue = () => {
+ const current = summaryStats.periodProgress < 100
+ ? (projection?.projectedRevenue || summaryStats.totalRevenue)
+ : summaryStats.totalRevenue;
+ return `${Math.abs(Math.round((current - summaryStats.prevRevenue) / summaryStats.prevRevenue * 100))}%`;
+ };
+
+ const getOrdersTrend = () => {
+ const projected = Math.round(summaryStats.totalOrders * (100 / summaryStats.periodProgress));
+ const current = summaryStats.periodProgress < 100 ? projected : summaryStats.totalOrders;
+ return current >= summaryStats.prevOrders ? "up" : "down";
+ };
+
+ const getOrdersTrendValue = () => {
+ const projected = Math.round(summaryStats.totalOrders * (100 / summaryStats.periodProgress));
+ const current = summaryStats.periodProgress < 100 ? projected : summaryStats.totalOrders;
+ return `${Math.abs(Math.round((current - summaryStats.prevOrders) / summaryStats.prevOrders * 100))}%`;
+ };
+
if (loading && !data) {
return (
{/* Stat Cards */}
-
-
+
+
{/* Chart Card */}
-
+
@@ -294,56 +192,38 @@ const MiniSalesChart = ({ className = "" }) => {
{loading ? (
<>
-
-
+
+
>
) : (
<>
- = summaryStats.prevRevenue ? "up" : "down")
- : (summaryStats.totalRevenue >= summaryStats.prevRevenue ? "up" : "down")
- }
- trendValue={
- summaryStats.periodProgress < 100
- ? `${Math.abs(Math.round(((projection?.projectedRevenue || summaryStats.totalRevenue) - summaryStats.prevRevenue) / summaryStats.prevRevenue * 100))}%`
- : `${Math.abs(Math.round(((summaryStats.totalRevenue - summaryStats.prevRevenue) / summaryStats.prevRevenue) * 100))}%`
- }
- colorClass="text-emerald-300"
- titleClass="text-emerald-300 font-bold text-md"
- descriptionClass="text-emerald-300 text-md font-semibold pb-1"
+ description={`Prev: ${formatCurrency(summaryStats.prevRevenue, false)}`}
+ trend={{
+ direction: getRevenueTrend(),
+ value: getRevenueTrendValue(),
+ }}
icon={PiggyBank}
- iconColor="text-emerald-900"
iconBackground="bg-emerald-300"
+ gradient="slate"
+ className={!visibleMetrics.revenue ? 'opacity-50' : ''}
onClick={() => toggleMetric('revenue')}
- active={visibleMetrics.revenue}
/>
- = summaryStats.prevOrders ? "up" : "down")
- : (summaryStats.totalOrders >= summaryStats.prevOrders ? "up" : "down")
- }
- trendValue={
- summaryStats.periodProgress < 100
- ? `${Math.abs(Math.round(((Math.round(summaryStats.totalOrders * (100 / summaryStats.periodProgress))) - summaryStats.prevOrders) / summaryStats.prevOrders * 100))}%`
- : `${Math.abs(Math.round(((summaryStats.totalOrders - summaryStats.prevOrders) / summaryStats.prevOrders) * 100))}%`
- }
- colorClass="text-blue-300"
- titleClass="text-blue-300 font-bold text-md"
- descriptionClass="text-blue-300 text-md font-semibold pb-1"
+ description={`Prev: ${summaryStats.prevOrders.toLocaleString()}`}
+ trend={{
+ direction: getOrdersTrend(),
+ value: getOrdersTrendValue(),
+ }}
icon={Truck}
- iconColor="text-blue-900"
iconBackground="bg-blue-300"
+ gradient="slate"
+ className={!visibleMetrics.orders ? 'opacity-50' : ''}
onClick={() => toggleMetric('orders')}
- active={visibleMetrics.orders}
/>
>
)}
@@ -354,40 +234,7 @@ const MiniSalesChart = ({ className = "" }) => {
{loading ? (
-
- {/* Grid lines */}
- {[...Array(5)].map((_, i) => (
-
- ))}
- {/* Y-axis labels */}
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
- {/* X-axis labels */}
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
- {/* Chart lines */}
-
-
+
) : (
{
content={({ active, payload }) => {
if (active && payload && payload.length) {
const timestamp = new Date(payload[0].payload.timestamp);
+ const styles = TOOLTIP_THEMES.stone;
return (
-
-
-
- {timestamp.toLocaleDateString([], {
- weekday: "short",
- month: "short",
- day: "numeric"
- })}
-
+
+
+ {timestamp.toLocaleDateString([], {
+ weekday: "short",
+ month: "short",
+ day: "numeric"
+ })}
+
+
{payload
.filter(entry => visibleMetrics[entry.dataKey])
.map((entry, index) => (
-
-
- {entry.name}:
+
+
+ {entry.name}
-
- {entry.dataKey === 'revenue'
+
+ {entry.dataKey === 'revenue'
? formatCurrency(entry.value)
: entry.value.toLocaleString()}
))}
-
-
+
+
);
}
return null;
@@ -458,7 +306,7 @@ const MiniSalesChart = ({ className = "" }) => {
type="monotone"
dataKey="revenue"
name="Revenue"
- stroke="#10b981"
+ stroke={METRIC_COLORS.revenue}
strokeWidth={2}
dot={false}
/>
@@ -469,7 +317,7 @@ const MiniSalesChart = ({ className = "" }) => {
type="monotone"
dataKey="orders"
name="Orders"
- stroke="#3b82f6"
+ stroke={METRIC_COLORS.orders}
strokeWidth={2}
dot={false}
/>
diff --git a/inventory/src/components/dashboard/MiniStatCards.jsx b/inventory/src/components/dashboard/MiniStatCards.jsx
index b9771e0..1a11121 100644
--- a/inventory/src/components/dashboard/MiniStatCards.jsx
+++ b/inventory/src/components/dashboard/MiniStatCards.jsx
@@ -1,20 +1,11 @@
-import React, { useState, useEffect, useCallback, memo } from "react";
-import axios from "axios";
+import React, { useState, useEffect, useCallback } from "react";
import { acotService } from "@/services/dashboard/acotService";
import {
Card,
CardContent,
- CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
import {
Dialog,
DialogContent,
@@ -22,7 +13,6 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { DateTime } from "luxon";
-import { TIME_RANGES } from "@/lib/dashboard/constants";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
DollarSign,
@@ -30,23 +20,7 @@ import {
Package,
AlertCircle,
CircleDollarSign,
- Loader2,
} from "lucide-react";
-import { Skeleton } from "@/components/ui/skeleton";
-import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
- TooltipProvider,
-} from "@/components/ui/tooltip";
-import {
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@/components/ui/table";
// Import the detail view components and utilities from StatCards
import {
@@ -54,163 +28,28 @@ import {
OrdersDetails,
AverageOrderDetails,
ShippingDetails,
- StatCard,
DetailDialog,
formatCurrency,
formatPercentage,
- SkeletonCard,
} from "./StatCards";
+import {
+ DashboardStatCardMini,
+ DashboardStatCardMiniSkeleton,
+ ChartSkeleton,
+ TableSkeleton,
+ DashboardErrorState,
+} from "@/components/dashboard/shared";
-// Mini skeleton components
-const MiniSkeletonChart = ({ type = "line" }) => (
-
-
- {/* Grid lines */}
- {[...Array(5)].map((_, i) => (
-
- ))}
- {/* Y-axis labels */}
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
- {/* X-axis labels */}
-
- {[...Array(6)].map((_, i) => (
-
- ))}
-
- {type === "bar" ? (
-
- {[...Array(24)].map((_, i) => (
-
- ))}
-
- ) : (
-
- )}
-
-
-);
-
-const MiniSkeletonTable = ({ rows = 8, colorScheme = "orange" }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {[...Array(rows)].map((_, i) => (
-
-
-
-
-
-
-
-
-
-
-
- ))}
-
-
-
-);
+// Helper to map metric to colorVariant
+const getColorVariant = (metric) => {
+ switch (metric) {
+ case 'revenue': return 'emerald';
+ case 'orders': return 'blue';
+ case 'average_order': return 'violet';
+ case 'shipping': return 'orange';
+ default: return 'default';
+ }
+};
const MiniStatCards = ({
timeRange: initialTimeRange = "today",
@@ -421,101 +260,16 @@ const MiniStatCards = ({
if (loading && !stats) {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
);
}
if (error) {
- return (
-
-
- Error
- Failed to load stats: {error}
-
- );
+ return ;
}
if (!stats) return null;
@@ -527,100 +281,68 @@ const MiniStatCards = ({
return (
<>
-
- Proj:
- {projectionLoading ? (
-
-
-
- ) : (
- formatCurrency(
- projection?.projectedRevenue || stats.projectedRevenue
- )
- )}
-
- ) : null
+ stats?.periodProgress < 100
+ ? `Proj: ${formatCurrency(projection?.projectedRevenue || stats.projectedRevenue)}`
+ : undefined
}
- progress={stats?.periodProgress < 100 ? stats.periodProgress : undefined}
- trend={projectionLoading && stats?.periodProgress < 100 ? undefined : revenueTrend?.trend}
- trendValue={
- projectionLoading && stats?.periodProgress < 100 ? (
-
-
-
-
- ) : revenueTrend?.value ? (
- formatPercentage(revenueTrend.value)
- ) : null
+ trend={
+ revenueTrend?.trend && !projectionLoading
+ ? { direction: revenueTrend.trend, value: formatPercentage(revenueTrend.value) }
+ : undefined
}
- colorClass="text-emerald-200"
- titleClass="text-emerald-100 font-bold text-md"
- descriptionClass="text-emerald-200 text-md font-semibold"
icon={DollarSign}
- iconColor="text-emerald-900"
iconBackground="bg-emerald-300"
- onDetailsClick={() => setSelectedMetric("revenue")}
- isLoading={loading || !stats}
- variant="mini"
- background="h-[150px] bg-gradient-to-br from-emerald-900 to-emerald-800"
+ gradient="emerald"
+ className="h-[150px]"
+ onClick={() => setSelectedMetric("revenue")}
/>
- setSelectedMetric("orders")}
- isLoading={loading || !stats}
- variant="mini"
- background="h-[150px] bg-gradient-to-br from-blue-900 to-blue-800"
+ gradient="blue"
+ className="h-[150px]"
+ onClick={() => setSelectedMetric("orders")}
/>
- setSelectedMetric("average_order")}
- isLoading={loading || !stats}
- variant="mini"
- background="h-[150px] bg-gradient-to-br from-violet-900 to-violet-800"
+ gradient="violet"
+ className="h-[150px]"
+ onClick={() => setSelectedMetric("average_order")}
/>
- setSelectedMetric("shipping")}
- isLoading={loading || !stats}
- variant="mini"
- background="h-[150px] bg-gradient-to-br from-orange-900 to-orange-800"
+ gradient="orange"
+ className="h-[150px]"
+ onClick={() => setSelectedMetric("shipping")}
/>
@@ -633,7 +355,7 @@ const MiniStatCards = ({
selectedMetric === 'orders' ? 'bg-blue-50 dark:bg-blue-950/30' :
selectedMetric === 'average_order' ? 'bg-violet-50 dark:bg-violet-950/30' :
selectedMetric === 'shipping' ? 'bg-orange-50 dark:bg-orange-950/30' :
- 'bg-white dark:bg-gray-950'
+ 'bg-card'
} backdrop-blur-md border-none`}>
@@ -657,20 +379,18 @@ const MiniStatCards = ({
{detailDataLoading[selectedMetric] ? (
{selectedMetric === "shipping" ? (
-
) : (
<>
-
{selectedMetric === "orders" && (
@@ -683,7 +403,12 @@ const MiniStatCards = ({
}`}>
Hourly Distribution
-
+
)}
>
diff --git a/inventory/src/components/dashboard/Navigation.jsx b/inventory/src/components/dashboard/Navigation.jsx
index 6ea25ed..15d88d3 100644
--- a/inventory/src/components/dashboard/Navigation.jsx
+++ b/inventory/src/components/dashboard/Navigation.jsx
@@ -226,7 +226,7 @@ const Navigation = () => {
>
{
))}
-
+
| |