AeThex-Bot-Master/aethex-bot/commands/rank.js
sirpiglr 6feaad75db Update user profile displays to show custom avatar URLs when available
Modify commands like badges, profile, rank, and stats to prioritize and validate user-provided HTTP/HTTPS avatar URLs over default display avatars.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 566d93fe-73b9-4076-a03a-cb3263aa2dab
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/19PeEhC
Replit-Helium-Checkpoint-Created: true
2025-12-08 17:58:53 +00:00

92 lines
3.2 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('rank')
.setDescription('View your unified level and XP across all platforms')
.addUserOption(option =>
option.setName('user')
.setDescription('User to check (defaults to yourself)')
.setRequired(false)
),
async execute(interaction, supabase, client) {
if (!supabase) {
return interaction.reply({ content: 'Database not configured.', ephemeral: true });
}
const target = interaction.options.getUser('user') || interaction.user;
await interaction.deferReply();
try {
const { data: link } = await supabase
.from('discord_links')
.select('user_id, primary_arm')
.eq('discord_id', target.id)
.single();
if (!link) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xff6b6b)
.setDescription(`${target.id === interaction.user.id ? 'You are' : `${target.tag} is`} not linked to AeThex. Use \`/verify\` to link your account.`)
]
});
}
const { data: profile } = await supabase
.from('user_profiles')
.select('username, avatar_url, xp, bio')
.eq('id', link.user_id)
.single();
const xp = profile?.xp || 0;
const level = Math.floor(Math.sqrt(xp / 100));
const currentLevelXp = level * level * 100;
const nextLevelXp = (level + 1) * (level + 1) * 100;
const progress = xp - currentLevelXp;
const needed = nextLevelXp - currentLevelXp;
const progressPercent = Math.floor((progress / needed) * 100);
const progressBar = createProgressBar(progressPercent);
const { count: rankPosition } = await supabase
.from('user_profiles')
.select('*', { count: 'exact', head: true })
.gt('xp', xp);
// Validate avatar URL - must be http/https, not base64
let avatarUrl = target.displayAvatarURL();
if (profile?.avatar_url && profile.avatar_url.startsWith('http')) {
avatarUrl = profile.avatar_url;
}
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle(`${profile?.username || target.tag}'s Rank`)
.setThumbnail(avatarUrl)
.addFields(
{ name: 'Level', value: `**${level}**`, inline: true },
{ name: 'Total XP', value: `**${xp.toLocaleString()}**`, inline: true },
{ name: 'Rank', value: `#${(rankPosition || 0) + 1}`, inline: true },
{ name: 'Progress to Next Level', value: `${progressBar}\n${progress.toLocaleString()} / ${needed.toLocaleString()} XP (${progressPercent}%)` },
{ name: 'Primary Realm', value: link.primary_arm || 'None set', inline: true }
)
.setFooter({ text: 'XP earned across Discord & AeThex platforms' })
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Rank error:', error);
await interaction.editReply({ content: 'Failed to fetch rank data.' });
}
},
};
function createProgressBar(percent) {
const filled = Math.floor(percent / 10);
const empty = 10 - filled;
return '█'.repeat(filled) + '░'.repeat(empty);
}