330 lines
9.4 KiB
JavaScript
330 lines
9.4 KiB
JavaScript
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);
|
||
}
|
||
} |