Files
telegram-shop/src/handlers/adminHandlers/adminLocationHandler.js
Artyom Ashirov 5d4f56e265 refactoring
2024-11-23 05:03:30 +03:00

330 lines
9.4 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 Validators from '../../utils/validators.js';
import config from '../../config/config.js';
import userStates from "../../context/userStates.js";
import bot from "../../context/bot.js";
export default class AdminLocationHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleAddLocation(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) {
return;
}
const chatId = callbackQuery.message.chat.id;
userStates.set(chatId, { action: 'add_location' });
await bot.editMessageText(
'Please enter the location in the following format:\nCountry|City|District',
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: {
inline_keyboard: [[{ text: '« Back', callback_data: 'view_locations' }]]
}
}
);
}
static async handleLocationInput(msg) {
const chatId = msg.chat.id;
const state = userStates.get(chatId);
if (!state || state.action !== 'add_location') {
return false;
}
if (!this.isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.');
return;
}
const parts = msg.text.split('|').map(s => s.trim());
if (parts.length !== 3) {
await bot.sendMessage(
chatId,
'Invalid format. Please use: Country|City|District'
);
return true;
}
const [country, city, district] = parts;
if (!Validators.isValidLocation(country, city, district)) {
await bot.sendMessage(
chatId,
'Invalid location data. All fields are required.'
);
return true;
}
try {
await db.runAsync('BEGIN TRANSACTION');
const result = await db.runAsync(
'INSERT INTO locations (country, city, district) VALUES (?, ?, ?)',
[country, city, district]
);
await db.runAsync('COMMIT');
if (result.changes > 0) {
await bot.sendMessage(
chatId,
`✅ Location added successfully!\n\nCountry: ${country}\nCity: ${city}\nDistrict: ${district}`,
{
reply_markup: {
inline_keyboard: [
[{ text: ' Add Another Location', callback_data: 'add_location' }],
[{ text: '« Back to Locations', callback_data: 'view_locations' }]
]
}
}
);
} else {
throw new Error('Failed to insert location');
}
userStates.delete(chatId);
} catch (error) {
await db.runAsync('ROLLBACK');
if (error.code === 'SQLITE_CONSTRAINT') {
await bot.sendMessage(
chatId,
'❌ This location already exists.',
{
reply_markup: {
inline_keyboard: [[
{ text: 'Try Again', callback_data: 'add_location' }
]]
}
}
);
} else {
console.error('Error adding location:', error);
await bot.sendMessage(
chatId,
'❌ Error adding location. Please try again.',
{
reply_markup: {
inline_keyboard: [[
{ text: 'Try Again', callback_data: 'add_location' }
]]
}
}
);
}
}
return true;
}
static async handleViewLocations(msg) {
const chatId = msg.chat?.id || msg.message?.chat.id;
const messageId = msg.message?.message_id;
if (!this.isAdmin(msg.from?.id || msg.message?.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.');
return;
}
userStates.delete(chatId);
try {
const locations = await db.allAsync(`
SELECT l.*,
COUNT(DISTINCT p.id) as product_count,
COUNT(DISTINCT c.id) as category_count
FROM locations l
LEFT JOIN products p ON l.id = p.location_id
LEFT JOIN categories c ON l.id = c.location_id
GROUP BY l.id
ORDER BY l.country, l.city, l.district
`);
if (locations.length === 0) {
const message = 'No locations found.';
const keyboard = {
inline_keyboard: [[{ text: ' Add Location', callback_data: 'add_location' }]]
};
if (messageId) {
await bot.editMessageText(message, {
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
});
} else {
await bot.sendMessage(chatId, message, { reply_markup: keyboard });
}
return;
}
let currentCountry = '';
let message = '📍 *Locations List:*\n\n';
for (const loc of locations) {
if (loc.country !== currentCountry) {
currentCountry = loc.country;
message += `\n🌍 *${currentCountry}*\n`;
}
message += ` └ 🏙 ${loc.city} > ${loc.district}\n`;
message += ` ├ Products: ${loc.product_count}\n`;
message += ` └ Categories: ${loc.category_count}\n`;
}
const keyboard = {
inline_keyboard: [
[{ text: ' Add Location', callback_data: 'add_location' }],
[{ text: '❌ Delete Location', callback_data: 'delete_location' }],
[{ text: '« Back to Admin Menu', callback_data: 'admin_menu' }]
]
};
if (messageId) {
await bot.editMessageText(message, {
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard,
parse_mode: 'Markdown'
});
} else {
await bot.sendMessage(chatId, message, {
reply_markup: keyboard,
parse_mode: 'Markdown'
});
}
} catch (error) {
console.error('Error viewing locations:', error);
await bot.sendMessage(chatId, 'Error loading locations. Please try again.');
}
}
static async handleDeleteLocation(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) {
return;
}
const chatId = callbackQuery.message.chat.id;
try {
const locations = await db.allAsync(`
SELECT l.*,
COUNT(DISTINCT p.id) as product_count,
COUNT(DISTINCT c.id) as category_count
FROM locations l
LEFT JOIN products p ON l.id = p.location_id
LEFT JOIN categories c ON l.id = c.location_id
GROUP BY l.id
ORDER BY l.country, l.city, l.district
`);
const keyboard = {
inline_keyboard: locations.map(loc => [{
text: `${loc.country} > ${loc.city} > ${loc.district} (P:${loc.product_count} C:${loc.category_count})`,
callback_data: `confirm_delete_location_${loc.country}_${loc.city}_${loc.district}`
}])
};
keyboard.inline_keyboard.push([{ text: '« Back', callback_data: 'view_locations' }]);
await bot.editMessageText(
'❌ Select location to delete:\n\n*Note:* Deleting a location will also remove all associated products and categories!',
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: keyboard,
parse_mode: 'Markdown'
}
);
} catch (error) {
console.error('Error in handleDeleteLocation:', error);
await bot.sendMessage(chatId, 'Error loading locations. Please try again.');
}
}
static async handleConfirmDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) {
return;
}
const chatId = callbackQuery.message.chat.id;
const [country, city, district] = callbackQuery.data
.replace('confirm_delete_location_', '')
.split('_');
try {
await db.runAsync('BEGIN TRANSACTION');
const result = await db.runAsync(
'DELETE FROM locations WHERE country = ? AND city = ? AND district = ?',
[country, city, district]
);
await db.runAsync('COMMIT');
if (result.changes > 0) {
await bot.editMessageText(
`✅ Location deleted successfully!\n\nCountry: ${country}\nCity: ${city}\nDistrict: ${district}`,
{
chat_id: chatId,
message_id: callbackQuery.message.message_id,
reply_markup: {
inline_keyboard: [[{ text: '« Back to Locations', callback_data: 'view_locations' }]]
}
}
);
} else {
throw new Error('Location not found');
}
} catch (error) {
await db.runAsync('ROLLBACK');
console.error('Error deleting location:', error);
await bot.sendMessage(
chatId,
'❌ Error deleting location. Please try again.',
{
reply_markup: {
inline_keyboard: [[{ text: '« Back to Locations', callback_data: 'view_locations' }]]
}
}
);
}
}
static async backToMenu(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) {
return;
}
const chatId = callbackQuery.message.chat.id;
const messageId = callbackQuery.message.message_id;
const keyboard = {
reply_markup: {
keyboard: [
['👥 Manage Users', '📦 Manage Products'],
['💰 Manage Wallets', '📍 Manage Locations'],
['💾 Database Backup']
],
resize_keyboard: true
}
};
await bot.editMessageText(
`You we're returned to the admin menu`,
{
chat_id: chatId,
message_id: messageId,
reply_markup: keyboard
}
);
userStates.delete(chatId);
}
}