Skip to content

Commit c83f5fd

Browse files
author
raineer
committed
Merge branch 'dev' of https://github.com/CodebilityDev/codebility-plus into gradient-dshboard01
2 parents 4fcd1f4 + 4b20978 commit c83f5fd

90 files changed

Lines changed: 15958 additions & 287 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ yarn-error.log
3939
## Ignore environment variable files
4040
apps/bot/.env
4141

42+
.next
43+
4244
# BUCK
4345
buck-out/
4446
\.buckd/
@@ -68,6 +70,7 @@ web-build/
6870
**/*/.expo
6971

7072
**/*/.next
73+
packages/ui/dist/*
7174

7275
**/*/ios
7376
**/*/android
@@ -84,4 +87,5 @@ build/**
8487
!.yarn/sdks
8588
!.yarn/versions
8689

87-
dist
90+
distapps/bot/.env
91+
.env

‎apps/bot/commands/resetXP.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
114114
.from("user_stats_discord")
115115
.update({
116116
xp: 0,
117-
level: 1, // Reset to level 1 (most bots start at level 1, not 0)
117+
level: 0, // Reset to level 1 (most bots start at level 1, not 0)
118118
total_messages: 0,
119119
})
120120
.eq("user_id", targetUser.id)

‎apps/bot/dist/commands/badges.js‎

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
"use strict";
2+
// apps/bot/commands/badges.ts
3+
Object.defineProperty(exports, "__esModule", { value: true });
4+
exports.execute = exports.command = void 0;
5+
const discord_js_1 = require("discord.js");
6+
const supabase_bot_1 = require("../utils/supabase.bot");
7+
//Slash command
8+
const slashCommand = new discord_js_1.SlashCommandBuilder()
9+
.setName("badges")
10+
.setDescription("View your badges or award a badge (admin only).")
11+
.addUserOption((opt) => opt
12+
.setName("user")
13+
.setDescription("Target user to view or award badges to.")
14+
.setRequired(false))
15+
.addStringOption((opt) => opt
16+
.setName("badge")
17+
.setDescription("Badge ID to award (admin only)")
18+
.setRequired(false));
19+
// Export the command
20+
exports.command = {
21+
name: "badges",
22+
data: slashCommand,
23+
};
24+
// Execute function
25+
const execute = async (interaction) => {
26+
try {
27+
await interaction.deferReply();
28+
const userOption = interaction.options.getUser("user");
29+
const badgeId = interaction.options.getString("badge");
30+
const targetUser = userOption || interaction.user;
31+
// Ensure users_discord record exists for target user
32+
const { error: userError } = await supabase_bot_1.supabaseBot
33+
.from("users_discord")
34+
.upsert({
35+
id: targetUser.id,
36+
username: targetUser.username,
37+
avatar_url: targetUser.displayAvatarURL(),
38+
discriminator: targetUser.discriminator || "0",
39+
}, { onConflict: "id" });
40+
if (userError) {
41+
console.error("❌ Error ensuring user record:", userError.message);
42+
}
43+
// ===== ADMIN AWARD FLOW =====
44+
if (badgeId) {
45+
// Permission check
46+
if (!interaction.memberPermissions?.has(discord_js_1.PermissionFlagsBits.ManageGuild)) {
47+
await interaction.editReply({
48+
content: "❌ You do not have permission to award badges. (Requires **Manage Server** permission.)",
49+
});
50+
return;
51+
}
52+
// Validate badgeId
53+
const badgeIdNum = parseInt(badgeId);
54+
if (isNaN(badgeIdNum)) {
55+
await interaction.editReply({
56+
content: "❌ Invalid badge ID. Please provide a valid **number**.",
57+
});
58+
return;
59+
}
60+
// Check if badge exists
61+
const { data: badge, error: badgeError } = await supabase_bot_1.supabaseBot
62+
.from("badges_discord")
63+
.select("id, badge_name")
64+
.eq("id", badgeIdNum)
65+
.single();
66+
if (badgeError || !badge) {
67+
await interaction.editReply({
68+
content: `❌ No badge found with ID **${badgeIdNum}**.`,
69+
});
70+
return;
71+
}
72+
// Check if user already has this badge
73+
const { data: existingBadge } = await supabase_bot_1.supabaseBot
74+
.from("user_badges_discord")
75+
.select("id")
76+
.eq("user_id", targetUser.id)
77+
.eq("badge_id", badgeIdNum)
78+
.maybeSingle();
79+
if (existingBadge) {
80+
await interaction.editReply({
81+
content: `⚠️ <@${targetUser.id}> already has the badge **${badge.badge_name}**.`,
82+
});
83+
return;
84+
}
85+
// Award the badge
86+
const { error: insertError } = await supabase_bot_1.supabaseBot
87+
.from("user_badges_discord")
88+
.insert({
89+
user_id: targetUser.id,
90+
badge_id: badgeIdNum,
91+
});
92+
if (insertError) {
93+
console.error("❌ Error awarding badge:", insertError.message);
94+
await interaction.editReply({
95+
content: "⚠️ Failed to award badge. Please try again later.",
96+
});
97+
return;
98+
}
99+
await interaction.editReply({
100+
content: `🏅 **${badge.badge_name}** has been awarded to <@${targetUser.id}>!`,
101+
});
102+
console.log(`✅ Badge ${badgeIdNum} awarded to ${targetUser.username} by ${interaction.user.username}`);
103+
return;
104+
}
105+
// ===== VIEW BADGES FLOW =====
106+
const { data: userBadges, error: ubError } = await supabase_bot_1.supabaseBot
107+
.from("user_badges_discord")
108+
.select("badge_id, awarded_at")
109+
.eq("user_id", targetUser.id);
110+
if (ubError) {
111+
console.error("❌ Error fetching user badges:", ubError.message);
112+
await interaction.editReply({
113+
content: "⚠️ Failed to fetch user badges. Please try again.",
114+
});
115+
return;
116+
}
117+
if (!userBadges || userBadges.length === 0) {
118+
await interaction.editReply({
119+
content: `<@${targetUser.id}> has no badges yet. 🏆`,
120+
});
121+
return;
122+
}
123+
// Fetch all badge details from badges_discord
124+
const { data: allBadges, error: allBadgesError } = await supabase_bot_1.supabaseBot
125+
.from("badges_discord")
126+
.select("id, badge_name, badge_icon_url, description");
127+
if (allBadgesError || !allBadges) {
128+
console.error("❌ Error fetching badge details:", allBadgesError.message);
129+
await interaction.editReply({
130+
content: "⚠️ Failed to load badge details. Please try again.",
131+
});
132+
return;
133+
}
134+
// Merge badge info
135+
const badgesWithDetails = userBadges
136+
.map((ub) => {
137+
const badge = allBadges.find((b) => b.id === ub.badge_id);
138+
if (!badge)
139+
return null;
140+
return {
141+
badge_name: badge.badge_name,
142+
badge_icon_url: badge.badge_icon_url,
143+
description: badge.description,
144+
awarded_at: ub.awarded_at,
145+
};
146+
})
147+
.filter((badge) => badge !== null);
148+
// ===== CREATE EMBED =====
149+
const embed = new discord_js_1.EmbedBuilder()
150+
.setTitle(`${targetUser.username}'s Badges`)
151+
.setColor("#FFD700")
152+
.setThumbnail(targetUser.displayAvatarURL())
153+
.setFooter({ text: `Total Badges: ${badgesWithDetails.length}` })
154+
.setTimestamp();
155+
if (badgesWithDetails.length > 0) {
156+
embed.setDescription(badgesWithDetails
157+
.map((b) => `🏅 **${b.badge_name}**\n${b.description ?? "No description."}`)
158+
.join("\n\n"));
159+
}
160+
else {
161+
embed.setDescription("No badges found.");
162+
}
163+
await interaction.editReply({ embeds: [embed] });
164+
}
165+
catch (error) {
166+
console.error("❌ Error executing badges command:", error);
167+
const errorMessage = {
168+
content: "❌ An unexpected error occurred while processing this command. Please try again later.",
169+
};
170+
if (interaction.deferred) {
171+
await interaction.editReply(errorMessage);
172+
}
173+
else if (!interaction.replied) {
174+
await interaction.reply({
175+
...errorMessage,
176+
flags: [discord_js_1.MessageFlags.Ephemeral],
177+
});
178+
}
179+
}
180+
};
181+
exports.execute = execute;

‎apps/bot/dist/commands/configXP.js‎

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"use strict";
2+
// apps/bot/commands/configXP.ts
3+
Object.defineProperty(exports, "__esModule", { value: true });
4+
exports.execute = exports.command = void 0;
5+
const discord_js_1 = require("discord.js");
6+
const supabase_bot_1 = require("../utils/supabase.bot");
7+
const slashCommand = new discord_js_1.SlashCommandBuilder()
8+
.setName("configxp")
9+
.setDescription("Configure the XP leveling system for your server.")
10+
.addIntegerOption((o) => o
11+
.setName("min")
12+
.setDescription("Minimum XP gained per message")
13+
.setRequired(true)
14+
.setMinValue(1)
15+
.setMaxValue(100))
16+
.addIntegerOption((o) => o
17+
.setName("max")
18+
.setDescription("Maximum XP gained per message")
19+
.setRequired(true)
20+
.setMinValue(1)
21+
.setMaxValue(100))
22+
.addIntegerOption((o) => o
23+
.setName("cooldown")
24+
.setDescription("Cooldown between XP gains (in seconds)")
25+
.setRequired(true)
26+
.setMinValue(0)
27+
.setMaxValue(300))
28+
.addChannelOption((o) => o
29+
.setName("levelup_channel")
30+
.setDescription("Channel where level-up messages will be sent")
31+
.setRequired(false))
32+
.setDefaultMemberPermissions(discord_js_1.PermissionFlagsBits.Administrator);
33+
exports.command = {
34+
name: "configxp",
35+
data: slashCommand,
36+
};
37+
const execute = async (interaction) => {
38+
try {
39+
const guildId = interaction.guildId;
40+
const guildName = interaction.guild?.name ?? "Unknown Guild";
41+
if (!guildId) {
42+
await interaction.reply({
43+
content: "❌ This command can only be used inside a server.",
44+
flags: [discord_js_1.MessageFlags.Ephemeral],
45+
});
46+
return;
47+
}
48+
const min = interaction.options.getInteger("min", true);
49+
const max = interaction.options.getInteger("max", true);
50+
const cooldown = interaction.options.getInteger("cooldown", true);
51+
const levelUpChannel = interaction.options.getChannel("levelup_channel");
52+
// Validate XP range
53+
if (min > max) {
54+
await interaction.reply({
55+
content: "❌ Minimum XP cannot be greater than maximum XP!",
56+
flags: [discord_js_1.MessageFlags.Ephemeral],
57+
});
58+
return;
59+
}
60+
await interaction.deferReply({ flags: [discord_js_1.MessageFlags.Ephemeral] });
61+
// ✅ Ensure guild record exists
62+
const { error: guildError } = await supabase_bot_1.supabaseBot
63+
.from("guilds_discord")
64+
.upsert({
65+
id: guildId,
66+
name: guildName,
67+
active: true,
68+
}, { onConflict: "id" });
69+
if (guildError) {
70+
console.error("❌ Error ensuring guild record:", guildError.message);
71+
await interaction.editReply({
72+
content: "❌ Failed to ensure guild record. Please try again later.",
73+
});
74+
return;
75+
}
76+
// ✅ Upsert into xp_config_discord
77+
const { error: xpError } = await supabase_bot_1.supabaseBot
78+
.from("xp_config_discord")
79+
.upsert({
80+
guild_id: guildId,
81+
min_xp: min,
82+
max_xp: max,
83+
cooldown: cooldown,
84+
levelup_channel: levelUpChannel?.id ?? null,
85+
}, { onConflict: "guild_id" });
86+
if (xpError) {
87+
console.error("❌ Error saving XP config:", xpError.message);
88+
await interaction.editReply({
89+
content: "❌ Failed to save XP configuration. Please try again later.",
90+
});
91+
return;
92+
}
93+
// ✅ Also sync to settings_discord
94+
const { error: settingsError } = await supabase_bot_1.supabaseBot
95+
.from("settings_discord")
96+
.upsert({
97+
guild_id: guildId,
98+
xp_per_message: Math.floor((min + max) / 2), // avg XP for info purposes
99+
cooldown_seconds: cooldown,
100+
level_up_channel_id: levelUpChannel?.id ?? null,
101+
updated_at: new Date().toISOString(),
102+
}, { onConflict: "guild_id" });
103+
if (settingsError) {
104+
console.error("⚠️ Warning: settings_discord sync failed:", settingsError.message);
105+
// Don’t block command if this one fails, but log it
106+
}
107+
// ✅ Success message
108+
const summary = [
109+
`✅ **XP configuration updated successfully!**`,
110+
"",
111+
"**Settings:**",
112+
`• Min XP: **${min}**`,
113+
`• Max XP: **${max}**`,
114+
`• Cooldown: **${cooldown}s**`,
115+
levelUpChannel ? `• Level-up Channel: <#${levelUpChannel.id}>` : null,
116+
]
117+
.filter(Boolean)
118+
.join("\n");
119+
await interaction.editReply({ content: summary });
120+
console.log(`✅ XP config + settings updated for guild: ${guildName} (${guildId})`);
121+
}
122+
catch (error) {
123+
console.error("🔥 Error executing configxp command:", error);
124+
const errorMessage = {
125+
content: "❌ An unexpected error occurred while saving the XP configuration.",
126+
};
127+
if (interaction.deferred) {
128+
await interaction.editReply(errorMessage);
129+
}
130+
else if (!interaction.replied) {
131+
await interaction.reply({
132+
...errorMessage,
133+
flags: [discord_js_1.MessageFlags.Ephemeral],
134+
});
135+
}
136+
}
137+
};
138+
exports.execute = execute;

0 commit comments

Comments
 (0)