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) => ( - - ))} -
- )} -
-