import { useQuery } from '@tanstack/react-query' import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { Radio } from 'lucide-react' import type { ScheduleEntryDto } from '@/shared/api/types' import { cn } from '@/shared/lib/cn' import { Badge } from '@/shared/ui/badge' import { ChannelPlayer } from './ChannelPlayer' import { getEpg, listChannels, watchChannel } from './api' function formatTime(iso: string) { return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } export function AirPage() { const { t } = useTranslation() const [selected, setSelected] = useState(null) const [watchReady, setWatchReady] = useState(false) const { data: channels, isLoading } = useQuery({ queryKey: ['air', 'channels'], queryFn: listChannels, }) useEffect(() => { if (!selected && channels && channels.length > 0) setSelected(channels[0].slug) }, [channels, selected]) useEffect(() => { if (!selected) return setWatchReady(false) let cancelled = false void watchChannel(selected) .then(() => { if (!cancelled) setWatchReady(true) }) .catch(() => undefined) return () => { cancelled = true } }, [selected]) const { data: epg } = useQuery({ queryKey: ['air', 'epg', selected], queryFn: () => getEpg( selected!, new Date(Date.now() - 30 * 60_000), new Date(Date.now() + 3 * 60 * 60_000), ), enabled: !!selected, refetchInterval: 60_000, }) const { current, upcoming } = useMemo(() => splitEpg(epg ?? []), [epg]) if (isLoading) return

{t('common.loading')}

if (!channels || channels.length === 0) return (

{t('nav.dashboard')}

{t('air.noChannels')}

) return (

{t('nav.dashboard')}

{selected && watchReady ? ( ) : (
)}
{current && (
{t('air.now')} {programLabel(current, t)}
{formatTime(current.startsAtUtc)} – {formatTime(current.endsAtUtc)}
)} {upcoming.length > 0 && (
{t('air.next')}
    {upcoming.slice(0, 6).map((entry) => (
  • {formatTime(entry.startsAtUtc)} {programLabel(entry, t)}
  • ))}
)}
) } function splitEpg(entries: ScheduleEntryDto[]) { const now = Date.now() const current = entries.find( (e) => new Date(e.startsAtUtc).getTime() <= now && new Date(e.endsAtUtc).getTime() > now, ) const upcoming = entries.filter((e) => new Date(e.startsAtUtc).getTime() > now) return { current, upcoming } } function programLabel(entry: ScheduleEntryDto, t: (key: string) => string) { if (entry.kind === 'Ad') return t('air.ad') const name = entry.showName ?? '—' return entry.episodeIndex != null ? `${name} · ${t('air.episode')} ${entry.episodeIndex + 1}` : name }