'use client'; import { useState, useEffect, useCallback } from 'react'; import { Box, TextField, Select, MenuItem, FormControl, InputLabel, Card, CardContent, Alert, Chip, IconButton, Tooltip, Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Paper, Divider, Accordion, AccordionSummary, AccordionDetails } from '@mui/material'; import { DataGrid, GridColDef, GridActionsCellItem, GridRowParams, GridPaginationModel } from '@mui/x-data-grid'; import { Visibility, Block, CheckCircle, Delete, Person, Chat, Schedule, Warning, ExpandMore } from '@mui/icons-material'; interface Conversation { id: string; title: string; language: string; isActive: boolean; createdAt: string; updatedAt: string; lastMessageAt: string; user: { id: string; email: string; name: string | null; role: string; } | null; _count: { messages: number; }; messages: Array<{ id: string; role: string; content: string; timestamp: string; }>; } interface ConversationStats { total: number; active: number; inactive: number; today: number; thisWeek: number; } interface ConversationDetailModalProps { conversationId: string | null; open: boolean; onClose: () => void; onConversationUpdate: (conversationId: string, action: string) => void; } function ConversationDetailModal({ conversationId, open, onClose, onConversationUpdate }: ConversationDetailModalProps) { const [conversation, setConversation] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { if (conversationId && open) { const fetchConversation = async () => { setLoading(true); try { const response = await fetch(`/api/admin/chat/conversations/${conversationId}`, { credentials: 'include' }); if (response.ok) { const data = await response.json(); setConversation(data); } } catch (error) { console.error('Error fetching conversation:', error); } finally { setLoading(false); } }; fetchConversation(); } }, [conversationId, open]); const handleAction = async (action: string) => { if (!conversationId) return; try { const response = await fetch(`/api/admin/chat/conversations/${conversationId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ action }) }); if (response.ok) { onConversationUpdate(conversationId, action); onClose(); } } catch (error) { console.error('Error updating conversation:', error); } }; const formatDuration = (milliseconds: number) => { const minutes = Math.floor(milliseconds / 60000); const hours = Math.floor(minutes / 60); if (hours > 0) { return `${hours}h ${minutes % 60}m`; } return `${minutes}m`; }; return ( Conversation Details {loading ? ( Loading... ) : conversation ? ( {/* Conversation Info */} {conversation.conversation.title} {conversation.conversation.user && ( User Information Name: {conversation.conversation.user.name || 'Unknown'} Email: {conversation.conversation.user.email} Role: {conversation.conversation.user.role} )} {/* Analysis */} Conversation Analysis Total Messages {conversation.analysis.messageCount} User Messages {conversation.analysis.userMessages} Duration {formatDuration(conversation.analysis.duration)} Avg Message Length {Math.round(conversation.analysis.averageMessageLength)} {/* Potential Issues */} {conversation.analysis.potentialIssues.length > 0 && ( Potential Issues {conversation.analysis.potentialIssues.map((issue: string, index: number) => ( {issue} ))} )} {/* Messages */} Messages ({conversation.conversation.messages.length}) {conversation.conversation.messages.map((message: any, index: number) => ( }> {message.content.substring(0, 100)}... {new Date(message.timestamp).toLocaleString()} {message.content} ))} {/* Actions */} {conversation.conversation.isActive ? ( ) : ( )} ) : ( Conversation not found )} ); } export function ConversationMonitoring() { const [conversations, setConversations] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [paginationModel, setPaginationModel] = useState({ page: 0, pageSize: 10, }); const [rowCount, setRowCount] = useState(0); const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [languageFilter, setLanguageFilter] = useState('all'); const [sortBy, setSortBy] = useState('lastMessage'); const [selectedConversationId, setSelectedConversationId] = useState(null); const [modalOpen, setModalOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [conversationToDelete, setConversationToDelete] = useState(null); const fetchConversations = useCallback(async () => { setLoading(true); try { const params = new URLSearchParams({ page: paginationModel.page.toString(), pageSize: paginationModel.pageSize.toString(), search, status: statusFilter, language: languageFilter, sortBy }); const response = await fetch(`/api/admin/chat/conversations?${params}`, { credentials: 'include' }); if (response.ok) { const data = await response.json(); setConversations(data.conversations); setStats(data.stats); setRowCount(data.pagination.total); } else { setError('Failed to load conversations'); } } catch (error) { setError('Network error loading conversations'); } finally { setLoading(false); } }, [paginationModel, search, statusFilter, languageFilter, sortBy]); useEffect(() => { fetchConversations(); }, [fetchConversations]); const handleConversationUpdate = useCallback((conversationId: string, action: string) => { fetchConversations(); }, [fetchConversations]); const handleViewConversation = (params: GridRowParams) => { setSelectedConversationId(params.id as string); setModalOpen(true); }; const handleDeleteConversation = (params: GridRowParams) => { setConversationToDelete(params.row as Conversation); setDeleteDialogOpen(true); }; const confirmDeleteConversation = async () => { if (!conversationToDelete) return; try { const response = await fetch(`/api/admin/chat/conversations/${conversationToDelete.id}`, { method: 'DELETE', credentials: 'include' }); if (response.ok) { fetchConversations(); setDeleteDialogOpen(false); setConversationToDelete(null); } } catch (error) { console.error('Error deleting conversation:', error); } }; const getStatusChip = (isActive: boolean) => { return ( ); }; const columns: GridColDef[] = [ { field: 'title', headerName: 'Conversation', flex: 1, minWidth: 250, renderCell: (params) => ( {params.value} {params.row.user?.name || params.row.user?.email || 'Anonymous'} ) }, { field: 'language', headerName: 'Language', width: 100, renderCell: (params) => ( ) }, { field: '_count', headerName: 'Messages', width: 100, align: 'center', headerAlign: 'center', renderCell: (params) => params.value.messages }, { field: 'isActive', headerName: 'Status', width: 100, renderCell: (params) => getStatusChip(params.value) }, { field: 'lastMessageAt', headerName: 'Last Activity', width: 140, renderCell: (params) => { const date = new Date(params.value); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMins / 60); const diffDays = Math.floor(diffHours / 24); let timeAgo = ''; if (diffDays > 0) { timeAgo = `${diffDays}d ago`; } else if (diffHours > 0) { timeAgo = `${diffHours}h ago`; } else { timeAgo = `${diffMins}m ago`; } return ( {timeAgo} ); } }, { field: 'user', headerName: 'User', width: 120, renderCell: (params) => ( {params.value?.role || 'Anonymous'} ) }, { field: 'actions', type: 'actions', headerName: 'Actions', width: 120, getActions: (params) => [ } label="View" onClick={() => handleViewConversation(params)} />, } label="Delete" onClick={() => handleDeleteConversation(params)} /> ] } ]; return ( {/* Statistics Cards */} {stats && ( Total Conversations {stats.total} Active {stats.active} Today {stats.today} This Week {stats.thisWeek} )} {/* Filters */} setSearch(e.target.value)} size="small" sx={{ minWidth: 250 }} /> Status Language Sort By {error && ( {error} )} {/* Data Grid */} {/* Conversation Detail Modal */} setModalOpen(false)} onConversationUpdate={handleConversationUpdate} /> {/* Delete Confirmation Dialog */} setDeleteDialogOpen(false)} maxWidth="sm" fullWidth > Delete Conversation Are you sure you want to delete the conversation "{conversationToDelete?.title}"? This action cannot be undone. All messages in this conversation will be permanently deleted. ); }