import { useEffect, useState } from 'react'; import { useAlertSettings, useUpdateAlertSettings, useTestAlert } from '../../hooks/useAdmin'; import { SkeletonTable } from '../ui/Skeleton'; const SOURCE_LABEL: Record = { database: 'configured here', environment: 'from environment (.env)', none: 'not configured', }; type TriggerKey = | 'qualified_enabled' | 'sr_proximity_enabled' | 'score_drop_enabled' | 'digest_enabled' | 'regime_quadrant_enabled' | 'trade_closed_enabled'; const TRIGGERS: { key: TriggerKey; label: string; hint: string }[] = [ { key: 'qualified_enabled', label: 'Qualified setups', hint: 'a setup newly clears the activation gate' }, { key: 'sr_proximity_enabled', label: 'Watchlist S/R proximity', hint: 'a watched ticker nears a strong support/resistance' }, { key: 'score_drop_enabled', label: 'Score deterioration', hint: 'a watched ticker’s composite drops sharply' }, { key: 'digest_enabled', label: 'Daily digest', hint: 'end-of-day summary incl. open trades + trailing stops' }, { key: 'regime_quadrant_enabled', label: 'Risk quadrant change', hint: 'the AI/Tech risk monitor shifts quadrant (hysteresis + cooldown)' }, { key: 'trade_closed_enabled', label: 'Trade closed', hint: 'a paper trade auto-closes (trailing/target/stop) — incl. losses' }, ]; function Toggle({ checked, onChange, label, hint }: { checked: boolean; onChange: (v: boolean) => void; label: string; hint: string; }) { return ( ); } export function AlertSettings() { const { data, isLoading, isError, error } = useAlertSettings(); const update = useUpdateAlertSettings(); const test = useTestAlert(); const [enabled, setEnabled] = useState(false); const [chatId, setChatId] = useState(''); const [botToken, setBotToken] = useState(''); const [triggers, setTriggers] = useState>({ qualified_enabled: true, sr_proximity_enabled: true, score_drop_enabled: true, digest_enabled: true, regime_quadrant_enabled: true, trade_closed_enabled: true, }); useEffect(() => { if (data) { setEnabled(data.enabled); setChatId(data.telegram_chat_id ?? ''); setTriggers({ qualified_enabled: data.qualified_enabled, sr_proximity_enabled: data.sr_proximity_enabled, score_drop_enabled: data.score_drop_enabled, digest_enabled: data.digest_enabled, regime_quadrant_enabled: data.regime_quadrant_enabled, trade_closed_enabled: data.trade_closed_enabled, }); } }, [data]); if (isLoading) return ; if (isError) return

{(error as Error)?.message || 'Failed to load alert settings'}

; if (!data) return null; const onSave = () => { update.mutate({ enabled, telegram_chat_id: chatId, ...triggers, ...(botToken ? { bot_token: botToken } : {}), }); setBotToken(''); }; const tokenConfigured = data.bot_token_configured; return (

Telegram Alerts

Push actionable signals to Telegram so you don’t have to keep checking the dashboard. The dispatcher runs hourly; each trigger respects a cooldown so you’re not spammed.

Triggers

{TRIGGERS.map((t) => ( setTriggers((prev) => ({ ...prev, [t.key]: v }))} /> ))}
Save first, then Send Test to verify the bot reaches you.
Setup: 1) message @BotFather, send /newbot, copy the token. 2) send your new bot any message. 3) get your chat ID from @userinfobot. Paste both above.
); }