import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Events, type GuildMember, type TextChannel, } from "discord.js"; import { Event } from "@voidy/framework"; import type { IGuildConfig } from "../schemas/GuildConfig"; const TWO_DAYS = 2 * 24 * 60 * 60 * 1000; const TWO_WEEKS = 14 * 24 * 60 * 60 * 1000; const TWO_MONTHS = 60 * 24 * 60 * 60 * 1000; function getAccountRisk(createdAt: Date): { level: string; color: number } { const age = Date.now() - createdAt.getTime(); if (age < TWO_DAYS) return { level: "Extreme", color: 0xe21e1e }; if (age < TWO_WEEKS) return { level: "High", color: 0xe24d1e }; if (age < TWO_MONTHS) return { level: "Medium", color: 0xe2bb1e }; return { level: "Fairly Safe", color: 0x74e21e }; } export default new Event({ id: "guildMemberAdd", name: Events.GuildMemberAdd, execute: async (ctx, member: unknown) => { const m = member as GuildMember; const { client, buttonId } = ctx; const cache = client.data.get("guildConfig") as Map | undefined; const config = cache?.get(m.guild.id); if (!config) return; // Auto-role assignment const roleId = m.user.bot ? config.autoRoles?.botRoleId : config.autoRoles?.memberRoleId; if (roleId) { try { await m.roles.add(roleId); } catch (err) { console.error(`[Guild] Failed to assign auto-role to ${m.user.tag}:`, err); } } // Welcome message if (config.welcome?.channelId) { const welcomeChannel = m.guild.channels.cache.get(config.welcome.channelId) as | TextChannel | undefined; if (welcomeChannel) { const embed = new EmbedBuilder() .setColor(m.user.accentColor ?? 0x5865f2) .setThumbnail(m.user.displayAvatarURL({ size: 256 })) .setDescription(`Welcome to **${m.guild.name}**, ${m}!`) .setTimestamp(); await welcomeChannel.send({ embeds: [embed] }); } } // Member logging if (config.logging?.channelId) { const logChannel = m.guild.channels.cache.get(config.logging.channelId) as | TextChannel | undefined; if (!logChannel) return; const risk = getAccountRisk(m.user.createdAt); const createdTimestamp = Math.floor(m.user.createdTimestamp / 1000); const embed = new EmbedBuilder() .setColor(risk.color) .setAuthor({ name: `${m.user.tag} joined`, iconURL: m.user.displayAvatarURL(), }) .addFields( { name: "User", value: `${m}`, inline: true }, { name: "Account Created", value: ``, inline: true }, { name: "Risk Level", value: risk.level, inline: true }, ) .setFooter({ text: `ID: ${m.id}` }) .setTimestamp(); if (roleId) { embed.addFields({ name: "Auto-Role", value: `<@&${roleId}>`, inline: true }); } const components: ActionRowBuilder[] = []; if (risk.level === "High" || risk.level === "Extreme") { const row = new ActionRowBuilder().addComponents( new ButtonBuilder() .setCustomId(buttonId("MemberLogging", "Kick", m.id)) .setLabel("Kick") .setStyle(ButtonStyle.Danger), new ButtonBuilder() .setCustomId(buttonId("MemberLogging", "Ban", m.id)) .setLabel("Ban") .setStyle(ButtonStyle.Danger), ); components.push(row); } await logChannel.send({ embeds: [embed], components }); } }, });