import { useState } from 'react'; import { useNavigate } from 'react-router'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { adminBroadcastsApi } from '../api/adminBroadcasts'; import { usePlatform } from '../platform/hooks/usePlatform'; // Icons const BackIcon = () => ( ); const BroadcastIcon = () => ( ); const PlusIcon = () => ( ); const RefreshIcon = () => ( ); const PhotoIcon = () => ( ); const VideoIcon = () => ( ); const DocumentIcon = () => ( ); // Status badge component const statusConfig: Record = { queued: { bg: 'bg-warning-500/20', text: 'text-warning-400', labelKey: 'admin.broadcasts.status.queued', }, in_progress: { bg: 'bg-accent-500/20', text: 'text-accent-400', labelKey: 'admin.broadcasts.status.inProgress', }, completed: { bg: 'bg-success-500/20', text: 'text-success-400', labelKey: 'admin.broadcasts.status.completed', }, partial: { bg: 'bg-warning-500/20', text: 'text-warning-400', labelKey: 'admin.broadcasts.status.partial', }, failed: { bg: 'bg-error-500/20', text: 'text-error-400', labelKey: 'admin.broadcasts.status.failed', }, cancelled: { bg: 'bg-dark-500/20', text: 'text-dark-400', labelKey: 'admin.broadcasts.status.cancelled', }, cancelling: { bg: 'bg-warning-500/20', text: 'text-warning-400', labelKey: 'admin.broadcasts.status.cancelling', }, }; function StatusBadge({ status }: { status: string }) { const { t } = useTranslation(); const config = statusConfig[status] || statusConfig.queued; return ( {t(config.labelKey)} ); } // Main component export default function AdminBroadcasts() { const { t } = useTranslation(); const navigate = useNavigate(); const { capabilities } = usePlatform(); const [page, setPage] = useState(0); const limit = 20; // Fetch broadcasts const { data, isLoading, refetch } = useQuery({ queryKey: ['admin', 'broadcasts', 'list', page], queryFn: () => adminBroadcastsApi.list(limit, page * limit), refetchInterval: 5000, // Auto refresh every 5s }); const broadcasts = data?.items || []; const total = data?.total || 0; const totalPages = Math.ceil(total / limit); return ( {/* Header */} {/* Show back button only on web, not in Telegram Mini App */} {!capabilities.hasBackButton && ( navigate('/admin')} className="flex h-10 w-10 items-center justify-center rounded-xl border border-dark-700 bg-dark-800 transition-colors hover:border-dark-600" > )} {t('admin.broadcasts.title')} {t('admin.broadcasts.subtitle')} refetch()} className="rounded-lg bg-dark-800 p-2 text-dark-400 transition-colors hover:text-dark-100" > navigate('/admin/broadcasts/create')} className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600" > {t('admin.broadcasts.create')} {/* Broadcasts list */} {isLoading ? ( {t('common.loading')} ) : broadcasts.length === 0 ? ( {t('admin.broadcasts.empty')} ) : ( {broadcasts.map((broadcast) => ( navigate(`/admin/broadcasts/${broadcast.id}`)} className="w-full rounded-xl border border-dark-700 bg-dark-800/50 p-4 text-left transition-all hover:border-dark-600 hover:bg-dark-800" > #{broadcast.id} {broadcast.has_media && ( {broadcast.media_type === 'photo' && } {broadcast.media_type === 'video' && } {broadcast.media_type === 'document' && } )} {broadcast.message_text} {broadcast.target_type} {broadcast.sent_count}/{broadcast.total_count} {new Date(broadcast.created_at).toLocaleDateString()} {['queued', 'in_progress'].includes(broadcast.status) && ( {broadcast.progress_percent.toFixed(0)}% )} ))} )} {/* Pagination */} {totalPages > 1 && ( setPage((p) => Math.max(0, p - 1))} disabled={page === 0} className="rounded-lg bg-dark-700 px-3 py-1 text-dark-300 hover:bg-dark-600 disabled:cursor-not-allowed disabled:opacity-50" > {t('admin.broadcasts.prev')} {page + 1} / {totalPages} setPage((p) => Math.min(totalPages - 1, p + 1))} disabled={page >= totalPages - 1} className="rounded-lg bg-dark-700 px-3 py-1 text-dark-300 hover:bg-dark-600 disabled:cursor-not-allowed disabled:opacity-50" > {t('admin.broadcasts.next')} )} ); }
{t('admin.broadcasts.subtitle')}
{t('common.loading')}
{t('admin.broadcasts.empty')}
{broadcast.message_text}
{broadcast.progress_percent.toFixed(0)}%