diff --git a/dashboard/src/components/dashboard/AircallDashboard.jsx b/dashboard/src/components/dashboard/AircallDashboard.jsx
index 663c6bf..cdb7480 100644
--- a/dashboard/src/components/dashboard/AircallDashboard.jsx
+++ b/dashboard/src/components/dashboard/AircallDashboard.jsx
@@ -65,6 +65,7 @@ const COLORS = {
missed: "hsl(47.9 95.8% 53.1%)", // Yellow
answered: "hsl(142.1 76.2% 36.3%)", // Green
duration: "hsl(221.2 83.2% 53.3%)", // Blue
+ hourly: "hsl(321.2 81.1% 41.2%)", // Pink
};
const TIME_RANGES = [
@@ -89,10 +90,7 @@ const formatDuration = (seconds) => {
};
const MetricCard = ({ title, value, subtitle, icon: Icon, iconColor }) => (
-
-
-
-
+
{title}
@@ -104,12 +102,6 @@ const MetricCard = ({ title, value, subtitle, icon: Icon, iconColor }) => (
)}
-
-
- {title}
-
-
-
);
const CustomTooltip = ({ active, payload, label }) => {
@@ -130,39 +122,7 @@ const CustomTooltip = ({ active, payload, label }) => {
return null;
};
-export const exportToCSV = (data, filename) => {
- const headers = [
- "Name",
- "Total Calls",
- "Answered",
- "Missed",
- "Answer Rate",
- "Avg Duration",
- ];
- const rows = data.map((agent) => [
- agent.name,
- agent.total,
- agent.answered,
- agent.missed,
- `${((agent.answered / agent.total) * 100).toFixed(1)}%`,
- formatDuration(agent.average_duration),
- ]);
- const csvContent = [
- headers.join(","),
- ...rows.map((row) => row.join(",")),
- ].join("\n");
-
- const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
- const link = document.createElement("a");
- const url = URL.createObjectURL(blob);
- link.setAttribute("href", url);
- link.setAttribute("download", `${filename}.csv`);
- link.style.visibility = "hidden";
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-};
const AgentPerformanceTable = ({ agents, onSort }) => {
const [sortConfig, setSortConfig] = useState({
@@ -179,35 +139,15 @@ const AgentPerformanceTable = ({ agents, onSort }) => {
onSort(key, direction);
};
- const SortButton = ({ column }) => (
-
- );
-
return (
Agent
-
-
-
-
-
-
-
-
-
-
-
-
+ handleSort("total")}>Total Calls
+ handleSort("answered")}>Answered
+ handleSort("missed")}>Missed
+ handleSort("average_duration")}>Average Duration
@@ -225,67 +165,6 @@ const AgentPerformanceTable = ({ agents, onSort }) => {
);
};
-const TableActions = ({ onSearch, onExport }) => {
- return (
-
-
-
-
- onSearch(e.target.value)}
- className="pl-8"
- />
-
-
-
-
- );
-};
-
-const AgentStatsCard = ({ agent, formatDuration }) => {
- const answerRate = ((agent.answered / agent.total) * 100).toFixed(1);
-
- return (
-
-
- {agent.name}
-
-
-
- Answer Rate
- {answerRate}%
-
-
-
-
-
-
Total Calls
-
{agent.total}
-
-
-
Avg Duration
-
- {formatDuration(agent.average_duration)}
-
-
-
-
Answered
-
{agent.answered}
-
-
-
Missed
-
{agent.missed}
-
-
-
-
- );
-};
-
const AircallDashboard = () => {
const [timeRange, setTimeRange] = useState("last7days");
const [metrics, setMetrics] = useState(null);
@@ -296,8 +175,6 @@ const AircallDashboard = () => {
key: "total",
direction: "desc",
});
- const [searchTerm, setSearchTerm] = useState("");
- const [viewType, setViewType] = useState("table"); // 'table' or 'cards'
const safeArray = (arr) => (Array.isArray(arr) ? arr : []);
const safeObject = (obj) => (obj && typeof obj === "object" ? obj : {});
@@ -309,10 +186,6 @@ const AircallDashboard = () => {
})
: [];
- const filteredAgents = sortedAgents.filter((agent) =>
- agent.name.toLowerCase().includes(searchTerm.toLowerCase())
- );
-
const formatDate = (dateString) => {
try {
// Parse the date string (YYYY-MM-DD)
@@ -348,7 +221,10 @@ const AircallDashboard = () => {
const chartData = {
hourly: metrics?.by_hour
? metrics.by_hour.map((count, hour) => ({
- hour: `${hour.toString().padStart(2, "0")}:00`,
+ hour: new Date(2000, 0, 1, hour).toLocaleString('en-US', {
+ hour: 'numeric',
+ hour12: true
+ }).toUpperCase(),
calls: count || 0,
}))
: [],
@@ -364,7 +240,10 @@ const AircallDashboard = () => {
...day,
inbound: day.inbound || 0,
outbound: day.outbound || 0,
- date: day.date || "",
+ date: new Date(day.date).toLocaleString('en-US', {
+ month: 'short',
+ day: 'numeric'
+ }),
})),
};
@@ -432,299 +311,195 @@ const AircallDashboard = () => {
-
+
{/* Metric Cards */}
-
+
{isLoading ? (
- [...Array(6)].map((_, i) => (
+ [...Array(4)].map((_, i) => (
))
) : metrics ? (
<>
-
-
-
-
-
-
+
+
+ Total Calls
+ {metrics.total}
+
+
+ ↑ {metrics.by_direction.inbound} inbound
+
+
+ ↓ {metrics.by_direction.outbound} outbound
+
+
+
+
+
+
+ Answer Rate
+
+ {`${((metrics.by_status.answered / metrics.total) * 100).toFixed(1)}%`}
+
+
+
+ {metrics.by_status.answered} answered
+
+
+ {metrics.by_status.missed} missed
+
+
+
+
+
+
+ Peak Hour
+
+ {metrics?.by_hour ? new Date(2000, 0, 1, metrics.by_hour.indexOf(Math.max(...metrics.by_hour))).toLocaleString('en-US', { hour: 'numeric', hour12: true }).toUpperCase() : 'N/A'}
+
+
+ Busiest Agent: {sortedAgents[0]?.name || "N/A"}
+
+
+
+
+
+ Avg Duration
+
+
+
+
+
+ {formatDuration(metrics.average_duration)}
+
+
+ {metrics?.daily_data?.length > 0
+ ? `${Math.round(metrics.total / metrics.daily_data.length)} calls/day`
+ : "N/A"}
+
+
+
+
+
+
Duration Distribution
+ {metrics?.duration_distribution?.map((d, i) => (
+
+ {d.range}
+ {d.count} calls
+
+ ))}
+
+
+
+
+
+
>
) : null}
-
-
-
- Performance Summary
-
-
-
- Peak Hour
-
- {metrics?.by_hour.indexOf(Math.max(...metrics.by_hour))}:00
-
-
-
- Busiest Agent
-
- {sortedAgents[0]?.name || "N/A"}
-
-
-
- Best Answer Rate
-
- {sortedAgents
- .filter((agent) => agent.total > 0)
- .sort(
- (a, b) => b.answered / b.total - a.answered / a.total
- )[0]?.name || "N/A"}
-
-
-
-
+ {/* Charts and Tables Section */}
+
+ {/* Charts Row */}
+
+ {/* Daily Call Volume */}
+
+
+ Daily Call Volume
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
-
-
- Time Period
-
-
-
- Date Range
-
- {metrics?.daily_data?.length > 0 ? (
- <>
- {formatDate(metrics.daily_data[0]?.date)} -{" "}
- {formatDate(
- metrics.daily_data[metrics.daily_data.length - 1]?.date
- )}
- >
- ) : (
- "No data available"
- )}
-
-
-
- Avg Daily Calls
-
- {metrics?.daily_data?.length > 0
- ? Math.round(metrics.total / metrics.daily_data.length)
- : "N/A"}
-
-
-
- Avg Duration
-
- {metrics?.average_duration
- ? formatDuration(metrics.average_duration)
- : "N/A"}
-
-
-
-
+ {/* Hourly Distribution */}
+
+
+ Hourly Distribution
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+ {/* Tables Row */}
+
+ {/* Agent Performance */}
+
+
+ Agent Performance
+
+
+ setAgentSort({ key, direction })}
+ />
+
+
+
+ {/* Missed Call Reasons Table */}
+
+
+ Missed Call Reasons
+
+
+
+
+
+ Reason
+ Count
+
+
+
+ {chartData.missedReasons.map((reason, index) => (
+
+
+ {reason.reason}
+
+
+ {reason.count}
+
+
+ ))}
+
+
+
+
+
-
- {/* Charts */}
-
- {/* Daily Call Volume */}
-
-
- Daily Call Volume
-
-
-
-
-
-
-
- } />
-
-
-
-
-
-
-
-
- {/* Duration Distribution */}
-
-
- Call Duration Distribution
-
-
-
-
-
-
-
- } />
-
-
-
-
-
-
- {/* Missed Call Reasons */}
-
-
- Missed Call Reasons
-
-
-
-
-
-
-
- } />
-
-
-
-
-
-
- {/* Hourly Distribution */}
-
-
- Hourly Distribution
-
-
-
-
-
-
-
- } />
-
-
-
-
-
-
-
- {/* Agent Performance */}
-
-
-
-
Agent Performance
-
-
-
-
-
-
-
-
-
- {viewType === "table" ? (
- setAgentSort({ key, direction })}
- />
- ) : (
-
- {filteredAgents.map((agent) => (
-
- ))}
-
- )}
-
-