'use client'; import { useCallback, useEffect, useRef, useState } from 'react'; import { BotInlineKeyboard } from '@/components/chat/bot-inline-keyboard'; import { useToast } from '@/components/id/toast-provider'; import { useRealtime } from '@/components/notifications/realtime-provider'; import { submitBotCallback } from '@/lib/api'; const CALLBACK_ANSWER_TIMEOUT_MS = 30_000; interface BotMessageKeyboardProps { botRef: string; messageId: number; markup: unknown; token: string | null; botId?: string; onOpenMiniApp?: (url: string) => void; } export function BotMessageKeyboard({ botRef, messageId, markup, token, botId, onOpenMiniApp }: BotMessageKeyboardProps) { const { showToast } = useToast(); const { subscribe } = useRealtime(); const [loadingButtonKey, setLoadingButtonKey] = useState(null); const pendingQueriesRef = useRef(new Map>()); const clearPendingQuery = useCallback((callbackQueryId: string) => { const timer = pendingQueriesRef.current.get(callbackQueryId); if (timer) { clearTimeout(timer); pendingQueriesRef.current.delete(callbackQueryId); } setLoadingButtonKey(null); }, []); useEffect(() => { return () => { pendingQueriesRef.current.forEach((timer) => clearTimeout(timer)); pendingQueriesRef.current.clear(); }; }, []); useEffect(() => { return subscribe((event) => { if (event.type !== 'bot_callback_answer') return; const payload = event.payload ?? {}; const callbackQueryId = typeof payload.callbackQueryId === 'string' ? payload.callbackQueryId : null; if (!callbackQueryId || !pendingQueriesRef.current.has(callbackQueryId)) return; const eventBotId = typeof payload.botId === 'string' ? payload.botId : null; if (botId && eventBotId && eventBotId !== botId) return; clearPendingQuery(callbackQueryId); const text = typeof payload.text === 'string' ? payload.text.trim() : ''; const showAlert = Boolean(payload.showAlert); const url = typeof payload.url === 'string' ? payload.url.trim() : ''; if (url && onOpenMiniApp) { onOpenMiniApp(url); } if (text) { if (showAlert) { window.alert(text); } else { showToast(text); } } }); }, [botId, clearPendingQuery, onOpenMiniApp, showToast, subscribe]); async function handleCallbackClick(callbackData: string, buttonKey: string) { if (!token) return; setLoadingButtonKey(buttonKey); try { const response = await submitBotCallback(botRef, messageId, callbackData, token); const callbackQueryId = response.callbackQueryId; if (!callbackQueryId) { setLoadingButtonKey(null); return; } const timer = setTimeout(() => clearPendingQuery(callbackQueryId), CALLBACK_ANSWER_TIMEOUT_MS); pendingQueriesRef.current.set(callbackQueryId, timer); } catch (error) { setLoadingButtonKey(null); showToast(error instanceof Error ? error.message : 'Не удалось отправить действие'); } } return ( ); }