Merge pull request #2 from Fretuks/implement-improvements-from-readme

Add currency commands and polish utility responses
This commit is contained in:
2026-01-26 12:14:33 +01:00
committed by GitHub
7 changed files with 213 additions and 37 deletions
+26
View File
@@ -0,0 +1,26 @@
const { SlashCommandBuilder } = require('discord.js');
const { connectToDatabase } = require('../../db.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('balance')
.setDescription('Check your coin balance or another user\'s balance.')
.addUserOption(option =>
option
.setName('user')
.setDescription('User to check (defaults to you)')
.setRequired(false)),
async execute(interaction) {
const dbClient = await connectToDatabase();
const db = dbClient.db('discord');
const collection = db.collection('currency');
const target = interaction.options.getUser('user') ?? interaction.user;
const targetData = await collection.findOne({ userID: target.id });
const balance = targetData?.balance ?? 0;
return interaction.reply({
content: `${target.tag} has **${balance}** coins.`,
});
}
};
+59
View File
@@ -0,0 +1,59 @@
const { SlashCommandBuilder } = require('discord.js');
const { connectToDatabase } = require('../../db.js');
const REWARD_AMOUNT = 100;
const COOLDOWN_MS = 24 * 60 * 60 * 1000;
const formatDuration = (ms) => {
const totalSeconds = Math.ceil(ms / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
const parts = [];
if (hours) parts.push(`${hours}h`);
if (minutes) parts.push(`${minutes}m`);
if (!hours && !minutes) parts.push(`${seconds}s`);
return parts.join(' ');
};
module.exports = {
data: new SlashCommandBuilder()
.setName('earn')
.setDescription('Claim your daily coin reward.'),
async execute(interaction) {
const dbClient = await connectToDatabase();
const db = dbClient.db('discord');
const collection = db.collection('currency');
const now = new Date();
const userId = interaction.user.id;
const userData = await collection.findOne({ userID: userId });
const lastClaim = userData?.lastClaimedAt ? new Date(userData.lastClaimedAt) : null;
if (lastClaim) {
const elapsed = now - lastClaim;
if (elapsed < COOLDOWN_MS) {
const remaining = COOLDOWN_MS - elapsed;
return interaction.reply({
content: `You already claimed your reward. Try again in **${formatDuration(remaining)}**.`,
ephemeral: true,
});
}
}
await collection.updateOne(
{ userID: userId },
{
$set: { lastClaimedAt: now.toISOString() },
$inc: { balance: REWARD_AMOUNT },
},
{ upsert: true }
);
return interaction.reply({
content: `You earned **${REWARD_AMOUNT}** coins! Come back tomorrow for more.`,
});
}
};
+23 -15
View File
@@ -1,37 +1,45 @@
// exampleCommand.js
const { SlashCommandBuilder } = require('discord.js');
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const { connectToDatabase } = require('../../db.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('give')
.setDescription('give somebody coins')
.setDescription('Admin: grant coins to a user.')
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
.addIntegerOption(option =>
option
.setName('amount')
.setDescription('amount of the coins')
.setDescription('Amount of coins to give')
.setMinValue(1)
.setRequired(true))
.addUserOption(option =>
option.setName('target')
.setDescription('The user to give coins to')
option
.setName('target')
.setDescription('User to receive coins')
.setRequired(true)),
async execute(interaction) {
const dbClient = await connectToDatabase();
const target = interaction.options.getUser('target');
const amount = interaction.options.getInteger('amount');
// Choose a DB + Collection
if (target.bot) {
return interaction.reply({
content: 'You cannot grant coins to bot accounts.',
ephemeral: true,
});
}
const db = dbClient.db('discord');
const collection = db.collection('currency');
let targetData = await collection.findOne({ userID: target.id });
if (!targetData) {
await collection.insertOne({ userID: target.id, balance: 0 });
}
await collection.updateOne(
{ userID: target.id },
{ $inc: { balance: amount } },
{ upsert: true }
);
// Perform the transaction: subtract from sender and add to target.
await collection.updateOne({ userID: target.id }, { $inc: { balance: amount } }, { upsert: true });
return interaction.reply({ content: `You have given ${amount} coins to ${target.tag}.` });
return interaction.reply({
content: `You granted **${amount}** coins to ${target.tag}.`,
});
}
};
+68
View File
@@ -0,0 +1,68 @@
const { SlashCommandBuilder } = require('discord.js');
const { connectToDatabase } = require('../../db.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('transfer')
.setDescription('Send coins to another user.')
.addUserOption(option =>
option
.setName('target')
.setDescription('User to send coins to')
.setRequired(true))
.addIntegerOption(option =>
option
.setName('amount')
.setDescription('Amount of coins to send')
.setMinValue(1)
.setRequired(true)),
async execute(interaction) {
const dbClient = await connectToDatabase();
const db = dbClient.db('discord');
const collection = db.collection('currency');
const target = interaction.options.getUser('target');
const amount = interaction.options.getInteger('amount');
if (target.bot) {
return interaction.reply({
content: 'You cannot transfer coins to a bot account.',
ephemeral: true,
});
}
if (target.id === interaction.user.id) {
return interaction.reply({
content: 'You cannot transfer coins to yourself.',
ephemeral: true,
});
}
const senderId = interaction.user.id;
const senderData = await collection.findOne({ userID: senderId });
const senderBalance = senderData?.balance ?? 0;
if (senderBalance < amount) {
return interaction.reply({
content: `You only have **${senderBalance}** coins available.`,
ephemeral: true,
});
}
await collection.updateOne(
{ userID: senderId },
{ $inc: { balance: -amount } },
{ upsert: true }
);
await collection.updateOne(
{ userID: target.id },
{ $inc: { balance: amount } },
{ upsert: true }
);
return interaction.reply({
content: `You sent **${amount}** coins to ${target.tag}.`,
});
}
};
+11 -7
View File
@@ -1,19 +1,23 @@
const {SlashCommandBuilder, EmbedBuilder} = require("discord.js");
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName("about")
.setDescription("Information about this bot and creator"),
.setName('about')
.setDescription('Information about this bot and creator'),
async execute(interaction) {
const exampleEmbed = new EmbedBuilder()
.setColor(0x0099FF)
.setTitle('About Page')
.setDescription('I build this bot for managing my servers. (to lazy to write mor text rn)')
.setTitle('About This Bot')
.setDescription('A multipurpose Discord bot focused on helpful utilities, moderation, and fun community features.')
.addFields(
{ name: 'Highlights', value: 'Timezone converter, quiz games, and a growing currency system.' },
{ name: 'Created By', value: interaction.client.user?.username ?? 'Bot Creator' }
)
.setImage('https://i.postimg.cc/QdZZwKVD/Screenshot-2024-12-25-005933.png')
.setTimestamp();
await interaction.reply({
embeds: [exampleEmbed]
})
});
}
}
};
+12 -8
View File
@@ -1,23 +1,27 @@
const { SlashCommandBuilder} = require("discord.js");
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Gives all available commands.'),
async execute(interaction) {
// Map over the full command objects to get names and descriptions
const commandDetails = interaction.client.commands.map(cmd => ({
const commandDetails = interaction.client.commands
.map(cmd => ({
name: cmd.data.name,
description: cmd.data.description,
}));
}))
.sort((a, b) => a.name.localeCompare(b.name));
// Format the commands into a user-friendly help message
const helpMessage = commandDetails
.map(detail => `/${detail.name} - ${detail.description}`)
.map(detail => `• **/${detail.name}** — ${detail.description}`)
.join('\n');
// Send the help message
await interaction.reply(`Here are all the available commands:\n\n${helpMessage}`);
const embed = new EmbedBuilder()
.setColor(0x4b7bec)
.setTitle('Available Commands')
.setDescription(helpMessage)
.setFooter({ text: `${commandDetails.length} commands loaded.` });
await interaction.reply({ embeds: [embed], ephemeral: true });
},
};
+9 -2
View File
@@ -3,8 +3,15 @@ const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Check if the bots responsivnes'),
.setDescription('Check the bot\'s responsiveness.'),
async execute(interaction) {
await interaction.reply({ content: 'Pong! (Online)', ephemeral: true });
const sentAt = Date.now();
await interaction.reply({ content: 'Pinging...', ephemeral: true });
const latency = Date.now() - sentAt;
const apiLatency = Math.round(interaction.client.ws.ping);
await interaction.editReply({
content: `Pong! **${latency}ms** (API: **${apiLatency}ms**)`,
});
},
};