import React, { useState, useEffect, useCallback } from "react";
import gorgiasService from "../../services/gorgiasService";
import { getDateRange } from "../../utils/dateUtils";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import {
Select,
SelectTrigger,
SelectContent,
SelectItem,
} from "@/components/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Skeleton } from "@/components/ui/skeleton";
import { Clock, Star, Users, MessageSquare, Mail, Send } from "lucide-react";
const TIME_RANGES = {
7: "Last 7 Days",
14: "Last 14 Days",
30: "Last 30 Days",
90: "Last 90 Days",
};
const formatDuration = (seconds) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
};
const MetricCard = ({
title,
value,
delta,
suffix = "",
icon: Icon,
colorClass = "blue",
more_is_better = true,
loading = false,
}) => {
const getDeltaColor = (d) => {
if (d === 0) return "text-gray-600 dark:text-gray-400";
const isPositive = d > 0;
return isPositive === more_is_better
? "text-green-600 dark:text-green-500"
: "text-red-600 dark:text-red-500";
};
const formatDelta = (d) => {
if (d === undefined || d === null) return null;
if (d === 0) return "0";
return (d > 0 ? "+" : "") + d + suffix;
};
const colorMapping = {
blue: "bg-blue-50 dark:bg-blue-900/20 border-blue-100 dark:border-blue-800/50 text-blue-600 dark:text-blue-400",
green:
"bg-green-50 dark:bg-green-900/20 border-green-100 dark:border-green-800/50 text-green-600 dark:text-green-400",
purple:
"bg-purple-50 dark:bg-purple-900/20 border-purple-100 dark:border-purple-800/50 text-purple-600 dark:text-purple-400",
indigo:
"bg-indigo-50 dark:bg-indigo-900/20 border-indigo-100 dark:border-indigo-800/50 text-indigo-600 dark:text-indigo-400",
orange:
"bg-orange-50 dark:bg-orange-900/20 border-orange-100 dark:border-orange-800/50 text-orange-600 dark:text-orange-400",
teal: "bg-teal-50 dark:bg-teal-900/20 border-teal-100 dark:border-teal-800/50 text-teal-600 dark:text-teal-400",
cyan: "bg-cyan-50 dark:bg-cyan-900/20 border-cyan-100 dark:border-cyan-800/50 text-cyan-600 dark:text-cyan-400",
};
const baseColors = colorMapping[colorClass];
return (
{title}
{loading ? (
) : (
<>
{Icon &&
}
{typeof value === "number"
? value.toLocaleString() + suffix
: value}
{delta !== undefined && (
{formatDelta(delta)}
)}
>
)}
);
};
const TableSkeleton = () => (
);
const GorgiasSummary = () => {
const [timeRange, setTimeRange] = useState(7);
const [data, setData] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const loadStats = useCallback(async () => {
setLoading(true);
const filters = getDateRange(timeRange);
try {
const [overview, channelStats, agentStats, satisfaction, selfService] =
await Promise.all([
gorgiasService.fetchStatistics("overview", filters),
gorgiasService.fetchStatistics(
"tickets-created-per-channel",
filters
),
gorgiasService.fetchStatistics("tickets-closed-per-agent", filters),
gorgiasService.fetchStatistics("satisfaction-surveys", filters),
gorgiasService.fetchStatistics("self-service-overview", filters),
]);
setData({
overview: overview.data.data.data || [],
channels: channelStats.data.data.data.lines || [],
agents: agentStats.data.data.data.lines || [],
satisfaction: satisfaction.data.data.data || [],
selfService: selfService.data.data.data || [],
});
setError(null);
} catch (err) {
console.error("Error loading stats:", err);
setError(err.message);
} finally {
setLoading(false);
}
}, [timeRange]);
useEffect(() => {
loadStats();
// Set up auto-refresh every 5 minutes
const interval = setInterval(loadStats, 5 * 60 * 1000);
return () => clearInterval(interval);
}, [loadStats]);
// Convert overview array to object for easier access
const stats =
data.overview?.reduce((acc, item) => {
acc[item.name] = item;
return acc;
}, {}) || {};
// Process satisfaction data
const satisfactionStats =
data.satisfaction?.reduce((acc, item) => {
acc[item.name] = item;
return acc;
}, {}) || {};
// Process self-service data
const selfServiceStats =
data.selfService?.reduce((acc, item) => {
acc[item.name] = item;
return acc;
}, {}) || {};
if (error) return Error: {error}
;
return (
Customer Service
{/* Message & Response Metrics */}
{/* Satisfaction & Efficiency */}
{/* Channel Distribution */}
Channel Distribution
{loading ? (
) : (
Channel
Total
%
Δ
{data.channels
.sort((a, b) => b[1].value - a[1].value)
.map((line, index) => (
{line[0].value}
{line[1].value}
{line[2].value}%
0
? "text-green-600 dark:text-green-500"
: line[3].value < 0
? "text-red-600 dark:text-red-500"
: "dark:text-gray-300"
}`}
>
{line[3].value > 0 ? "+" : ""}
{line[3].value}
))}
)}
{/* Agent Performance - Same dark mode updates */}
Agent Performance
{loading ? (
) : (
Agent
Closed
Rating
Δ
{data.agents
.filter((line) => line[0].value !== "Unassigned")
.map((line, index) => (
{line[0].value}
{line[1].value}
{line[2].value ? `${line[2].value}/5` : "-"}
0
? "text-green-600 dark:text-green-500"
: line[4].value < 0
? "text-red-600 dark:text-red-500"
: "dark:text-gray-300"
}`}
>
{line[4].value > 0 ? "+" : ""}
{line[4].value}
))}
)}
);
};
export default GorgiasSummary;