Files
TeleWave/frontend/src/features/admin/channels/components/ApplyDialog.tsx
T

103 lines
3.6 KiB
TypeScript

import { useQuery } from '@tanstack/react-query'
import { AlertTriangle } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/shared/ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/shared/ui/dialog'
import { cn } from '@/shared/lib/cn'
import { getApplyDiff } from '../api'
import { formatChannelTime } from '../lib/format'
/**
* Диф перед применением (см. 6.6). Изменения в ближайшие сутки подсвечены отдельно — это самая
* частая причина случайного ущерба: у зрителя из-под носа уезжает то, что он уже видит в программе.
*/
export function ApplyDialog({
channelId,
utcOffsetMinutes,
pending,
onApply,
onClose,
}: {
channelId: string
utcOffsetMinutes: number
pending: boolean
onApply: () => void
onClose: () => void
}) {
const { t } = useTranslation()
const { data, isFetching } = useQuery({
queryKey: ['admin', 'channels', channelId, 'diff'],
queryFn: () => getApplyDiff(channelId),
staleTime: 0,
gcTime: 0,
})
return (
<Dialog open onOpenChange={(open) => !open && onClose()}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>{t('admin.channels.apply')}</DialogTitle>
<DialogDescription>
{isFetching || !data
? t('common.loading')
: t('admin.channels.diffSummary', { total: data.total, changed: data.changed })}
</DialogDescription>
</DialogHeader>
{data && (
<div className="flex flex-col gap-2 text-sm">
{data.changedSoon > 0 && (
<p className="flex items-center gap-1.5 text-amber-500">
<AlertTriangle className="h-4 w-4 shrink-0" />
{t('admin.channels.diffSoon', { count: data.changedSoon })}
</p>
)}
{data.changes.length === 0 ? (
<p className="text-muted-foreground">{t('admin.channels.diffNoChanges')}</p>
) : (
<ul className="max-h-80 divide-y divide-border overflow-y-auto text-xs">
{data.changes.map((change, index) => (
<li
key={`${change.startsAtUtc}-${index}`}
className={cn('flex items-center gap-2 py-1', change.soon && 'text-amber-500')}
>
<span className="w-24 shrink-0 tabular-nums text-muted-foreground">
{formatChannelTime(change.startsAtUtc, utcOffsetMinutes)}
</span>
<span className="min-w-0 flex-1 truncate">{change.before ?? '—'}</span>
<span className="shrink-0 text-muted-foreground"></span>
<span className="min-w-0 flex-1 truncate">{change.after ?? '—'}</span>
</li>
))}
</ul>
)}
{data.changed > data.changes.length && (
<p className="text-xs text-muted-foreground">
{t('admin.channels.andMore', { count: data.changed - data.changes.length })}
</p>
)}
</div>
)}
<DialogFooter>
<Button size="sm" variant="outline" onClick={onClose}>
{t('common.cancel')}
</Button>
<Button size="sm" disabled={pending} onClick={onApply}>
{t('admin.channels.apply')}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}