diff --git a/hooks/useTelegramWebApp.ts b/hooks/useTelegramWebApp.ts new file mode 100644 index 0000000..66103a4 --- /dev/null +++ b/hooks/useTelegramWebApp.ts @@ -0,0 +1,273 @@ +// hooks/useTelegramWebApp.ts +// Hook для интеграции с Telegram WebApp API + +import { useEffect, useState } from 'react'; + +declare global { + interface Window { + Telegram?: { + WebApp: { + ready: () => void; + expand: () => void; + close: () => void; + isExpanded: boolean; + viewportHeight: number; + viewportStableHeight: number; + headerColor: string; + backgroundColor: string; + isClosingConfirmationEnabled: boolean; + platform: string; + version: string; + + MainButton: { + text: string; + color: string; + textColor: string; + isVisible: boolean; + isActive: boolean; + isProgressVisible: boolean; + setText: (text: string) => void; + onClick: (callback: () => void) => void; + offClick: (callback: () => void) => void; + show: () => void; + hide: () => void; + enable: () => void; + disable: () => void; + showProgress: (leaveActive?: boolean) => void; + hideProgress: () => void; + setParams: (params: { text?: string; color?: string; text_color?: string; is_active?: boolean; is_visible?: boolean }) => void; + }; + + BackButton: { + isVisible: boolean; + onClick: (callback: () => void) => void; + offClick: (callback: () => void) => void; + show: () => void; + hide: () => void; + }; + + HapticFeedback: { + impactOccurred: (style: 'light' | 'medium' | 'heavy' | 'rigid' | 'soft') => void; + notificationOccurred: (type: 'error' | 'success' | 'warning') => void; + selectionChanged: () => void; + }; + + setHeaderColor: (color: string) => void; + setBackgroundColor: (color: string) => void; + enableClosingConfirmation: () => void; + disableClosingConfirmation: () => void; + + showPopup: (params: { + title?: string; + message: string; + buttons: Array<{ id?: string; type: string; text?: string }>; + }, callback?: (buttonId: string) => void) => void; + + showAlert: (message: string, callback?: () => void) => void; + showConfirm: (message: string, callback?: (confirmed: boolean) => void) => void; + + openLink: (url: string, options?: { try_instant_view?: boolean }) => void; + openTelegramLink: (url: string) => void; + openInvoice: (url: string, callback?: (status: string) => void) => void; + + shareToStory: (media_url: string, params?: { + text?: string; + widget_link?: { + url: string; + name?: string; + }; + }) => void; + + switchInlineQuery: (query: string, choose_chat_types?: string[]) => void; + + sendData: (data: string) => void; + + initData: string; + initDataUnsafe: { + query_id?: string; + user?: { + id: number; + first_name: string; + last_name?: string; + username?: string; + language_code?: string; + is_premium?: boolean; + photo_url?: string; + }; + receiver?: { + id: number; + first_name: string; + last_name?: string; + username?: string; + language_code?: string; + is_premium?: boolean; + }; + chat?: { + id: number; + type: string; + title: string; + username?: string; + photo_url?: string; + }; + chat_type?: string; + chat_instance?: string; + start_param?: string; + can_send_after?: number; + auth_date: number; + hash: string; + }; + + themeParams: { + bg_color?: string; + text_color?: string; + hint_color?: string; + link_color?: string; + button_color?: string; + button_text_color?: string; + secondary_bg_color?: string; + header_bg_color?: string; + accent_text_color?: string; + section_bg_color?: string; + section_header_text_color?: string; + subtitle_text_color?: string; + destructive_text_color?: string; + }; + + colorScheme: 'light' | 'dark'; + + isVersionAtLeast: (version: string) => boolean; + + onEvent: (eventType: string, eventHandler: () => void) => void; + offEvent: (eventType: string, eventHandler: () => void) => void; + }; + }; + } +} + +export function useTelegramWebApp() { + const [webApp, setWebApp] = useState(null); + const [isReady, setIsReady] = useState(false); + + useEffect(() => { + // Проверяем доступность Telegram WebApp только на клиенте + if (typeof window === 'undefined') return; + + const tg = window.Telegram?.WebApp; + if (!tg) { + console.warn('[TelegramWebApp] Not running in Telegram'); + setIsReady(true); // Всё равно помечаем как ready для dev + return; + } + + console.log('[TelegramWebApp] Initializing...', { + platform: tg.platform, + version: tg.version, + colorScheme: tg.colorScheme, + user: tg.initDataUnsafe.user, + }); + + // Инициализация Telegram WebApp + tg.ready(); + tg.expand(); + + // Настройка темы + tg.setHeaderColor('bg_color'); + tg.setBackgroundColor('#18222d'); + + // Отключить подтверждение закрытия (можно включить при необходимости) + tg.disableClosingConfirmation(); + + setWebApp(tg); + setIsReady(true); + + // Cleanup + return () => { + tg.MainButton.hide(); + tg.BackButton.hide(); + }; + }, []); + + return { + webApp, + isReady, + isTelegram: !!webApp, + user: webApp?.initDataUnsafe.user, + platform: webApp?.platform, + colorScheme: webApp?.colorScheme, + themeParams: webApp?.themeParams, + }; +} + +// Helper функции для удобства + +export function useTelegramMainButton( + text: string, + onClick: () => void, + options?: { + color?: string; + textColor?: string; + enabled?: boolean; + } +) { + const { webApp } = useTelegramWebApp(); + + useEffect(() => { + if (!webApp) return; + + webApp.MainButton.setText(text); + webApp.MainButton.onClick(onClick); + + if (options?.color) { + webApp.MainButton.color = options.color; + } + if (options?.textColor) { + webApp.MainButton.textColor = options.textColor; + } + if (options?.enabled !== undefined) { + if (options.enabled) { + webApp.MainButton.enable(); + } else { + webApp.MainButton.disable(); + } + } + + webApp.MainButton.show(); + + return () => { + webApp.MainButton.offClick(onClick); + webApp.MainButton.hide(); + }; + }, [webApp, text, onClick, options]); +} + +export function useTelegramBackButton(onClick: () => void) { + const { webApp } = useTelegramWebApp(); + + useEffect(() => { + if (!webApp) return; + + webApp.BackButton.onClick(onClick); + webApp.BackButton.show(); + + return () => { + webApp.BackButton.offClick(onClick); + webApp.BackButton.hide(); + }; + }, [webApp, onClick]); +} + +export function useTelegramHaptic() { + const { webApp } = useTelegramWebApp(); + + return { + impact: (style: 'light' | 'medium' | 'heavy' | 'rigid' | 'soft' = 'medium') => { + webApp?.HapticFeedback.impactOccurred(style); + }, + notification: (type: 'error' | 'success' | 'warning') => { + webApp?.HapticFeedback.notificationOccurred(type); + }, + selection: () => { + webApp?.HapticFeedback.selectionChanged(); + }, + }; +}