← Назадimport { Send, Users, FileText, Activity, FolderOpen, Clock, BarChart2, ExternalLink, Map } from 'lucide-react';
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '../ui/card';
import { Button } from '../ui/button';
import { Badge } from '../ui/badge';
import { useProject } from '../../hooks/useProjects';
interface AlphaPulseCardProps {
onViewTasks: () => void;
onViewFiles?: () => void;
}
function fmtLastPost(raw: string | null): string {
if (!raw) return '—';
const d = new Date(raw + 'Z');
if (isNaN(d.getTime())) return raw;
const now = Date.now();
const mins = Math.floor((now - d.getTime()) / 60000);
if (mins < 60) return `${mins}м назад`;
if (mins < 1440) return `${Math.floor(mins / 60)}ч назад`;
return `${Math.floor(mins / 1440)}д назад`;
}
export function AlphaPulseCard({ onViewTasks, onViewFiles }: AlphaPulseCardProps) {
const { data, isLoading, refetch } = useProject('alphapulse');
if (isLoading) {
return (
<Card className="animate-pulse">
<div className="h-64 flex items-center justify-center">
<div className="text-gray-400">Loading...</div>
</div>
</Card>
);
}
const { kpis, status } = data || {};
const botStatus = kpis?.bot?.status || 'unknown';
const postsToday = kpis?.posts?.today ?? '--';
const postsTotal = kpis?.posts?.total ?? '--';
const subscribers = kpis?.channel?.subscribers;
const lastPost = kpis?.timing?.lastPost ?? null;
const lastType = kpis?.timing?.lastType ?? null;
const nextPost = kpis?.timing?.nextPost ?? '--';
const isRunning = botStatus === 'running';
return (
<Card className={`border-l-4 ${isRunning ? 'border-l-alphapulse' : 'border-l-danger'} transition-all duration-300 hover:-translate-y-1 hover:shadow-lg hover:shadow-alphapulse/10`}>
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="p-3 rounded-xl bg-alphapulse/20">
<Send className="w-6 h-6 text-alphapulse" />
</div>
<div>
<CardTitle>AlphaPulse</CardTitle>
<CardDescription>Telegram сигнальный канал</CardDescription>
</div>
</div>
<Badge variant={isRunning ? 'success' : 'danger'}>
{isRunning ? 'RUNNING' : (status?.toUpperCase() || 'UNKNOWN')}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-3">
{/* Row 1 */}
<div className="grid grid-cols-3 gap-3">
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<Activity className="w-3.5 h-3.5" />
Бот
</div>
<div className={`text-base font-bold ${isRunning ? 'text-alphapulse' : 'text-danger'}`}>
{isRunning ? '● Online' : '● Offline'}
</div>
</div>
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<FileText className="w-3.5 h-3.5" />
Сегодня
</div>
<div className="text-2xl font-bold text-white">{postsToday}</div>
<div className="text-xs text-gray-500 mt-0.5">постов</div>
</div>
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<BarChart2 className="w-3.5 h-3.5" />
Всего
</div>
<div className="text-2xl font-bold text-white">{postsTotal}</div>
<div className="text-xs text-gray-500 mt-0.5">в базе</div>
</div>
</div>
{/* Row 2 */}
<div className="grid grid-cols-3 gap-3">
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<Clock className="w-3.5 h-3.5" />
Последний
</div>
<div className="text-sm font-semibold text-white">{fmtLastPost(lastPost)}</div>
{lastType && (
<div className="text-xs text-gray-500 mt-0.5 capitalize">{lastType}</div>
)}
</div>
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<Clock className="w-3.5 h-3.5" />
Следующий
</div>
<div className="text-sm font-semibold text-alphapulse">{nextPost}</div>
</div>
<div className="bg-white/5 rounded-xl p-3 border border-white/5">
<div className="flex items-center gap-1.5 text-xs text-gray-400 uppercase mb-2">
<Users className="w-3.5 h-3.5" />
Подписч.
</div>
<div className="text-2xl font-bold text-white">
{subscribers != null
? typeof subscribers === 'number'
? subscribers.toLocaleString('ru')
: subscribers
: <span className="text-sm text-gray-500">n/a</span>
}
</div>
</div>
</div>
</CardContent>
<CardFooter className="gap-2 flex-wrap">
<Button variant="primary" size="sm" onClick={() => refetch()}>
<Activity className="w-4 h-4" />
Обновить
</Button>
<Button variant="ghost" size="sm" onClick={onViewTasks}>
<FileText className="w-4 h-4" />
Задачи
</Button>
{onViewFiles && (
<Button variant="ghost" size="sm" onClick={onViewFiles}>
<FolderOpen className="w-4 h-4" />
Файлы
</Button>
)}
<Button
variant="ghost"
size="sm"
onClick={() => window.open('https://t.me/alphapulsexp', '_blank')}
>
<ExternalLink className="w-4 h-4" />
Канал
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => window.open('https://t.me/alphapulsexp', '_blank')}
title="ROADMAP"
>
<Map className="w-4 h-4" />
</Button>
</CardFooter>
</Card>
);
}