diff --git a/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx b/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
index 06fa25a..fa7df76 100644
--- a/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
+++ b/dashboard/src/components/dashboard/KlaviyoCampaigns.jsx
@@ -1,5 +1,4 @@
-import React, { useState, useEffect } from "react";
-import axios from "axios";
+import React, { useState, useEffect, useRef } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Tooltip,
@@ -8,24 +7,6 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { DateTime } from "luxon";
-import { Loader2, AlertCircle } from "lucide-react";
-import {
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@/components/ui/table";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
-import { TIME_RANGES } from "@/lib/constants";
// Helper functions for formatting
const formatRate = (value) => {
@@ -55,6 +36,13 @@ const TableSkeleton = () => (
);
+// Error alert component
+const ErrorAlert = ({ description }) => (
+
+ {description}
+
+);
+
// MetricCell component for displaying campaign metrics
const MetricCell = ({
value,
@@ -76,45 +64,58 @@ const MetricCell = ({
);
-const KlaviyoCampaigns = ({
- className,
- timeRange = "last7days",
- onTimeRangeChange,
- title = "Email Campaigns",
- description
-}) => {
+const KlaviyoCampaigns = ({ className, timeRange = "last7days" }) => {
const [campaigns, setCampaigns] = useState([]);
- const [loading, setLoading] = useState(true);
+ const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
- const [selectedTimeRange, setSelectedTimeRange] = useState(timeRange);
-
- useEffect(() => {
- fetchCampaigns();
- }, [selectedTimeRange]);
+ const [searchTerm, setSearchTerm] = useState("");
+ const [sortConfig, setSortConfig] = useState({
+ key: "send_time",
+ direction: "desc",
+ });
const fetchCampaigns = async () => {
try {
- setLoading(true);
+ setIsLoading(true);
+ const response = await fetch(`/api/klaviyo/reporting/campaigns/${timeRange}`);
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch campaigns: ${response.status}`);
+ }
+
+ const data = await response.json();
+ setCampaigns(data.data || []);
setError(null);
-
- const response = await axios.get(`/api/klaviyo/reporting/campaigns/${selectedTimeRange}`);
- setCampaigns(response.data.data || []);
- } catch (error) {
- console.error("Error fetching campaigns:", error);
- setError(error.message);
+ } catch (err) {
+ console.error("Error fetching campaigns:", err);
+ setError(err.message);
} finally {
- setLoading(false);
+ setIsLoading(false);
}
};
- const handleTimeRangeChange = (value) => {
- setSelectedTimeRange(value);
- if (onTimeRangeChange) {
- onTimeRangeChange(value);
- }
- };
+ useEffect(() => {
+ fetchCampaigns();
+ const interval = setInterval(fetchCampaigns, 10 * 60 * 1000); // Refresh every 10 minutes
+ return () => clearInterval(interval);
+ }, [timeRange]);
- if (loading) {
+ // Sort campaigns
+ const sortedCampaigns = [...campaigns].sort((a, b) => {
+ const direction = sortConfig.direction === "desc" ? -1 : 1;
+ if (sortConfig.key === "send_time") {
+ return direction * (DateTime.fromISO(a.send_time) - DateTime.fromISO(b.send_time));
+ }
+ return direction * (a[sortConfig.key] - b[sortConfig.key]);
+ });
+
+ // Filter campaigns by search term
+ const filteredCampaigns = sortedCampaigns.filter(
+ (campaign) =>
+ campaign?.name?.toLowerCase().includes((searchTerm || "").toLowerCase())
+ );
+
+ if (isLoading) {
return (
@@ -129,85 +130,73 @@ const KlaviyoCampaigns = ({
return (
- {error && (
-
-
- Error
- Failed to load campaigns: {error}
-
- )}
+ {error && }
-
-
- {title}
-
-
-
+
+ Email Campaigns
+
-
-
-
-
- Campaign
- Delivery
- Opens
- Clicks
- Orders
-
-
-
- {campaigns.map((campaign) => (
-
-
-
-
-
-
-
- {campaign.name || "Unnamed Campaign"}
-
-
- {campaign.subject || "No subject"}
-
-
- {campaign.send_time
- ? DateTime.fromISO(campaign.send_time).toLocaleString(
- DateTime.DATETIME_MED
- )
- : "No date"}
-
+
+
+
+
+ |
+ Campaign
+ |
+
+ Delivery
+ |
+
+ Opens
+ |
+
+ Clicks
+ |
+
+ CTR
+ |
+
+ Orders
+ |
+
+
+
+ {filteredCampaigns.map((campaign) => (
+
+
+
+
+ |
+
+ {campaign.name}
-
-
-
- {campaign.name || "Unnamed Campaign"}
-
- {campaign.subject || "No subject"}
-
+
+ {campaign.subject}
+
+
{campaign.send_time
- ? DateTime.fromISO(campaign.send_time).toLocaleString(
- DateTime.DATETIME_MED
- )
+ ? DateTime.fromISO(campaign.send_time).toLocaleString(DateTime.DATETIME_MED)
: "No date"}
-
-
-
-
-
+
+ |
+
+
+ {campaign.name}
+ {campaign.subject}
+
+ {campaign.send_time
+ ? DateTime.fromISO(campaign.send_time).toLocaleString(DateTime.DATETIME_MED)
+ : "No date"}
+
+
+
+
+
-
+
))}
-
-
+
+
);