"use client" import { useState } from 'react' import { Bell, CheckCircle, XCircle, Clock, Loader2, ChevronDown, ChevronUp, X } from 'lucide-react' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { useTask, Task } from '@/contexts/task-context' export function TaskNotificationMenu() { const { tasks, isFetching, isMenuOpen, cancelTask } = useTask() const [isExpanded, setIsExpanded] = useState(false) // Don't render if menu is closed if (!isMenuOpen) return null const activeTasks = tasks.filter(task => task.status === 'pending' || task.status === 'running' || task.status === 'processing' ) const recentTasks = tasks.filter(task => task.status === 'completed' || task.status === 'failed' || task.status === 'error' ).slice(0, 5) // Show last 5 completed/failed tasks const getTaskIcon = (status: Task['status']) => { switch (status) { case 'completed': return case 'failed': case 'error': return case 'pending': return case 'running': case 'processing': return default: return } } const getStatusBadge = (status: Task['status']) => { switch (status) { case 'completed': return Completed case 'failed': case 'error': return Failed case 'pending': return Pending case 'running': case 'processing': return Processing default: return Unknown } } const formatTaskProgress = (task: Task) => { const total = task.total_files || 0 const processed = task.processed_files || 0 const successful = task.successful_files || 0 const failed = task.failed_files || 0 if (total > 0) { return { basic: `${processed}/${total} files`, detailed: { total, processed, successful, failed, remaining: total - processed } } } return null } const formatRelativeTime = (dateString: string) => { // Handle different timestamp formats let date: Date // If it's a number (Unix timestamp), convert it if (/^\d+$/.test(dateString)) { const timestamp = parseInt(dateString) // If it looks like seconds (less than 10^13), convert to milliseconds date = new Date(timestamp < 10000000000 ? timestamp * 1000 : timestamp) } // If it's a decimal number (Unix timestamp with decimals) else if (/^\d+\.\d+$/.test(dateString)) { const timestamp = parseFloat(dateString) // Convert seconds to milliseconds date = new Date(timestamp * 1000) } // Otherwise, try to parse as ISO string or other date format else { date = new Date(dateString) } // Check if date is valid if (isNaN(date.getTime())) { console.warn('Invalid date format:', dateString) return 'Unknown time' } const now = new Date() const diffMs = now.getTime() - date.getTime() const diffMinutes = Math.floor(diffMs / 60000) const diffHours = Math.floor(diffMs / 3600000) const diffDays = Math.floor(diffMs / 86400000) if (diffMinutes < 1) return 'Just now' if (diffMinutes < 60) return `${diffMinutes}m ago` if (diffHours < 24) return `${diffHours}h ago` return `${diffDays}d ago` } return (
{/* Header */}

Tasks

{isFetching && ( )}
{activeTasks.length > 0 && ( {activeTasks.length} )}
{/* Content */}
{/* Active Tasks */} {activeTasks.length > 0 && (

Active Tasks

{activeTasks.map((task) => (
{getTaskIcon(task.status)} Task {task.task_id.substring(0, 8)}...
Started {formatRelativeTime(task.created_at)}
{formatTaskProgress(task) && (
Progress: {formatTaskProgress(task)?.basic}
{formatTaskProgress(task)?.detailed && (
{formatTaskProgress(task)?.detailed.successful} success
{formatTaskProgress(task)?.detailed.failed} failed
{formatTaskProgress(task)?.detailed.remaining} pending
)}
{/* Cancel button in bottom right */} {(task.status === 'pending' || task.status === 'running' || task.status === 'processing') && (
)}
)} {/* Cancel button for tasks without progress */} {!formatTaskProgress(task) && (task.status === 'pending' || task.status === 'running' || task.status === 'processing') && (
)}
))}
)} {/* Recent Tasks */} {recentTasks.length > 0 && (

Recent Tasks

{isExpanded && (
{recentTasks.map((task) => (
{getTaskIcon(task.status)}
Task {task.task_id.substring(0, 8)}...
{formatRelativeTime(task.updated_at)}
{/* Show final results for completed tasks */} {task.status === 'completed' && formatTaskProgress(task)?.detailed && (
{formatTaskProgress(task)?.detailed.successful} success, {' '} {formatTaskProgress(task)?.detailed.failed} failed
)} {task.status === 'failed' && task.error && (
{task.error}
)}
{getStatusBadge(task.status)}
))}
)}
)} {/* Empty State */} {activeTasks.length === 0 && recentTasks.length === 0 && (

No tasks yet

Task notifications will appear here when you upload files or sync connectors.

)}
) }