import React from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link } from 'react-router-dom'; import { api } from '@/lib/api'; import { __ } from '@/lib/i18n'; import { SettingsLayout } from '../components/SettingsLayout'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { ArrowLeft, Mail, Bell, MessageCircle, Send, CheckCircle2, XCircle, Clock, RefreshCw, Filter, Search } from 'lucide-react'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; interface NotificationLogEntry { id: number; channel: 'email' | 'push' | 'whatsapp' | 'telegram'; event: string; recipient: string; subject?: string; status: 'sent' | 'failed' | 'pending' | 'queued'; created_at: string; sent_at?: string; error_message?: string; } interface NotificationLogsResponse { logs: NotificationLogEntry[]; total: number; page: number; per_page: number; } const channelIcons: Record = { email: , push: , whatsapp: , telegram: , }; const statusConfig: Record = { sent: { icon: , color: 'text-green-600 bg-green-50', label: 'Sent' }, failed: { icon: , color: 'text-red-600 bg-red-50', label: 'Failed' }, pending: { icon: , color: 'text-yellow-600 bg-yellow-50', label: 'Pending' }, queued: { icon: , color: 'text-blue-600 bg-blue-50', label: 'Queued' }, }; export default function ActivityLog() { const [search, setSearch] = React.useState(''); const [channelFilter, setChannelFilter] = React.useState('all'); const [statusFilter, setStatusFilter] = React.useState('all'); const [page, setPage] = React.useState(1); const { data, isLoading, error, refetch } = useQuery({ queryKey: ['notification-logs', page, channelFilter, statusFilter, search], queryFn: async () => { const params = new URLSearchParams(); params.set('page', page.toString()); params.set('per_page', '20'); if (channelFilter !== 'all') params.set('channel', channelFilter); if (statusFilter !== 'all') params.set('status', statusFilter); if (search) params.set('search', search); return api.get(`/notifications/logs?${params.toString()}`); }, }); const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleString(); }; return ( } >
{/* Filters */}
setSearch(e.target.value)} className="!pl-9" />
{/* Activity Log Table */} {__('Recent Activity')} {isLoading ? __('Loading...') : data?.total ? `${data.total} ${__('notifications found')}` : __('No notifications recorded yet')} {isLoading ? (

{__('Loading activity log...')}

) : error ? (

{__('Failed to load activity log')}

) : !data?.logs?.length ? (

{__('No notifications yet')}

{__('Notification activities will appear here once sent.')}

) : (
{data.logs.map((log) => (
{/* Channel Icon */}
{channelIcons[log.channel] || }
{/* Content */}
{log.event} {statusConfig[log.status]?.icon} {statusConfig[log.status]?.label || log.status}

{__('To')}: {log.recipient} {log.subject && ` — ${log.subject}`}

{log.error_message && (

{__('Error')}: {log.error_message}

)}
{/* Timestamp */}
{formatDate(log.sent_at || log.created_at)}
))} {/* Pagination */} {data.total > 20 && (
{__('Page')} {page} {__('of')} {Math.ceil(data.total / 20)}
)}
)}
); }