"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.
)}
)
}