"use client"; import { useEffect, useState } from "react"; import { signOut, useSession } from "next-auth/react"; import { SessionsLineChart, CategoriesBarChart, LanguagePieChart, TokenUsageChart, } from "../../components/Charts"; import DashboardSettings from "./settings"; import UserManagement from "./users"; import { Company, MetricsResult } from "../../lib/types"; import MetricCard from "../../components/MetricCard"; import DonutChart from "../../components/DonutChart"; import WordCloud from "../../components/WordCloud"; import GeographicMap from "../../components/GeographicMap"; import ResponseTimeDistribution from "../../components/ResponseTimeDistribution"; import WelcomeBanner from "../../components/WelcomeBanner"; // Safely wrapped component with useSession function DashboardContent() { const { data: session } = useSession(); const [metrics, setMetrics] = useState(null); const [company, setCompany] = useState(null); const [, setLoading] = useState(false); // Remove unused csvUrl state variable const [refreshing, setRefreshing] = useState(false); const isAdmin = session?.user?.role === "admin"; const isAuditor = session?.user?.role === "auditor"; useEffect(() => { // Fetch metrics and company on mount const fetchData = async () => { setLoading(true); const res = await fetch("/api/dashboard/metrics"); const data = await res.json(); setMetrics(data.metrics); setCompany(data.company); // Removed unused csvUrl assignment setLoading(false); }; fetchData(); }, []); async function handleRefresh() { if (isAuditor) return; // Prevent auditors from refreshing try { setRefreshing(true); // Make sure we have a company ID to send if (!company?.id) { // Use a more appropriate error handling approach setRefreshing(false); alert("Cannot refresh: Company ID is missing"); return; } const res = await fetch("/api/admin/refresh-sessions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ companyId: company.id }), }); if (res.ok) { // Refetch metrics const metricsRes = await fetch("/api/dashboard/metrics"); const data = await metricsRes.json(); setMetrics(data.metrics); } else { const errorData = await res.json(); // Use alert instead of console.error for user feedback alert(`Failed to refresh sessions: ${errorData.error}`); } } finally { setRefreshing(false); } } // Calculate sentiment distribution const getSentimentData = () => { if (!metrics) return { positive: 0, neutral: 0, negative: 0 }; // If we have the new sentiment count fields, use those if ( metrics.sentimentPositiveCount !== undefined && metrics.sentimentNeutralCount !== undefined && metrics.sentimentNegativeCount !== undefined ) { return { positive: metrics.sentimentPositiveCount, neutral: metrics.sentimentNeutralCount, negative: metrics.sentimentNegativeCount, }; } // Fallback to estimating based on total const total = metrics.totalSessions || 1; return { positive: Math.round(total * 0.6), // 60% positive as fallback neutral: Math.round(total * 0.3), // 30% neutral as fallback negative: Math.round(total * 0.1), // 10% negative as fallback }; }; // Prepare token usage data const getTokenData = () => { if (!metrics || !metrics.tokensByDay) { return { labels: [], values: [], costs: [] }; } const days = Object.keys(metrics.tokensByDay).sort(); // Get the last 7 days if available const labels = days.slice(-7); const values = labels.map((day) => metrics.tokensByDay?.[day] || 0); const costs = labels.map((day) => metrics.tokensCostByDay?.[day] || 0); return { labels, values, costs }; }; if (!metrics || !company) { return
Loading dashboard...
; } // Function to prepare word cloud data from categories const getWordCloudData = () => { if (!metrics || !metrics.categories) return []; return Object.entries(metrics.categories) .map(([text, value]) => ({ text, value })) .filter((item) => item.text.trim() !== "") .sort((a, b) => b.value - a.value) .slice(0, 30); // Limit to top 30 categories }; // Function to prepare country data for the map - using simulated/dummy data const getCountryData = () => { // Use dummy country data as the actual metrics doesn't contain session-level country data return { US: 42, GB: 25, DE: 18, FR: 15, CA: 12, AU: 10, JP: 8, BR: 6, IN: 5, ZA: 3, ES: 7, NL: 9, IT: 6, SE: 4, }; }; // Function to prepare response time distribution data const getResponseTimeData = () => { // Since we have aggregated avgResponseTime, we'll create a simulated distribution // based on the average response time const avgTime = metrics.avgResponseTime || 1.5; const simulatedData: number[] = []; // Generate response times that average to our avgResponseTime for (let i = 0; i < 50; i++) { // Random value that's mostly close to the average const randomFactor = 0.5 + Math.random(); simulatedData.push(avgTime * randomFactor); } return simulatedData; }; return (
{" "} {/* Increased spacing */} {/* Welcome Banner */} {/* Header with company info */}

{company.name}

{" "} {/* Adjusted text color and margin */} Dashboard updated{" "} {" "} {/* Adjusted text color */} {new Date(metrics.lastUpdated || Date.now()).toLocaleString()}

{" "} {/* Adjusted gap and responsive margin */}
{/* Key Performance Metrics */}
{/* Sentiment & Escalation Metrics */}

Sentiment Distribution

Case Handling Statistics

metrics.totalSessions * 0.1 ? "warning" : "success" } /> metrics.totalSessions * 0.05 ? "warning" : "default" } />
{/* Charts Row */}

Sessions by Day

Top Categories

{/* Word Cloud and World Map */}

Categories Word Cloud

Geographic Distribution

{/* Response Time Distribution and Language Distribution */}

Response Time Distribution

Languages

{/* Token Usage */}

Token Usage & Costs

Total Tokens: {metrics.totalTokens?.toLocaleString() || 0}
Total Cost:€ {metrics.totalTokensEur?.toFixed(4) || 0}
{/* Admin Controls */} {isAdmin && ( <> )}
); } // Our exported component export default function DashboardPage() { // We don't use useSession here to avoid the error outside the provider return (
{" "} {/* Added gradient background */}
{" "} {/* Added inner container for content alignment */}
); }