From adbaa75499a63de882ea392a81d40fd1fc289a86 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 27 Dec 2024 11:29:06 -0500 Subject: [PATCH] Add missing columns and fix formatting --- .../components/dashboard/KlaviyoCampaigns.jsx | 244 +++++++++--------- 1 file changed, 119 insertions(+), 125 deletions(-) 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"} -
+ +
+ + + + + + + + + + + + {filteredCampaigns.map((campaign) => ( + + + + + + + +

{campaign.name}

+

{campaign.subject}

+

+ {campaign.send_time + ? DateTime.fromISO(campaign.send_time).toLocaleString(DateTime.DATETIME_MED) + : "No date"} +

+
+ + + - + ))} - -
+ Campaign + + Delivery + + Opens + + Clicks + + CTR + + Orders +
+
+ {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"} -

- - - - +
+
+ +
);