From 1cb0467f6c228f4ae0ecb9c79f1314682f839508 Mon Sep 17 00:00:00 2001 From: Artyom Ashirov <1323ED5@gmail.com> Date: Wed, 20 Nov 2024 17:43:51 +0300 Subject: [PATCH 1/2] purchase viewing --- src/handlers/userPurchaseHandler.js | 197 ++++++++++++++++++++++++++++ src/index.js | 10 +- 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/handlers/userPurchaseHandler.js diff --git a/src/handlers/userPurchaseHandler.js b/src/handlers/userPurchaseHandler.js new file mode 100644 index 0000000..92f5e04 --- /dev/null +++ b/src/handlers/userPurchaseHandler.js @@ -0,0 +1,197 @@ +import db from '../config/database.js'; +import User from '../models/User.js'; +import WalletService from "../utils/walletService.js"; +import config from "../config/config.js"; + +export default class UserPurchaseHandler { + constructor(bot) { + this.bot = bot; + this.userStates = new Map(); + } + + async viewPurchasePage(userId, page) { + try { + const limit = 10; + const offset = (page || 0) * limit; + + const previousPage = page > 0 ? page - 1 : 0; + const nextPage = page + 1; + + const purchases = await db.allAsync(` + SELECT + p.*, + pr.name as product_name, + pr.description, + l.country, + l.city, + l.district + FROM purchases p + JOIN products pr ON p.product_id = pr.id + JOIN locations l ON pr.location_id = l.id + WHERE p.user_id = ? + ORDER BY p.purchase_date DESC + LIMIT ? + OFFSET ? + `, [userId, limit, offset]); + + if ((purchases.length === 0) && (page == 0)) { + return { + text: 'You haven\'t made any purchases yet.', + markup: [[ + {text: '๐Ÿ› Browse Products', callback_data: 'shop_start'} + ]] + } + } + + if ((purchases.length === 0) && (page > 0)) { + return await this.viewPurchasePage(userId, previousPage); + } + + const keyboard = { + inline_keyboard: [ + ...purchases.map(item => [{ + text: `${item.product_name} [${new Date(item.purchase_date).toLocaleString()}]`, + callback_data: `view_purchase_${item.id}` + }]), + ] + }; + + keyboard.inline_keyboard.push([ + {text: `ยซ`, callback_data: `list_purchases_${previousPage}`}, + {text: `ยป`, callback_data: `list_purchases_${nextPage}`}, + ]); + + keyboard.inline_keyboard.push([ + {text: '๐Ÿ› Browse Products', callback_data: 'shop_start'} + ]); + + return { + text: `๐Ÿ“ฆ Select purchase to view detailed information:`, + markup: keyboard + } + + } catch (error) { + console.error('Error in showPurchases:', error); + return {text: 'Error loading purchase history. Please try again.'}; + } + } + + async handlePurchaseListPage(callbackQuery) { + const telegramId = callbackQuery.from.id; + const chatId = callbackQuery.message.chat.id; + + const page = callbackQuery.data.replace('list_purchases_', ''); + + try { + const user = await User.getById(telegramId); + + if (!user) { + await this.bot.sendMessage(chatId, 'User not found.'); + return; + } + + const {text, markup} = await this.viewPurchasePage(user.id, parseInt(page)); + await this.bot.editMessageText(text, { + chat_id: chatId, + message_id: callbackQuery.message.message_id, + reply_markup: markup, + parse_mode: 'Markdown', + }); + } catch (e) { + return; + } + } + + async showPurchases(msg) { + // const userId = callbackQuery.from.id; + // const chatId = callbackQuery.message.chat.id; + + const chatId = msg.chat.id; + const telegramId = msg.from.id; + + try { + + const user = await User.getById(telegramId); + + if (!user) { + await this.bot.sendMessage(chatId, 'User not found.'); + return; + } + + const {text, markup} = await this.viewPurchasePage(user.id, 0); + + await this.bot.sendMessage(chatId, text, {reply_markup: markup, parse_mode: 'Markdown'}); + } catch (error) { + console.error('Error in handleSubcategorySelection:', error); + await this.bot.sendMessage(chatId, 'Error loading products. Please try again.'); + } + } + + async viewPurchase(callbackQuery) { + const chatId = callbackQuery.message.chat.id; + const purchaseId = callbackQuery.data.replace('view_purchase_', ''); + + const purchase = await db.getAsync(` + SELECT + p.*, + pr.name as product_name, + pr.description, + l.country, + l.city, + l.district + FROM purchases p + JOIN products pr ON p.product_id = pr.id + JOIN locations l ON pr.location_id = l.id + WHERE p.id = ? + `, [purchaseId]); + + if (!purchase) { + await this.bot.sendMessage(chatId, "No such purchase"); + return; + } + + const product = await db.getAsync( + `SELECT * FROM products WHERE id = ?`, + [purchase.product_id] + ); + + if (!product) { + await this.bot.sendMessage(chatId, "No such product"); + return; + } + + let hiddenPhotoMessage; + if (product.hidden_photo_url) { + try { + hiddenPhotoMessage = await this.bot.sendPhoto(chatId, product.hidden_photo_url, {caption: 'Hidden photo'}); + } catch (e) { + hiddenPhotoMessage = await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Hidden photo'}) + } + } + + const message = ` +๐Ÿ“ฆ Purchase Details: +Name: ${purchase.product_name} +Quantity: ${purchase.quantity} +Total: $${purchase.total_price} +Location: ${purchase.country}, ${purchase.city} +Payment: ${purchase.wallet_type} +Date: ${new Date(purchase.purchase_date).toLocaleString()} + +๐Ÿ”’ Private Information: +${product.private_data} +Hidden Location: ${product.hidden_description} +Coordinates: ${product.hidden_coordinates} +`; + + const keyboard = { + inline_keyboard: [ + [{text: "I've got it!", callback_data: "Asdasdasd"}], + [{text: "Contact support", url: config.SUPPORT_LINK}] + ] + }; + + await this.bot.sendMessage(chatId, message, {reply_markup: keyboard}); + await this.bot.deleteMessage(chatId, callbackQuery.message.message_id); + } +} diff --git a/src/index.js b/src/index.js index d6414dc..b16f899 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ import ErrorHandler from './utils/errorHandler.js'; import User from './models/User.js'; import AdminUserLocationHandler from "./handlers/adminUserLocationHandler.js"; import AdminDumpHandler from "./handlers/adminDumpHandler.js"; +import UserPurchaseHandler from "./handlers/userPurchaseHandler.js"; // Debug logging function const logDebug = (action, functionName) => { @@ -41,6 +42,7 @@ const adminLocationHandler = new AdminLocationHandler(bot); const adminUserLocationHandler = new AdminUserLocationHandler(bot); const adminProductHandler = new AdminProductHandler(bot); const adminDumpHandler = new AdminDumpHandler(bot); +const userPurchaseHandler = new UserPurchaseHandler(bot); // Start command - Create user profile bot.onText(/\/start/, async (msg) => { @@ -125,7 +127,7 @@ bot.on('message', async (msg) => { await userWalletsHandler.showBalance(msg); break; case '๐Ÿ› Purchases': - await userProductHandler.showPurchases(msg); + await userPurchaseHandler.showPurchases(msg); break; case '๐Ÿ“ฆ Manage Products': if (adminHandler.isAdmin(msg.from.id)) { @@ -242,6 +244,12 @@ bot.on('callback_query', async (callbackQuery) => { } else if (action.startsWith('pay_with_')) { logDebug(action, 'handlePay'); await userProductHandler.handlePay(callbackQuery); + } else if (action.startsWith('list_purchases_')) { + logDebug(action, 'handlePurchaseListPage'); + await userPurchaseHandler.handlePurchaseListPage(callbackQuery); + } else if (action.startsWith('view_purchase_')) { + logDebug(action, 'viewPurchase'); + await userPurchaseHandler.viewPurchase(callbackQuery); } // Admin location management else if (action === 'add_location') { From 627f9e417eb8b3bf9e431ff95da46f1f7e49ecab Mon Sep 17 00:00:00 2001 From: Artyom Ashirov <1323ED5@gmail.com> Date: Thu, 21 Nov 2024 13:24:04 +0300 Subject: [PATCH 2/2] Old purchase method removed --- src/handlers/userProductHandler.js | 64 ------------------------------ 1 file changed, 64 deletions(-) diff --git a/src/handlers/userProductHandler.js b/src/handlers/userProductHandler.js index e52272f..2cd8c1c 100644 --- a/src/handlers/userProductHandler.js +++ b/src/handlers/userProductHandler.js @@ -688,68 +688,4 @@ Coordinates: ${product.hidden_coordinates} await this.bot.sendMessage(chatId, 'Error processing purchase. Please try again.'); } } - - async showPurchases(msg) { - const chatId = msg.chat.id; - const userId = msg.from.id; - - try { - const user = await User.getById(userId); - if (!user) { - await this.bot.sendMessage(chatId, 'Profile not found. Please use /start to create one.'); - return; - } - - const purchases = await db.allAsync(` - SELECT p.*, pr.name as product_name, pr.description, - l.country, l.city, l.district - FROM purchases p - JOIN products pr ON p.product_id = pr.id - JOIN locations l ON pr.location_id = l.id - WHERE p.user_id = ? - ORDER BY p.purchase_date DESC - LIMIT 10 - `, [user.id]); - - if (purchases.length === 0) { - await this.bot.sendMessage( - chatId, - 'You haven\'t made any purchases yet.', - { - reply_markup: { - inline_keyboard: [[ - {text: '๐Ÿ› Browse Products', callback_data: 'shop_start'} - ]] - } - } - ); - return; - } - - let message = '๐Ÿ› *Your Recent Purchases:*\n\n'; - - for (const purchase of purchases) { - const date = new Date(purchase.purchase_date).toLocaleString(); - message += `๐Ÿ“ฆ *${purchase.product_name}*\n`; - message += `โ”œ Quantity: ${purchase.quantity}\n`; - message += `โ”œ Total: $${purchase.total_price}\n`; - message += `โ”œ Location: ${purchase.country}, ${purchase.city}\n`; - message += `โ”œ Payment: ${purchase.wallet_type}\n`; - message += `โ”œ TX: \`${purchase.tx_hash}\`\n`; - message += `โ”” Date: ${date}\n\n`; - } - - await this.bot.sendMessage(chatId, message, { - parse_mode: 'Markdown', - reply_markup: { - inline_keyboard: [[ - {text: '๐Ÿ› Browse Products', callback_data: 'shop_start'} - ]] - } - }); - } catch (error) { - console.error('Error in showPurchases:', error); - await this.bot.sendMessage(chatId, 'Error loading purchase history. Please try again.'); - } - } } \ No newline at end of file