diff --git a/dashboard/src/components/dashboard/AircallDashboard.jsx b/dashboard/src/components/dashboard/AircallDashboard.jsx
index cdb7480..dba16b5 100644
--- a/dashboard/src/components/dashboard/AircallDashboard.jsx
+++ b/dashboard/src/components/dashboard/AircallDashboard.jsx
@@ -165,6 +165,81 @@ const AgentPerformanceTable = ({ agents, onSort }) => {
);
};
+const SkeletonMetricCard = () => (
+
+
+
+
+
+
+
+
+
+
+);
+
+const SkeletonChart = ({ type = "line" }) => (
+
+
+
+ {type === "bar" ? (
+
+ {[...Array(24)].map((_, i) => (
+
+ ))}
+
+ ) : (
+
+ {[...Array(5)].map((_, i) => (
+
+ ))}
+
+
+ )}
+
+
+
+);
+
+const SkeletonTable = ({ rows = 5 }) => (
+
+
+
+
+
+
+
+
+
+
+
+ {[...Array(rows)].map((_, i) => (
+
+
+
+
+
+
+
+ ))}
+
+
+);
+
const AircallDashboard = () => {
const [timeRange, setTimeRange] = useState("last7days");
const [metrics, setMetrics] = useState(null);
@@ -316,7 +391,7 @@ const AircallDashboard = () => {
{isLoading ? (
[...Array(4)].map((_, i) => (
-
+
))
) : metrics ? (
<>
@@ -407,24 +482,28 @@ const AircallDashboard = () => {
Daily Call Volume
-
-
-
-
-
- } />
-
-
-
-
-
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ } />
+
+
+
+
+
+ )}
@@ -434,23 +513,27 @@ const AircallDashboard = () => {
Hourly Distribution
-
-
-
-
-
- } />
-
-
-
+ {isLoading ? (
+
+ ) : (
+
+
+
+
+
+ } />
+
+
+
+ )}
@@ -463,10 +546,14 @@ const AircallDashboard = () => {
Agent Performance
- setAgentSort({ key, direction })}
- />
+ {isLoading ? (
+
+ ) : (
+ setAgentSort({ key, direction })}
+ />
+ )}
@@ -476,26 +563,30 @@ const AircallDashboard = () => {
Missed Call Reasons
-
-
-
- Reason
- Count
-
-
-
- {chartData.missedReasons.map((reason, index) => (
-
-
- {reason.reason}
-
-
- {reason.count}
-
+ {isLoading ? (
+
+ ) : (
+
+
+
+ Reason
+ Count
- ))}
-
-
+
+
+ {chartData.missedReasons.map((reason, index) => (
+
+
+ {reason.reason}
+
+
+ {reason.count}
+
+
+ ))}
+
+
+ )}
diff --git a/dashboard/src/components/dashboard/AnalyticsDashboard.jsx b/dashboard/src/components/dashboard/AnalyticsDashboard.jsx
index 5399da6..5bb75d3 100644
--- a/dashboard/src/components/dashboard/AnalyticsDashboard.jsx
+++ b/dashboard/src/components/dashboard/AnalyticsDashboard.jsx
@@ -56,29 +56,50 @@ const SkeletonChart = () => (
clipPath: "polygon(0 50%, 100% 20%, 100% 100%, 0 100%)",
}}
/>
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
+
);
const SkeletonStats = () => (
-
+
{[...Array(4)].map((_, i) => (
-
-
-
+
+
-
-
-
+
+
+
))}
);
+const SkeletonButtons = () => (
+
+ {[...Array(4)].map((_, i) => (
+
+ ))}
+
+);
+
// Add StatCard component
const StatCard = ({
title,
@@ -264,17 +285,21 @@ export const AnalyticsDashboard = () => {
Analytics Overview
-
+ {loading ? (
+
+ ) : (
+
+ )}
{loading ? (
@@ -317,60 +342,64 @@ export const AnalyticsDashboard = () => {
) : null}
-
-
-
-
-
-
+ {loading ? (
+
+ ) : (
+
+
+
+
+
+
+ )}
diff --git a/dashboard/src/components/dashboard/EventFeed.jsx b/dashboard/src/components/dashboard/EventFeed.jsx
index 4391862..9302c3e 100644
--- a/dashboard/src/components/dashboard/EventFeed.jsx
+++ b/dashboard/src/components/dashboard/EventFeed.jsx
@@ -142,18 +142,33 @@ const formatShipMethodSimple = (method) => {
// Loading State Component
const LoadingState = () => (
-
-
- {[...Array(5)].map((_, i) => (
-
-
-
-
-
+
+ {[...Array(8)].map((_, i) => (
+
+
+
+
+
+
+ ))}
);
diff --git a/dashboard/src/components/dashboard/GorgiasOverview.jsx b/dashboard/src/components/dashboard/GorgiasOverview.jsx
index e59f876..022161c 100644
--- a/dashboard/src/components/dashboard/GorgiasOverview.jsx
+++ b/dashboard/src/components/dashboard/GorgiasOverview.jsx
@@ -111,32 +111,40 @@ const MetricCard = ({
-
{title}
{loading ? (
-
+ <>
+
+
+
+
+
+ >
) : (
-
-
- {typeof value === "number"
- ? value.toLocaleString() + suffix
- : value}
-
- {delta !== undefined && delta !== 0 && (
-
- {delta > 0 ? (
-
- ) : (
-
- )}
-
- {formatDelta(delta)}
-
-
- )}
-
+ <>
+
{title}
+
+
+ {typeof value === "number"
+ ? value.toLocaleString() + suffix
+ : value}
+
+ {delta !== undefined && delta !== 0 && (
+
+ {delta > 0 ? (
+
+ ) : (
+
+ )}
+
+ {formatDelta(delta)}
+
+
+ )}
+
+ >
)}
- {Icon && (
+ {!loading && Icon && (
)}
+ {loading && (
+
+ )}
);
};
+const SkeletonMetricCard = () => (
+
+
+
+
+
+);
+
const TableSkeleton = () => (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {[...Array(5)].map((_, i) => (
+
+
+
+
+
+
+ ))}
+
+
);
const GorgiasOverview = () => {
@@ -324,48 +366,56 @@ const GorgiasOverview = () => {
{/* Message & Response Metrics */}
-
-
-
-
-
-
-
-
-
-
-
-
+ {loading ? (
+ [...Array(8)].map((_, i) => (
+
+ ))
+ ) : (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
{/* Satisfaction & Efficiency */}
@@ -423,9 +473,7 @@ const GorgiasOverview = () => {
{loading ? (
-
+
) : (
@@ -487,9 +535,7 @@ const GorgiasOverview = () => {
{loading ? (
-
+
) : (
diff --git a/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx b/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
index 7617f48..4b2b568 100644
--- a/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
+++ b/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
@@ -17,6 +17,7 @@ import {
import { Button } from "@/components/ui/button";
import { TIME_RANGES } from "@/lib/constants";
import { Mail, MessageSquare, ArrowUpDown } from "lucide-react";
+import { Skeleton } from "@/components/ui/skeleton";
// Helper functions for formatting
const formatRate = (value, isSMS = false, hideForSMS = false) => {
@@ -37,14 +38,76 @@ const formatCurrency = (value) => {
// Loading skeleton component
const TableSkeleton = () => (
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
+
+
+
+ |
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ {[...Array(15)].map((_, i) => (
+
+ |
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+ ))}
+
+
);
// Error alert component
@@ -167,10 +230,21 @@ const KlaviyoCampaigns = ({ className }) => {
if (isLoading) {
return (
-
-
+
+
-
+
diff --git a/dashboard/src/components/dashboard/MetaCampaigns.jsx b/dashboard/src/components/dashboard/MetaCampaigns.jsx
index 00dbcc4..6998abf 100644
--- a/dashboard/src/components/dashboard/MetaCampaigns.jsx
+++ b/dashboard/src/components/dashboard/MetaCampaigns.jsx
@@ -28,6 +28,7 @@ import {
Hash,
} from "lucide-react";
import { Button } from "@/components/ui/button";
+import { Skeleton } from "@/components/ui/skeleton";
// Helper functions for formatting
const formatCurrency = (value, decimalPlaces = 2) =>
@@ -250,6 +251,63 @@ const processCampaignData = (campaign) => {
};
};
+const SkeletonMetricCard = () => (
+
+
+
+
+
+);
+
+const SkeletonTable = () => (
+
+
+
+
+
+ |
+
+ |
+ {[...Array(8)].map((_, i) => (
+
+
+ |
+ ))}
+
+
+
+ {[...Array(5)].map((_, rowIndex) => (
+
+ |
+
+
+
+
+ |
+ {[...Array(8)].map((_, colIndex) => (
+
+
+
+
+
+ |
+ ))}
+
+ ))}
+
+
+
+
+);
+
const MetaCampaigns = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -392,8 +450,28 @@ const MetaCampaigns = () => {
if (loading) {
return (
-
-
+
+
+
+ Meta Ads Performance
+
+
+
+
+ {[...Array(12)].map((_, i) => (
+
+ ))}
+
+
+
+
);
diff --git a/dashboard/src/components/dashboard/ProductGrid.jsx b/dashboard/src/components/dashboard/ProductGrid.jsx
index a406dee..2ebcbcf 100644
--- a/dashboard/src/components/dashboard/ProductGrid.jsx
+++ b/dashboard/src/components/dashboard/ProductGrid.jsx
@@ -100,59 +100,75 @@ const ProductGrid = ({
);
const SkeletonProduct = () => (
-
+
|
-
+
|
- |
-
+
|
-
+
|
-
+
|
);
const LoadingState = () => (
-
+
- |
-
-
-
-
+ | |
+
+
|
-
-
-
-
+ |
+
|
-
-
-
-
+ |
+
|
-
-
-
-
+ |
+
|
- {[...Array(10)].map((_, i) => (
+ {[...Array(20)].map((_, i) => (
))}
@@ -161,6 +177,39 @@ const ProductGrid = ({
);
+ if (loading) {
+ return (
+
+
+
+
+
+
+
+
+ {description && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
return (
@@ -230,9 +279,7 @@ const ProductGrid = ({
- {loading ? (
-
- ) : error ? (
+ {error ? (
Error
@@ -247,13 +294,13 @@ const ProductGrid = ({
Try selecting a different time range
) : (
-
+
- |
-
+ | |
+
|
-
+ |
|
-
+ |
|
-
+ |
|