Skip to content
Open
8 changes: 4 additions & 4 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getServerCounters, saveServerCounters, updateCounter } from './services
import { logger, startupLog, shutdownLog } from './utils/logger.js';
import { checkBirthdays } from './services/birthdayService.js';
import { checkGiveaways } from './services/giveawayService.js';
import { loadCommands, registerCommands as registerSlashCommands } from './handlers/loaders/commandLoader.js';
import { loadCommands, registerCommands as registerGlobalSlashCommands } from './handlers/loaders/commandLoader.js';
import { runSafeTask, handleTaskError, ErrorCodes } from './utils/errorHandler.js';
import { initializeMusic } from './services/music/riffySetup.js';
import { shutdownMusic } from './services/music/playerHandler.js';
Expand Down Expand Up @@ -324,9 +324,9 @@ class TitanBot extends Client {

async registerCommands() {
try {
await registerSlashCommands(this, { clientId: this.config.bot.clientId });
await registerGlobalSlashCommands(this, { clientId: this.config.bot.clientId });
} catch (error) {
logger.error('Error registering commands:', error);
logger.error('Error registering slash commands:', error);
}
}

Expand Down Expand Up @@ -428,4 +428,4 @@ try {
process.exit(1);
}

export default TitanBot;
export default TitanBot;
1 change: 0 additions & 1 deletion src/commands/Community/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ function getApplicationStatusPresentation(statusValue) {
}

export default {
slashOnly: true,
data: new SlashCommandBuilder()
.setName("apply")
.setDescription("Manage role applications")
Expand Down
1 change: 0 additions & 1 deletion src/commands/Community/modules/app_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ async function refreshDashboard(rootInteraction, settings, roles, guildId, clien
}

export default {
prefixOnly: false,
async execute(interaction, config, client, selectedAppName = null) {
try {
const guildId = interaction.guild.id;
Expand Down
1 change: 0 additions & 1 deletion src/commands/Core/configWizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,6 @@ async function handleSettingModalSubmit(selectInteraction, rootInteraction, sett
}

export default {
slashOnly: true,
data: new SlashCommandBuilder()
.setName('configwizard')
.setDescription('Open the server configuration dashboard and setup wizard')
Expand Down
1 change: 0 additions & 1 deletion src/commands/Core/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ export async function createInitialHelpMenu(client) {
}

export default {
slashOnly: true,
data: new SlashCommandBuilder()
.setName("help")
.setDescription("Displays the help menu with all available commands"),
Expand Down
45 changes: 42 additions & 3 deletions src/commands/Economy/buy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ import { withErrorHandling, createError, ErrorTypes } from '../../utils/errorHan
import { InteractionHelper } from '../../utils/interactionHelper.js';

const SHOP_ITEMS = shopItems;
const LUCK_POTION_IDS = new Set([
'luck_potion_1',
'luck_potion_2',
'luck_potion_3',
'luck_potion_4',
'luck_potion_5',
]);
const DEFAULT_LUCK_POTION_DURATION_MS = 5 * 60 * 1000;

export default {
data: new SlashCommandBuilder()
Expand All @@ -28,7 +36,9 @@ export default {
),

execute: withErrorHandling(async (interaction, config, client) => {
const deferred = await InteractionHelper.safeDefer(interaction);
const deferred = await InteractionHelper.safeDefer(interaction, {
flags: MessageFlags.Ephemeral,
});
if (!deferred) return;

const userId = interaction.user.id;
Expand Down Expand Up @@ -62,6 +72,8 @@ export default {
const PREMIUM_ROLE_ID = guildConfig.premiumRoleId;

const userData = await getEconomyData(client, guildId, userId);
const alreadyOwnsFishingRod = userData.fishingRodOwned === true
|| Number(userData.inventory?.fishing_rod || 0) > 0;

if (userData.wallet < totalCost) {
throw createError(
Expand Down Expand Up @@ -136,6 +148,14 @@ export default {
} else if (item.type === "upgrade") {
userData.upgrades[itemId] = true;
successDescription += `\n\n**✨ Your upgrade is now active!**`;
} else if (item.type === "consumable" && LUCK_POTION_IDS.has(itemId)) {
const now = Date.now();
const expiresAt = userData.luckPotionExpiresAt || {};
const currentExpiry = Math.max(now, Number(expiresAt[itemId]) || 0);
const duration = Number(item.effect?.duration) || DEFAULT_LUCK_POTION_DURATION_MS;
expiresAt[itemId] = currentExpiry + (duration * quantity);
userData.luckPotionExpiresAt = expiresAt;
successDescription += `\n\n🍀 **Active for ${Math.ceil((expiresAt[itemId] - now) / 60000)} minutes. Timer started at purchase.**`;
} else if (item.type === "consumable" || item.type === "tool") {
userData.inventory[itemId] =
(userData.inventory[itemId] || 0) + quantity;
Expand All @@ -144,6 +164,10 @@ export default {
}
}

if (alreadyOwnsFishingRod || itemId === "fishing_rod") {
userData.fishingRodOwned = true;
}

await setEconomyData(client, guildId, userId, userData);

const embed = successEmbed(
Expand All @@ -155,6 +179,21 @@ export default {
inline: true,
});

await InteractionHelper.safeEditReply(interaction, { embeds: [embed], flags: [MessageFlags.Ephemeral] });
if (interaction._isPrefixCommand) {
try {
await interaction.user.send({ embeds: [embed] });
const sourceMessage = InteractionHelper.getCoordinator(interaction)?.message;
await sourceMessage?.delete().catch(() => {});
} catch {
const sourceMessage = InteractionHelper.getCoordinator(interaction)?.message;
await sourceMessage?.delete().catch(() => {});
await interaction.channel.send(
`${interaction.user}, pembelian berhasil, tetapi DM bot kamu tertutup. Aktifkan DM agar struk pembelian bisa dikirim secara pribadi.`
);
}
return;
}

await InteractionHelper.safeEditReply(interaction, { embeds: [embed] });
}, { command: 'buy' })
};
};
31 changes: 4 additions & 27 deletions src/commands/Economy/daily.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { SlashCommandBuilder } from 'discord.js';
import { createEmbed, errorEmbed, successEmbed, infoEmbed, warningEmbed } from '../../utils/embeds.js';
import { getEconomyData, setEconomyData } from '../../utils/economy.js';
import { getGuildConfig } from '../../services/config/guildConfig.js';
import { formatDuration } from '../../utils/embeds.js';
import { withErrorHandling, createError, ErrorTypes } from '../../utils/errorHandler.js';
import { logger } from '../../utils/logger.js';
Expand All @@ -10,7 +9,6 @@ import { botConfig } from '../../config/bot.js';

const DAILY_COOLDOWN = 24 * 60 * 60 * 1000;
const DAILY_AMOUNT = botConfig.economy?.dailyAmount ?? 100;
const PREMIUM_BONUS_PERCENTAGE = 0.1;

export default {
data: new SlashCommandBuilder()
Expand Down Expand Up @@ -50,25 +48,7 @@ export default {
);
}

const guildConfig = await getGuildConfig(client, guildId);
const PREMIUM_ROLE_ID = guildConfig.premiumRoleId;

let earned = DAILY_AMOUNT;
let bonusMessage = "";
let hasPremiumRole = false;

if (
PREMIUM_ROLE_ID &&
interaction.member &&
interaction.member.roles.cache.has(PREMIUM_ROLE_ID)
) {
const bonusAmount = Math.floor(
DAILY_AMOUNT * PREMIUM_BONUS_PERCENTAGE,
);
earned += bonusAmount;
bonusMessage = `\n✨ **Premium Bonus:** +$${bonusAmount.toLocaleString()}`;
hasPremiumRole = true;
}
const earned = DAILY_AMOUNT;

userData.wallet = (userData.wallet || 0) + earned;
userData.lastDaily = now;
Expand All @@ -80,25 +60,22 @@ export default {
guildId,
amount: earned,
newWallet: userData.wallet,
hasPremium: hasPremiumRole,
timestamp: new Date().toISOString()
});

const embed = successEmbed(
"✅ Daily Claimed!",
`You have claimed your daily **$${earned.toLocaleString()}**!${bonusMessage}`
`You have claimed your daily **$${earned.toLocaleString()}**!`
)
.addFields({
name: "New Cash Balance",
value: `$${userData.wallet.toLocaleString()}`,
inline: true,
})
.setFooter({
text: hasPremiumRole
? `Next claim in 24 hours. (Premium Active)`
: `Next claim in 24 hours.`,
text: `Next claim in 24 hours.`,
});

await InteractionHelper.safeEditReply(interaction, { embeds: [embed] });
}, { command: 'daily' })
};
};
1 change: 0 additions & 1 deletion src/commands/Economy/economy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { InteractionHelper } from '../../utils/interactionHelper.js';
import economyDashboard from './modules/economy_dashboard.js';

export default {
slashOnly: true,
data: new SlashCommandBuilder()
.setName('economy')
.setDescription('Economy management commands')
Expand Down
Loading