"use client"; import { useState, useEffect, useCallback } from "react"; import { ChatSession } from "../../../lib/types"; import Link from "next/link"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { formatCategory } from "@/lib/format-enums"; import { MessageSquare, Search, Filter, Calendar, ChevronLeft, ChevronRight, Clock, Globe, Eye, ChevronDown, ChevronUp } from "lucide-react"; // Placeholder for a SessionListItem component to be created later // For now, we'll display some basic info directly. // import SessionListItem from "../../../components/SessionListItem"; // TODO: Consider moving filter/sort types to lib/types.ts if they become complex interface FilterOptions { categories: string[]; languages: string[]; } export default function SessionsPage() { const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchTerm, setSearchTerm] = useState(""); // Filter states const [filterOptions, setFilterOptions] = useState({ categories: [], languages: [], }); const [selectedCategory, setSelectedCategory] = useState(""); const [selectedLanguage, setSelectedLanguage] = useState(""); const [startDate, setStartDate] = useState(""); const [endDate, setEndDate] = useState(""); // Sort states const [sortKey, setSortKey] = useState("startTime"); // Default sort key const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc"); // Default sort order // Debounce search term to avoid excessive API calls const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm); // Pagination states const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars const [pageSize, setPageSize] = useState(10); // Or make this configurable // UI states const [filtersExpanded, setFiltersExpanded] = useState(false); useEffect(() => { const timerId = setTimeout(() => { setDebouncedSearchTerm(searchTerm); }, 500); // 500ms delay return () => { clearTimeout(timerId); }; }, [searchTerm]); const fetchFilterOptions = useCallback(async () => { try { const response = await fetch("/api/dashboard/session-filter-options"); if (!response.ok) { throw new Error("Failed to fetch filter options"); } const data = await response.json(); setFilterOptions(data); } catch (err) { setError( err instanceof Error ? err.message : "Failed to load filter options" ); } }, []); const fetchSessions = useCallback(async () => { setLoading(true); setError(null); try { const params = new URLSearchParams(); if (debouncedSearchTerm) params.append("searchTerm", debouncedSearchTerm); if (selectedCategory) params.append("category", selectedCategory); if (selectedLanguage) params.append("language", selectedLanguage); if (startDate) params.append("startDate", startDate); if (endDate) params.append("endDate", endDate); if (sortKey) params.append("sortKey", sortKey); if (sortOrder) params.append("sortOrder", sortOrder); params.append("page", currentPage.toString()); params.append("pageSize", pageSize.toString()); const response = await fetch( `/api/dashboard/sessions?${params.toString()}` ); if (!response.ok) { throw new Error(`Failed to fetch sessions: ${response.statusText}`); } const data = await response.json(); setSessions(data.sessions || []); setTotalPages(Math.ceil((data.totalSessions || 0) / pageSize)); } catch (err) { setError( err instanceof Error ? err.message : "An unknown error occurred" ); setSessions([]); } finally { setLoading(false); } }, [ debouncedSearchTerm, selectedCategory, selectedLanguage, startDate, endDate, sortKey, sortOrder, currentPage, pageSize, ]); useEffect(() => { fetchSessions(); }, [fetchSessions]); useEffect(() => { fetchFilterOptions(); }, [fetchFilterOptions]); return (
{/* Page heading for screen readers */}

Sessions Management

{/* Header */}
Chat Sessions
{/* Search Input */}

Search Sessions

{/* Filter and Sort Controls */}
{filtersExpanded && (
Session Filters and Sorting Options
{/* Category Filter */}
Filter sessions by category type
{/* Language Filter */}
Filter sessions by language
{/* Start Date Filter */}
setStartDate(e.target.value)} aria-describedby="start-date-help" />
Filter sessions from this date onwards
{/* End Date Filter */}
setEndDate(e.target.value)} aria-describedby="end-date-help" />
Filter sessions up to this date
{/* Sort Key */}
Choose field to sort sessions by
{/* Sort Order */}
Choose ascending or descending order
)}
{/* Results section */}

Session Results

{/* Live region for screen reader announcements */}
{loading && "Loading sessions..."} {error && `Error loading sessions: ${error}`} {!loading && !error && sessions.length > 0 && `Found ${sessions.length} sessions`} {!loading && !error && sessions.length === 0 && "No sessions found"}
{/* Loading State */} {loading && ( )} {/* Error State */} {error && ( )} {/* Empty State */} {!loading && !error && sessions.length === 0 && (
{debouncedSearchTerm ? `No sessions found for "${debouncedSearchTerm}".` : "No sessions found."}
)} {/* Sessions List */} {!loading && !error && sessions.length > 0 && (
    {sessions.map((session) => (
  • Session {session.sessionId || session.id} from {new Date(session.startTime).toLocaleDateString()}

    ID {session.sessionId || session.id}
    {new Date(session.startTime).toLocaleTimeString()}
    {session.category && ( )} {session.language && ( )}
    {session.summary ? (

    {session.summary}

    ) : session.initialMsg ? (

    {session.initialMsg}

    ) : null}
  • ))}
)} {/* Pagination */} {totalPages > 0 && (
Page {currentPage} of {totalPages}
)}
); }