import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Alert, Button, Input, Select, Space, Switch, Tabs } from 'antd'; import { BellOutlined, SendOutlined, SettingOutlined, WarningOutlined } from '@ant-design/icons'; import { HttpUtil, LanguageManager } from '@/utils'; import type { AllSetting } from '@/models/setting'; import { SettingListItem } from '@/components/ui'; import { TelegramNotifications } from '@/components/ui/notifications/TelegramNotifications'; import { useMediaQuery } from '@/hooks/useMediaQuery'; import { catTabLabel } from './catTabLabel'; import { NotifyTimeField } from './NotifyTimeField'; import SecretInput from './SecretInput'; interface TelegramTabProps { allSetting: AllSetting; updateSetting: (patch: Partial) => void; } export default function TelegramTab({ allSetting, updateSetting }: TelegramTabProps) { const { t } = useTranslation(); const { isMobile } = useMediaQuery(); const [testLoading, setTestLoading] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; msg: string } | null>(null); const [inlineWarning, setInlineWarning] = useState(null); const [privacyWarning, setPrivacyWarning] = useState(null); const [capsLoading, setCapsLoading] = useState(false); // The bot's lists live in inline mode, which only BotFather can enable, so the // panel checks the live capability and warns instead of leaving dead buttons. async function checkInlineMode() { setCapsLoading(true); try { const res = (await HttpUtil.post('/panel/api/setting/tgBotCapabilities')) as { success?: boolean; obj?: { inlineEnabled?: boolean; groupPrivacy?: boolean; username?: string }; }; if (res.success && res.obj && !res.obj.inlineEnabled) { setInlineWarning(res.obj.username || ''); } else { setInlineWarning(null); } // Privacy mode is the mirror-image trap: with it on, a bare /start typed // in a group never reaches the bot, so the command looks dead. setPrivacyWarning(res.success && !!res.obj?.groupPrivacy ? res.obj?.username || '' : null); } catch { // The bot may simply be stopped; the token field still tells that story. setInlineWarning(null); } finally { setCapsLoading(false); } } async function handleTestTgBot() { setTestLoading(true); setTestResult(null); try { const res = (await HttpUtil.post('/panel/api/setting/testTgBot')) as { success?: boolean; msg?: string; }; setTestResult({ success: !!res.success, msg: res.msg || '' }); } catch (e: unknown) { setTestResult({ success: false, msg: e instanceof Error ? e.message : t('pages.settings.requestFailed'), }); } finally { setTestLoading(false); } } const langOptions = useMemo( () => LanguageManager.supportedLanguages.map( (l: { value: string; name: string; icon: string }) => ({ value: l.value, label: ( <> {l.icon}   {l.name} ), }), ), [], ); return ( , t('pages.settings.panelSettings'), isMobile, ), children: ( <> updateSetting({ tgBotEnable: v })} /> updateSetting({ tgBotToken: v })} onClearArmedChange={(armed) => updateSetting({ clearTgBotToken: armed })} /> updateSetting({ tgBotChatId: e.target.value })} /> updateSetting({ tgBotAPIServer: e.target.value })} /> {inlineWarning !== null && ( } style={{ marginTop: 16 }} title={t('pages.settings.tgInlineMissing')} description={t('pages.settings.tgInlineMissingDesc')} action={ } /> )} {privacyWarning !== null && ( } style={{ marginTop: 16 }} title={t('pages.settings.tgPrivacyOn')} description={t('pages.settings.tgPrivacyOnDesc')} /> )} {testResult && ( setTestResult(null) }} /> )} ), }, { key: '2', label: catTabLabel( , t('pages.settings.notifications'), isMobile, ), children: ( <> updateSetting({ tgRunTime: v })} /> updateSetting({ tgBotBackup: v })} /> ), }, ]} /> ); }