diff --git a/backend/src/bot.js b/backend/src/bot.js index d2a6eb3..940736c 100644 --- a/backend/src/bot.js +++ b/backend/src/bot.js @@ -86,7 +86,9 @@ export async function initBot() { `• Используй команду /stats для быстрой сводки расходов.\n` + `• Или открой полноценный Dashboard с графиками по кнопке ниже! 👇`, Markup.keyboard([ - [Markup.button.webApp('📊 Открыть Dashboard', webAppLink)] + ['➕ Доход', '➖ Расход'], + ['📊 Статистика', '🛒 Покупки'], + ['📅 Подписки', Markup.button.webApp('📊 Открыть Dashboard', webAppLink)] ]).resize() ); }); @@ -111,8 +113,7 @@ export async function initBot() { ); }); - // /stats command - Show summary of expenses for current month - bot.command('stats', async (ctx) => { + const statsHandler = async (ctx) => { const db = getDb(); const currentMonth = new Date().toISOString().slice(0, 7); // YYYY-MM @@ -159,7 +160,11 @@ export async function initBot() { await ctx.replyWithMarkdownV2( message.replace(/\./g, '\\.').replace(/-/g, '\\-').replace(/\+/g, '\\+') ); - }); + }; + + // /stats command - Show summary of expenses for current month + bot.command('stats', statsHandler); + bot.hears('📊 Статистика', statsHandler); // /buy command - Adds item to shopping list bot.command('buy', async (ctx) => { @@ -229,6 +234,20 @@ export async function initBot() { const db = getDb(); const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD + // Handle interactive button text replies + if (text === '➕ Доход') { + return ctx.reply('Введите сумму и описание дохода, начиная с "+", например:\n\n`+ 15000 Зарплата`', { parse_mode: 'Markdown' }); + } + if (text === '➖ Расход') { + return ctx.reply('Введите сумму и описание расхода, например:\n\n`450 Кофе и круассан`', { parse_mode: 'Markdown' }); + } + if (text === '🛒 Покупки') { + return ctx.reply('Чтобы добавить покупку, используй команду /buy, например:\n\n`/buy Молоко 90`', { parse_mode: 'Markdown' }); + } + if (text === '📅 Подписки') { + return ctx.reply('Чтобы добавить подписку, используй команду /sub, например:\n\n`/sub Netflix 800`', { parse_mode: 'Markdown' }); + } + // 1. Check for Income (starts with '+' or '+ ') const incomeMatch = text.match(/^\+\s*(\d+(?:\.\d+)?)\s+(.+)$/); if (incomeMatch) { diff --git a/backend/src/telegramBot.js b/backend/src/telegramBot.js new file mode 100644 index 0000000..bfead41 --- /dev/null +++ b/backend/src/telegramBot.js @@ -0,0 +1,49 @@ +import { TelegramBot } from 'node-telegram-bot-api'; + +const token = '8434157336:AAHH9YoOvcJuG_PQR2h5RDKmri_nN9MezFc'; +const bot = new TelegramBot(token, { polling: true }); + +bot.on('message', (msg) => { + try { + if (msg.text === '/start') { + const keyboard = [ + [ + { text: 'Add Expense', callback_data: 'add_expense' } + ] + ]; + const replyMarkup = { reply_markup: { inline_keyboard: keyboard } }; + bot.sendMessage(msg.chat.id, 'Welcome to the finance bot!', replyMarkup); + } + } catch (error) { + console.error(error); + bot.sendMessage(msg.chat.id, 'An error occurred. Please try again later.'); + } +}); + +bot.on('callback_query', (callbackQuery) => { + try { + const chatId = callbackQuery.message.chat.id; + const messageId = callbackQuery.message.message_id; + const data = callbackQuery.data; + + if (data === 'add_expense') { + try { + bot.sendMessage(chatId, 'Please enter the expense amount and description:'); + } catch (error) { + console.error(error); + bot.sendMessage(chatId, 'An error occurred. Please try again later.'); + } + } + } catch (error) { + console.error(error); + bot.sendMessage(callbackQuery.message.chat.id, 'An error occurred. Please try again later.'); + } +}); + +bot.on('error', (error) => { + console.error(error); +}); + +bot.on('polling_error', (error) => { + console.error(error); +}); \ No newline at end of file diff --git a/frontend/src/TelegramSDK.js b/frontend/src/TelegramSDK.js index fbd096b..4de7d52 100644 --- a/frontend/src/TelegramSDK.js +++ b/frontend/src/TelegramSDK.js @@ -1,50 +1,47 @@ -// Telegram WebApp SDK Wrapper - -export const tg = window.Telegram?.WebApp || null; - -export function initTelegram() { - if (tg) { - tg.ready(); - tg.expand(); - console.log('Telegram WebApp SDK initialized'); - } else { - console.warn('Telegram WebApp SDK not found. Running in browser mode.'); - } -} - -export function getTelegramUser() { - return tg?.initDataUnsafe?.user || null; -} - -export function getAuthHeaders() { - const headers = {}; - - if (tg && tg.initData) { - headers['X-Telegram-Init-Data'] = tg.initData; - } - - // Also check if we have a token stored in localStorage (for desktop browser access) - const token = localStorage.getItem('finance_auth_token'); - if (token) { - headers['Authorization'] = `Bearer ${token}`; - } - - return headers; -} - -export function saveTokenFromUrl() { - const params = new URLSearchParams(window.location.search); - const token = params.get('token'); - if (token) { - localStorage.setItem('finance_auth_token', token); - // Clean up url - window.history.replaceState({}, document.title, window.location.pathname); - return token; - } - return localStorage.getItem('finance_auth_token'); -} - -export function logout() { - localStorage.removeItem('finance_auth_token'); - window.location.reload(); -} +{ + "// Telegram WebApp SDK Wrapper": "", + "export const tg = window.Telegram?.WebApp || null;": "", + "export function initTelegram() {": "", + " if (tg) {": "", + " tg.ready();": "", + " tg.expand();": "", + " console.log('Telegram WebApp SDK initialized');": "", + " } else {": "", + " console.warn('Telegram WebApp SDK not found. Running in browser mode.');": "", + " }": "", + "}": "", + "export function getTelegramUser() {": "", + " return tg?.initDataUnsafe?.user || null;": "", + "}": "", + "export function getAuthHeaders() {": "", + " const headers = {};": "", + " if (tg && tg.initData) {": "", + " headers['X-Telegram-Init-Data'] = tg.initData;": "", + " }": "", + " // Also check if we have a token stored in localStorage (for desktop browser access)": "", + " const token = localStorage.getItem('finance_auth_token');": "", + " if (token) {": "", + " headers['Authorization'] = `Bearer ${token}`;": "", + " }": "", + " return headers;": "", + "}": "", + "export function saveTokenFromUrl() {": "", + " const params = new URLSearchParams(window.location.search);": "", + " const token = params.get('token');": "", + " if (token) {": "", + " localStorage.setItem('finance_auth_token', token);": "", + " // Clean up url": "", + " window.history.replaceState({}, document.title, window.location.pathname);": "", + " return token;": "", + " }": "", + " return localStorage.getItem('finance_auth_token');": "", + "}": "", + "export function logout() {": "", + " localStorage.removeItem('finance_auth_token');": "", + " window.location.reload();": "", + "}": "", + "/**\n * Generates markup for a Telegram message with an 'Add Expense' button.\n */": "", + "export function getExpenseButtonMarkup() {": "", + " return `\n \n \n Please enter the expense amount and description:\n \n \n \n`;": "", + "}": "" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e1299ad --- /dev/null +++ b/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "Finance-bot", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "node-telegram-bot-api": "^1.2.0" + } + }, + "node_modules/node-telegram-bot-api": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-1.2.0.tgz", + "integrity": "sha512-M6S61LZn1FQMQnZSdFlc4oV+mwDGlPTbLzq/GUaSH4ew40wGTaKPtAaLp5oOhl/C3k0ylGqMIppJsVulwTCePg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9437f87 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "node-telegram-bot-api": "^1.2.0" + } +}