Безопасность: - proxy: белый список путей (только /sub/*), POST заблокирован - console.log заменён на logger (утечки URL/данных) - OnboardingFlow: убраны --tg-theme-* (не существуют в проекте) TypeScript (0 ошибок): - tsconfig target es5→es2017 (regex /u flag fix) - layout.tsx: viewport перенесён в metadata (Next.js 13.5) - telegram-webhook: fix text possibly undefined - hooks/useTelegramWebApp: fix Object possibly undefined - types/telegram: убрана дублирующая Window декларация UI: - BottomNav: новый компонент (Назад/Главная/Помощь) - safe-area-bottom CSS класс добавлен в globals.css - dashboard: spacer h-20, toast поднят над BottomNav - OnboardingFlow: цены 149/249/350₽ (были 200/350/500₽) Очистка: - page_NEW.tsx удалён локально (не был в git)
190 lines
5.8 KiB
TypeScript
190 lines
5.8 KiB
TypeScript
// Telegram Bot Webhook Handler
|
||
// POST /api/telegram-webhook
|
||
// Принимает вебхуки от Telegram и обрабатывает команды
|
||
|
||
import { NextRequest, NextResponse } from 'next/server';
|
||
import { logger } from '@/lib/logger';
|
||
|
||
const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || '';
|
||
const WEBAPP_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://app.umbrix.net';
|
||
|
||
interface TelegramUpdate {
|
||
message?: {
|
||
message_id: number;
|
||
from: {
|
||
id: number;
|
||
first_name: string;
|
||
last_name?: string;
|
||
username?: string;
|
||
};
|
||
chat: {
|
||
id: number;
|
||
};
|
||
text?: string;
|
||
};
|
||
}
|
||
|
||
interface InlineKeyboardButton {
|
||
text: string;
|
||
web_app?: { url: string };
|
||
url?: string;
|
||
}
|
||
|
||
async function sendMessage(
|
||
chatId: number,
|
||
text: string,
|
||
replyMarkup?: { inline_keyboard: InlineKeyboardButton[][] }
|
||
) {
|
||
const url = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
|
||
const body = {
|
||
chat_id: chatId,
|
||
text: text,
|
||
parse_mode: 'HTML',
|
||
reply_markup: replyMarkup,
|
||
};
|
||
|
||
try {
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(body),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
logger.error('Telegram API error:', await response.text());
|
||
}
|
||
} catch (error) {
|
||
logger.error('Failed to send Telegram message:', error);
|
||
}
|
||
}
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const update: TelegramUpdate = await request.json();
|
||
|
||
logger.debug('📨 Telegram webhook received:', update);
|
||
|
||
if (!update.message || !update.message.text) {
|
||
return NextResponse.json({ ok: true });
|
||
}
|
||
|
||
const { message } = update;
|
||
const { chat, from } = message;
|
||
const text = message.text!;
|
||
|
||
// Обработка команды /start
|
||
if (text.startsWith('/start')) {
|
||
const parts = text.split(' ');
|
||
const startParam = parts[1]; // Например: "ref_john_doe"
|
||
|
||
let webAppUrl = WEBAPP_URL;
|
||
let welcomeText = `👋 Привет, ${from.first_name}!\n\n`;
|
||
|
||
// Если есть реферальный параметр
|
||
if (startParam && startParam.startsWith('ref_')) {
|
||
const referrerId = startParam.replace('ref_', '');
|
||
webAppUrl = `${WEBAPP_URL}?ref=${encodeURIComponent(referrerId)}`;
|
||
|
||
welcomeText += `🎁 Вы перешли по реферальной ссылке от <b>${referrerId}</b>!\n\n`;
|
||
welcomeText += `При регистрации вы получите:\n`;
|
||
welcomeText += `✅ <b>7 дней бесплатно</b>\n`;
|
||
welcomeText += `✅ А ваш друг получит <b>+7 дней</b> к подписке!\n\n`;
|
||
|
||
logger.info(`🎁 Referral link opened: ${from.id} -> ${referrerId}`);
|
||
} else {
|
||
welcomeText += `🚀 <b>Umbrix VPN</b> - быстрый и безопасный VPN!\n\n`;
|
||
welcomeText += `✅ Надежная защита данных\n`;
|
||
welcomeText += `✅ Высокая скорость соединения\n`;
|
||
welcomeText += `✅ Простая настройка\n\n`;
|
||
}
|
||
|
||
welcomeText += `Нажмите кнопку ниже, чтобы начать:`;
|
||
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{
|
||
text: '🚀 Открыть Umbrix',
|
||
web_app: { url: webAppUrl },
|
||
},
|
||
],
|
||
],
|
||
};
|
||
|
||
await sendMessage(chat.id, welcomeText, keyboard);
|
||
|
||
return NextResponse.json({ ok: true });
|
||
}
|
||
|
||
// Обработка других команд
|
||
if (text === '/help') {
|
||
const helpText = `
|
||
<b>Доступные команды:</b>
|
||
|
||
/start - Открыть приложение
|
||
/help - Показать эту справку
|
||
/referral - Получить свою реферальную ссылку
|
||
|
||
<b>Как получить реферальную ссылку?</b>
|
||
1. Откройте приложение
|
||
2. Перейдите в раздел "Реферальная программа"
|
||
3. Скопируйте ссылку и отправьте друзьям!
|
||
|
||
<b>Условия реферальной программы:</b>
|
||
• За каждого друга: <b>+7 дней</b> бесплатно
|
||
• За 5 друзей: <b>1 месяц в подарок</b>
|
||
• При оплате: <b>10% скидка</b>
|
||
`;
|
||
|
||
await sendMessage(chat.id, helpText.trim());
|
||
return NextResponse.json({ ok: true });
|
||
}
|
||
|
||
if (text === '/referral') {
|
||
const referralText = `
|
||
🎁 <b>Ваша реферальная ссылка:</b>
|
||
|
||
Чтобы получить ссылку, откройте приложение и перейдите в раздел "Пригласить друга".
|
||
|
||
Там вы найдете свою уникальную ссылку и сможете поделиться ей!
|
||
`;
|
||
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{
|
||
text: '🚀 Открыть приложение',
|
||
web_app: { url: WEBAPP_URL },
|
||
},
|
||
],
|
||
],
|
||
};
|
||
|
||
await sendMessage(chat.id, referralText.trim(), keyboard);
|
||
return NextResponse.json({ ok: true });
|
||
}
|
||
|
||
// Неизвестная команда
|
||
await sendMessage(
|
||
chat.id,
|
||
'Неизвестная команда. Используйте /help для списка команд.'
|
||
);
|
||
|
||
return NextResponse.json({ ok: true });
|
||
} catch (error) {
|
||
logger.error('❌ Telegram webhook error:', error);
|
||
return NextResponse.json(
|
||
{ ok: false, error: 'Internal server error' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|
||
|
||
// Для проверки что webhook работает
|
||
export async function GET() {
|
||
return NextResponse.json({
|
||
status: 'ok',
|
||
message: 'Telegram webhook endpoint is running'
|
||
});
|
||
}
|