Replaced `.single()` with `.maybeSingle()` in multiple command files to handle cases where no record is found, and added a new /pricing route and navigation links to the UI. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: e91d020a-35a6-4add-9945-887dd3ecae9f Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/tdDjujk Replit-Helium-Checkpoint-Created: true
80 lines
2.7 KiB
JavaScript
80 lines
2.7 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('userinfo')
|
|
.setDescription('View information about a user')
|
|
.addUserOption(option =>
|
|
option.setName('user')
|
|
.setDescription('User to view (defaults to yourself)')
|
|
.setRequired(false)
|
|
),
|
|
|
|
async execute(interaction, supabase, client) {
|
|
const target = interaction.options.getUser('user') || interaction.user;
|
|
const member = await interaction.guild.members.fetch(target.id).catch(() => null);
|
|
|
|
const embed = new EmbedBuilder()
|
|
.setColor(0x7c3aed)
|
|
.setTitle(target.tag)
|
|
.setThumbnail(target.displayAvatarURL({ size: 256 }))
|
|
.addFields(
|
|
{ name: 'ID', value: target.id, inline: true },
|
|
{ name: 'Bot', value: target.bot ? 'Yes' : 'No', inline: true },
|
|
{ name: 'Account Created', value: `<t:${Math.floor(target.createdTimestamp / 1000)}:R>`, inline: true }
|
|
);
|
|
|
|
if (member) {
|
|
embed.addFields(
|
|
{ name: 'Joined Server', value: `<t:${Math.floor(member.joinedTimestamp / 1000)}:R>`, inline: true },
|
|
{ name: 'Nickname', value: member.nickname || 'None', inline: true },
|
|
{ name: 'Highest Role', value: member.roles.highest.toString(), inline: true }
|
|
);
|
|
|
|
const roles = member.roles.cache
|
|
.filter(r => r.id !== interaction.guildId)
|
|
.sort((a, b) => b.position - a.position)
|
|
.map(r => r.toString())
|
|
.slice(0, 10);
|
|
|
|
if (roles.length > 0) {
|
|
embed.addFields({
|
|
name: `Roles (${member.roles.cache.size - 1})`,
|
|
value: roles.join(', ') + (member.roles.cache.size > 11 ? '...' : '')
|
|
});
|
|
}
|
|
}
|
|
|
|
if (supabase) {
|
|
try {
|
|
const { data: link } = await supabase
|
|
.from('discord_links')
|
|
.select('user_id, primary_arm, linked_at')
|
|
.eq('discord_id', target.id)
|
|
.maybeSingle();
|
|
|
|
if (link) {
|
|
const { data: profile } = await supabase
|
|
.from('user_profiles')
|
|
.select('username, xp')
|
|
.eq('id', link.user_id)
|
|
.maybeSingle();
|
|
|
|
embed.addFields(
|
|
{ name: 'AeThex Linked', value: 'Yes', inline: true },
|
|
{ name: 'Platform Username', value: profile?.username || 'Unknown', inline: true },
|
|
{ name: 'Realm', value: link.primary_arm || 'None', inline: true }
|
|
);
|
|
|
|
if (profile?.xp) {
|
|
const level = Math.floor(Math.sqrt(profile.xp / 100));
|
|
embed.addFields({ name: 'Level', value: `${level} (${profile.xp} XP)`, inline: true });
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
embed.setTimestamp();
|
|
await interaction.reply({ embeds: [embed] });
|
|
},
|
|
};
|