import { useTranslation } from 'react-i18next'; import type { UserDetailResponse, UserSubscriptionInfo, PanelSyncStatusResponse, } from '../../../api/adminUsers'; // ────────────────────────────────────────────────────────────────── // Icons (sync-tab-local — not used outside this view) // ────────────────────────────────────────────────────────────────── const ArrowDownIcon = ({ className = 'w-5 h-5' }: { className?: string }) => ( ); const ArrowUpIcon = ({ className = 'w-5 h-5' }: { className?: string }) => ( ); // ────────────────────────────────────────────────────────────────── // Sync tab — compares bot DB vs panel data, offers a 2-way push // ────────────────────────────────────────────────────────────────── export interface SyncTabProps { user: UserDetailResponse; syncStatus: PanelSyncStatusResponse | null; userSubscriptions: UserSubscriptionInfo[]; activeSubscriptionId: number | null; onActiveSubscriptionChange: (id: number | null) => void; actionLoading: boolean; onSyncFromPanel: () => void; onSyncToPanel: () => void; locale: string; } export function SyncTab({ user, syncStatus, userSubscriptions, activeSubscriptionId, onActiveSubscriptionChange, actionLoading, onSyncFromPanel, onSyncToPanel, locale, }: SyncTabProps) { const { t } = useTranslation(); return (
{/* Subscription selector for multi-tariff */} {userSubscriptions.length > 1 && (
{t('admin.users.detail.sync.selectSubscription')}
)} {/* Sync status */} {syncStatus && (
{syncStatus.has_differences ? ( {t('admin.users.detail.sync.hasDifferences')} ) : ( {t('admin.users.detail.sync.synced')} )}
{syncStatus.differences.length > 0 && (
{syncStatus.differences.map((diff, i) => (
• {diff}
))}
)}
{t('admin.users.detail.sync.bot')}
{t('admin.users.detail.sync.statusLabel')}: {syncStatus.bot_subscription_status || '-'}
{t('admin.users.detail.sync.until')}: {syncStatus.bot_subscription_end_date ? new Date(syncStatus.bot_subscription_end_date).toLocaleDateString(locale) : '-'}
{t('admin.users.detail.sync.traffic')}: {syncStatus.bot_traffic_used_gb.toFixed(2)} {t('common.units.gb')}
{t('admin.users.detail.sync.devices')}: {syncStatus.bot_device_limit}
{t('admin.users.detail.sync.squads')}: {syncStatus.bot_squads?.length || 0}
{t('admin.users.detail.sync.panel')}
{t('admin.users.detail.sync.statusLabel')}: {syncStatus.panel_status || '-'}
{t('admin.users.detail.sync.until')}: {syncStatus.panel_expire_at ? new Date(syncStatus.panel_expire_at).toLocaleDateString(locale) : '-'}
{t('admin.users.detail.sync.traffic')}: {syncStatus.panel_traffic_used_gb.toFixed(2)} {t('common.units.gb')}
{t('admin.users.detail.sync.devices')}: {syncStatus.panel_device_limit}
{t('admin.users.detail.sync.squads')}: {syncStatus.panel_squads?.length || 0}
)} {/* UUID info */}
{syncStatus?.subscription_tariff_name && (
{syncStatus.subscription_tariff_name}
)}
Remnawave UUID
{syncStatus?.remnawave_uuid || user.remnawave_uuid || t('admin.users.detail.sync.notLinked')}
{/* Sync buttons */}
); }