telegram-shop/src/handlers/adminProductHandler.js
2024-11-19 05:01:13 +03:00

969 lines
36 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import db from '../config/database.js';
import config from '../config/config.js';
import fs from 'fs/promises';
import User from "../models/User.js";
export default class AdminProductHandler {
constructor(bot) {
this.bot = bot;
this.userStates = new Map();
}
isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
async handleProductManagement(msg) {
const chatId = msg.chat?.id || msg.message?.chat.id;
if (!this.isAdmin(msg.from?.id || msg.message?.from.id)) {
await this.bot.sendMessage(chatId, 'Unauthorized access.');
return;
}
try {
const countries = await db.allAsync(
'SELECT DISTINCT country FROM locations ORDER BY country'
);
if (countries.length === 0) {
await this.bot.sendMessage(
chatId,
'No locations available. Please add locations first.',
{
reply_markup: {
inline_keyboard: [[
{text: '📍 Manage Locations', callback_data: 'view_locations'}
]]
}
}
);
return;
}
const keyboard = {
inline_keyboard: countries.map(loc => [{
text: loc.country,
callback_data: `prod_country_${loc.country}`
}])
};
await this.bot.sendMessage(
chatId,
'🌍 Select country to manage products:',
{reply_markup: keyboard}
);
} catch (error) {
console.error('Error in handleProductManagement:', error);
await this.bot.sendMessage(chatId, 'Error loading locations. Please try again.');
}
}
async handleCountrySelection(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const country = callbackQuery.data.replace('prod_country_', '');
try {
const cities = await db.allAsync(
'SELECT DISTINCT city FROM locations WHERE country = ? ORDER BY city',
[country]
);
const keyboard = {
inline_keyboard: [
...cities.map(loc => [{
text: loc.city,
callback_data: `prod_city_${country}_${loc.city}`
}]),
[{text: '« Back', callback_data: 'manage_products'}]
]
};
await this.bot.editMessageText(
`🏙 Select city in ${country}:`,
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
} catch (error) {
console.error('Error in handleCountrySelection:', error);
await this.bot.sendMessage(chatId, 'Error loading cities. Please try again.');
}
}
async handleCitySelection(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const [country, city] = callbackQuery.data.replace('prod_city_', '').split('_');
try {
const districts = await db.allAsync(
'SELECT district FROM locations WHERE country = ? AND city = ? ORDER BY district',
[country, city]
);
const keyboard = {
inline_keyboard: [
...districts.map(loc => [{
text: loc.district,
callback_data: `prod_district_${country}_${city}_${loc.district}`
}]),
[{text: '« Back', callback_data: `prod_country_${country}`}]
]
};
await this.bot.editMessageText(
`📍 Select district in ${city}:`,
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
} catch (error) {
console.error('Error in handleCitySelection:', error);
await this.bot.sendMessage(chatId, 'Error loading districts. Please try again.');
}
}
async handleDistrictSelection(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const [country, city, district] = callbackQuery.data.replace('prod_district_', '').split('_');
try {
const location = await db.getAsync(
'SELECT id FROM locations WHERE country = ? AND city = ? AND district = ?',
[country, city, district]
);
if (!location) {
throw new Error('Location not found');
}
const categories = await db.allAsync(
'SELECT id, name FROM categories WHERE location_id = ? ORDER BY name',
[location.id]
);
const keyboard = {
inline_keyboard: [
...categories.map(cat => [{
text: cat.name,
callback_data: `prod_category_${location.id}_${cat.id}`
}]),
[{text: ' Add Category', callback_data: `add_category_${location.id}`}],
[{text: '« Back', callback_data: `prod_city_${country}_${city}`}]
]
};
await this.bot.editMessageText(
'📦 Select or add category:',
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
} catch (error) {
console.error('Error in handleDistrictSelection:', error);
await this.bot.sendMessage(chatId, 'Error loading categories. Please try again.');
}
}
async handleCategoryInput(msg) {
const chatId = msg.chat.id;
const state = this.userStates.get(chatId);
if (!state || !state.action?.startsWith('add_category_')) return false;
try {
const locationId = state.action.replace('add_category_', '');
await db.runAsync(
'INSERT INTO categories (location_id, name) VALUES (?, ?)',
[locationId, msg.text]
);
const location = await db.getAsync(
'SELECT country, city, district FROM locations WHERE id = ?',
[locationId]
);
await this.bot.sendMessage(
chatId,
`✅ Category "${msg.text}" added successfully!`,
{
reply_markup: {
inline_keyboard: [[
{
text: '« Back to Categories',
callback_data: `prod_district_${location.country}_${location.city}_${location.district}`
}
]]
}
}
);
this.userStates.delete(chatId);
} catch (error) {
if (error.code === 'SQLITE_CONSTRAINT') {
await this.bot.sendMessage(chatId, 'This category already exists in this location.');
} else {
console.error('Error adding category:', error);
await this.bot.sendMessage(chatId, 'Error adding category. Please try again.');
}
}
return true;
}
async handleAddCategory(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const locationId = callbackQuery.data.replace('add_category_', '');
this.userStates.set(chatId, {action: `add_category_${locationId}`});
await this.bot.editMessageText(
'Please enter the name for the new category:',
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: {
inline_keyboard: [[
{text: '❌ Cancel', callback_data: `prod_district_${locationId}`}
]]
}
}
);
}
async handleCategorySelection(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const [locationId, categoryId] = callbackQuery.data.replace('prod_category_', '').split('_');
try {
const subcategories = await db.allAsync(
'SELECT id, name FROM subcategories WHERE category_id = ? ORDER BY name',
[categoryId]
);
const category = await db.getAsync('SELECT name FROM categories WHERE id = ?', [categoryId]);
const location = await db.getAsync('SELECT country, city, district FROM locations WHERE id = ?', [locationId]);
const keyboard = {
inline_keyboard: [
...subcategories.map(sub => [{
text: sub.name,
callback_data: `prod_subcategory_${locationId}_${categoryId}_${sub.id}`
}]),
[{text: ' Add Subcategory', callback_data: `add_subcategory_${locationId}_${categoryId}`}],
[{text: '✏️ Edit Category', callback_data: `edit_category_${locationId}_${categoryId}`}],
[{
text: '« Back',
callback_data: `prod_district_${location.country}_${location.city}_${location.district}`
}]
]
};
await this.bot.editMessageText(
`📦 Category: ${category.name}\nSelect or add subcategory:`,
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
} catch (error) {
console.error('Error in handleCategorySelection:', error);
await this.bot.sendMessage(chatId, 'Error loading subcategories. Please try again.');
}
}
async handleSubcategoryInput(msg) {
const chatId = msg.chat.id;
const state = this.userStates.get(chatId);
if (!state || !state.action?.startsWith('add_subcategory_')) return false;
try {
const [locationId, categoryId] = state.action.replace('add_subcategory_', '').split('_');
await db.runAsync(
'INSERT INTO subcategories (category_id, name) VALUES (?, ?)',
[categoryId, msg.text]
);
await this.bot.sendMessage(
chatId,
`✅ Subcategory "${msg.text}" added successfully!`,
{
reply_markup: {
inline_keyboard: [[
{
text: '« Back to Subcategories',
callback_data: `prod_category_${locationId}_${categoryId}`
}
]]
}
}
);
this.userStates.delete(chatId);
} catch (error) {
if (error.code === 'SQLITE_CONSTRAINT') {
await this.bot.sendMessage(chatId, 'This subcategory already exists in this category.');
} else {
console.error('Error adding subcategory:', error);
await this.bot.sendMessage(chatId, 'Error adding subcategory. Please try again.');
}
}
return true;
}
async handleAddSubcategory(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const [locationId, categoryId] = callbackQuery.data.replace('add_subcategory_', '').split('_');
this.userStates.set(chatId, {action: `add_subcategory_${locationId}_${categoryId}`});
await this.bot.editMessageText(
'Please enter the name for the new subcategory:',
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: {
inline_keyboard: [[
{text: '❌ Cancel', callback_data: `prod_category_${locationId}_${categoryId}`}
]]
}
}
);
}
async viewProductsPage(locationId, categoryId, subcategoryId, page) {
try {
const limit = 10;
const offset = (page || 0) * limit;
const previousPage = page > 0 ? page - 1 : 0;
const nextPage = page + 1;
const products = await db.allAsync(
`SELECT id, name, price, quantity_in_stock
FROM products
WHERE location_id = ? AND category_id = ? AND subcategory_id = ?
ORDER BY name
LIMIT ?
OFFSET ?
`,
[locationId, categoryId, subcategoryId, limit, offset]
);
if ((products.length === 0) && (page == 0)) {
return {
text: 'No products for this location',
markup: {
inline_keyboard: [
[{
text: '📥 Import Products',
callback_data: `add_product_${locationId}_${categoryId}_${subcategoryId}`
}],
[{text: '« Back', callback_data: `prod_category_${locationId}_${categoryId}`}]
]
}
};
}
if ((products.length === 0) && (page > 0)) {
return await this.viewProductsPage(locationId, categoryId, subcategoryId, previousPage);
}
const subcategory = await db.getAsync('SELECT name FROM subcategories WHERE id = ?', [subcategoryId]);
const category = await db.getAsync('SELECT name FROM categories WHERE id = ?', [categoryId]);
const keyboard = {
inline_keyboard: [
...products.map(prod => [{
text: `${prod.name} - $${prod.price} (${prod.quantity_in_stock} left)`,
callback_data: `view_product_${prod.id}`
}]),
[{
text: '📥 Import Products',
callback_data: `add_product_${locationId}_${categoryId}_${subcategoryId}`
}],
]
};
keyboard.inline_keyboard.push([
{
text: `«`,
callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${previousPage}`
},
{text: `»`, callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${nextPage}`},
]);
keyboard.inline_keyboard.push([
{text: '« Back', callback_data: `prod_category_${locationId}_${categoryId}`}
]);
return {
text: `📦 ${category.name} > ${subcategory.name}\nSelect product or import new ones:`,
markup: keyboard
}
} catch (error) {
console.error('Error in handleSubcategorySelection:', error);
return {text: 'Error loading products. Please try again.'};
}
}
async handleSubcategorySelection(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const [locationId, categoryId, subcategoryId] = callbackQuery.data.replace('prod_subcategory_', '').split('_');
const state = this.userStates.get(chatId)
for (const msgId of state?.msgToDelete || []) {
try {
await this.bot.deleteMessage(chatId, msgId);
} catch (e) {
// ignore if can't delete
}
}
this.userStates.delete(chatId);
try {
const {text, markup} = await this.viewProductsPage(locationId, categoryId, subcategoryId, 0);
await this.bot.editMessageText(
text,
{
chat_id: chatId,
message_id: messageId,
reply_markup: markup
}
);
} catch (error) {
console.error('Error in handleSubcategorySelection:', error);
await this.bot.sendMessage(chatId, 'Error loading products. Please try again.');
}
}
async handleProductListPage(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) {
return;
}
const chatId = callbackQuery.message.chat.id;
const [locationId, categoryId, subcategoryId, page] = callbackQuery.data.replace('list_products_', '').split("_");
try {
const {text, markup} = await this.viewProductsPage(locationId, categoryId, subcategoryId, parseInt(page));
await this.bot.editMessageText(text, {
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: markup,
parse_mode: 'HTML'
});
} catch (e) {
return;
}
}
async handleAddProduct(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const [locationId, categoryId, subcategoryId] = callbackQuery.data.replace('add_product_', '').split('_');
try {
const location = await db.getAsync(
'SELECT country, city, district FROM locations WHERE id = ?',
[locationId]
);
const category = await db.getAsync('SELECT name FROM categories WHERE id = ?', [categoryId]);
const subcategory = await db.getAsync('SELECT name FROM subcategories WHERE id = ?', [subcategoryId]);
const sampleProducts = [
{
name: "Sample Product 1",
price: 100,
description: "Product description",
private_data: "Hidden details about the product",
quantity_in_stock: 10,
photo_url: "https://example.com/photo.jpg",
hidden_photo_url: "https://example.com/hidden.jpg",
hidden_coordinates: "40.7128,-74.0060",
hidden_description: "Secret location details"
}
];
const jsonExample = JSON.stringify(sampleProducts, null, 2);
const message = `To import products, send a JSON file with an array of products in the following format:\n\n<pre>${jsonExample}</pre>\n\nEach product must have all the fields shown above.\n\nYou can either:\n1. Send the JSON as text\n2. Upload a .json file`;
this.userStates.set(chatId, {
action: 'import_products',
locationId,
categoryId,
subcategoryId
});
await this.bot.editMessageText(message, {
chat_id: chatId,
message_id: messageId,
parse_mode: 'HTML',
reply_markup: {
inline_keyboard: [[
{
text: '❌ Cancel',
callback_data: `prod_subcategory_${locationId}_${categoryId}_${subcategoryId}`
}
]]
}
});
} catch (error) {
console.error('Error in handleAddProduct:', error);
await this.bot.sendMessage(chatId, 'Error preparing product import. Please try again.');
}
}
async handleProductImport(msg) {
const chatId = msg.chat.id;
const state = this.userStates.get(chatId);
if (!state || state.action !== 'import_products') return false;
try {
let products;
let jsonContent;
// Handle file upload
if (msg.document) {
if (!msg.document.file_name.endsWith('.json')) {
await this.bot.sendMessage(chatId, 'Please upload a .json file.');
return true;
}
const file = await this.bot.getFile(msg.document.file_id);
const fileContent = await this.bot.downloadFile(file.file_id, '.');
jsonContent = await fs.readFile(fileContent, 'utf8');
await fs.rm(fileContent);
} else if (msg.text) {
jsonContent = msg.text;
} else {
await this.bot.sendMessage(chatId, 'Please send either a JSON file or JSON text.');
return true;
}
try {
products = JSON.parse(jsonContent);
if (!Array.isArray(products)) {
throw new Error('Input must be an array of products');
}
} catch (e) {
await this.bot.sendMessage(chatId, 'Invalid JSON format. Please check the format and try again.');
return true;
}
await db.runAsync('BEGIN TRANSACTION');
for (const product of products) {
await db.runAsync(
`INSERT INTO products (
location_id, category_id, subcategory_id,
name, price, description, private_data,
quantity_in_stock, photo_url, hidden_photo_url,
hidden_coordinates, hidden_description
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
state.locationId, state.categoryId, state.subcategoryId,
product.name, product.price, product.description, product.private_data,
product.quantity_in_stock, product.photo_url, product.hidden_photo_url,
product.hidden_coordinates, product.hidden_description
]
);
}
await db.runAsync('COMMIT');
await this.bot.sendMessage(
chatId,
`✅ Successfully imported ${products.length} products!`,
{
reply_markup: {
inline_keyboard: [[
{
text: '« Back to Products',
callback_data: `prod_subcategory_${state.locationId}_${state.categoryId}_${state.subcategoryId}`
}
]]
}
}
);
this.userStates.delete(chatId);
} catch (error) {
console.error('Error importing products:', error);
await this.bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.');
await db.runAsync('ROLLBACK');
}
return true;
}
async handleProductEditImport(msg) {
const chatId = msg.chat.id;
const state = this.userStates.get(chatId);
if (!state || state.action !== 'edit_product') return false;
try {
let product;
let jsonContent;
// Handle file upload
if (msg.document) {
if (!msg.document.file_name.endsWith('.json')) {
await this.bot.sendMessage(chatId, 'Please upload a .json file.');
return true;
}
const file = await this.bot.getFile(msg.document.file_id);
const fileContent = await this.bot.downloadFile(file.file_id, '.');
jsonContent = await fs.readFile(fileContent, 'utf8');
await fs.rm(fileContent);
} else if (msg.text) {
jsonContent = msg.text;
} else {
await this.bot.sendMessage(chatId, 'Please send either a JSON file or JSON text.');
return true;
}
try {
product = JSON.parse(jsonContent);
} catch (e) {
await this.bot.sendMessage(chatId, 'Invalid JSON format. Please check the format and try again.');
return true;
}
await db.runAsync('BEGIN TRANSACTION');
await db.runAsync(
`UPDATE products SET
location_id = ?,
category_id = ?,
subcategory_id = ?,
name = ?,
price = ?,
description = ?,
private_data = ?,
quantity_in_stock = ?,
photo_url = ?,
hidden_photo_url = ?,
hidden_coordinates = ?,
hidden_description = ?
WHERE
id = ?
`,
[
state.locationId, state.categoryId, state.subcategoryId,
product.name, product.price, product.description, product.private_data,
product.quantity_in_stock, product.photo_url, product.hidden_photo_url,
product.hidden_coordinates, product.hidden_description, state.productId
]
);
await db.runAsync('COMMIT');
await this.bot.sendMessage(
chatId,
`✅ Successfully edited!`,
{
reply_markup: {
inline_keyboard: [[
{
text: '« Back to Products',
callback_data: `prod_subcategory_${state.locationId}_${state.categoryId}_${state.subcategoryId}`
}
]]
}
}
);
this.userStates.delete(chatId);
} catch (error) {
console.error('Error importing products:', error);
await this.bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.');
await db.runAsync('ROLLBACK');
}
return true;
}
async handleViewProduct(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const productId = callbackQuery.data.replace('view_product_', '');
try {
const product = await db.getAsync(
`SELECT p.*, c.name as category_name, s.name as subcategory_name,
l.country, l.city, l.district
FROM products p
JOIN categories c ON p.category_id = c.id
JOIN subcategories s ON p.subcategory_id = s.id
JOIN locations l ON p.location_id = l.id
WHERE p.id = ?`,
[productId]
);
if (!product) {
throw new Error('Product not found');
}
const message = `
📦 Product Details:
Name: ${product.name}
Price: $${product.price}
Description: ${product.description}
Stock: ${product.quantity_in_stock}
Location: ${product.country}, ${product.city}, ${product.district}
Category: ${product.category_name}
Subcategory: ${product.subcategory_name}
🔒 Private Information:
${product.private_data}
Hidden Location: ${product.hidden_description}
Coordinates: ${product.hidden_coordinates}
`;
const keyboard = {
inline_keyboard: [
[
{text: '✏️ Edit', callback_data: `edit_product_${productId}`},
{text: '❌ Delete', callback_data: `delete_product_${productId}`}
],
[{
text: '« Back',
callback_data: `prod_subcategory_${product.location_id}_${product.category_id}_${product.subcategory_id}`
}]
]
};
let photoMessage;
let hiddenPhotoMessage;
// Send product photos
if (product.photo_url) {
try {
photoMessage = await this.bot.sendPhoto(chatId, product.photo_url, {caption: 'Public photo'});
} catch (e) {
photoMessage = await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Public photo'})
}
}
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'})
}
}
this.userStates.set(chatId, {
msgToDelete: [photoMessage.message_id, hiddenPhotoMessage.message_id]
})
await this.bot.deleteMessage(chatId, messageId);
await this.bot.sendMessage(chatId, message, {reply_markup: keyboard});
} catch (error) {
console.error('Error in handleViewProduct:', error);
await this.bot.sendMessage(chatId, 'Error loading product details. Please try again.');
}
}
async handleProductEdit(callbackQuery) {
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const productId = callbackQuery.data.replace('edit_product_', '');
try {
const product = await db.getAsync(
`SELECT p.*, c.name as category_name, s.name as subcategory_name,
l.country, l.city, l.district
FROM products p
JOIN categories c ON p.category_id = c.id
JOIN subcategories s ON p.subcategory_id = s.id
JOIN locations l ON p.location_id = l.id
WHERE p.id = ?`,
[productId]
);
if (!product) {
throw new Error('Product not found');
}
const locationId = product.location_id;
const categoryId = product.category_id;
const subcategoryId = product.subcategory_id;
const sampleProduct = {
name: "Sample Product 1",
price: 100,
description: "Product description",
private_data: "Hidden details about the product",
quantity_in_stock: 10,
photo_url: "https://example.com/photo.jpg",
hidden_photo_url: "https://example.com/hidden.jpg",
hidden_coordinates: "40.7128,-74.0060",
hidden_description: "Secret location details"
}
const jsonExample = JSON.stringify(sampleProduct, null, 2);
const message = `To edit product, send a JSON file with product in the following format:\n\n<pre>${jsonExample}</pre>\n\nProduct must have all the fields shown above.\n\nYou can either:\n1. Send the JSON as text\n2. Upload a .json file`;
this.userStates.set(chatId, {
action: 'edit_product',
locationId,
categoryId,
subcategoryId,
productId
});
await this.bot.editMessageText(message, {
chat_id: chatId,
message_id: messageId,
parse_mode: 'HTML',
reply_markup: {
inline_keyboard: [[
{
text: '❌ Cancel',
callback_data: `prod_subcategory_${locationId}_${categoryId}_${subcategoryId}`
}
]]
}
});
} catch (error) {
console.error('Error in handleViewProduct:', error);
await this.bot.sendMessage(chatId, 'Error loading product details. Please try again.');
}
}
async handleProductDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) return;
const productId = callbackQuery.data.replace('delete_product_', '');
const chatId = callbackQuery.message.chat.id;
try {
const product = await db.getAsync(
`SELECT p.*, c.name as category_name, s.name as subcategory_name,
l.country, l.city, l.district
FROM products p
JOIN categories c ON p.category_id = c.id
JOIN subcategories s ON p.subcategory_id = s.id
JOIN locations l ON p.location_id = l.id
WHERE p.id = ?`,
[productId]
);
if (!product) {
throw new Error('Product not found');
}
const keyboard = {
inline_keyboard: [
[
{text: '✅ Confirm Delete', callback_data: `confirm_delete_product_${productId}`},
{
text: '❌ Cancel',
callback_data: `prod_subcategory_${product.location_id}_${product.category_id}_${product.subcategory_id}`
}
]
]
};
await this.bot.editMessageText(
`⚠️ Are you sure you want to delete product\n\nThis action cannot be undone!`,
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: keyboard,
parse_mode: 'HTML'
}
);
} catch (error) {
console.error('Error in handleDeleteUser:', error);
await this.bot.sendMessage(chatId, 'Error processing delete request. Please try again.');
}
}
async handleConfirmDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) return;
const productId = callbackQuery.data.replace('confirm_delete_product_', '');
const chatId = callbackQuery.message.chat.id;
try {
const product = await db.getAsync(
`SELECT p.*, c.name as category_name, s.name as subcategory_name,
l.country, l.city, l.district
FROM products p
JOIN categories c ON p.category_id = c.id
JOIN subcategories s ON p.subcategory_id = s.id
JOIN locations l ON p.location_id = l.id
WHERE p.id = ?`,
[productId]
);
if (!product) {
throw new Error('Product not found');
}
try {
await db.runAsync('BEGIN TRANSACTION');
await db.runAsync('DELETE FROM products WHERE id=?', [productId.toString()]);
await db.runAsync('COMMIT');
} catch (e) {
await db.runAsync("ROLLBACK");
console.error('Error deleting product:', error);
throw error;
}
const keyboard = {
inline_keyboard: [
[{
text: '« Back',
callback_data: `prod_subcategory_${product.location_id}_${product.category_id}_${product.subcategory_id}`
}]
]
};
await this.bot.editMessageText(
`✅ Product has been successfully deleted.`,
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: keyboard
}
);
} catch (error) {
console.error('Error in handleConfirmDelete:', error);
await this.bot.sendMessage(chatId, 'Error deleting product. Please try again.');
}
}
}