post.ts
· 1.9 KiB · TypeScript
Sin formato
import { ChatInputCommandInteraction, TextChannel, EmbedBuilder } from "discord.js";
import { cfg } from "../../systems/config";
import { loadResult, todayString } from "../../systems/history";
import { normalizeSlot, detectSlot } from "../../systems/scores";
import { replyAndDelete } from "../../utils";
export async function handleResultPost(interaction: ChatInputCommandInteraction): Promise<void> {
const slotArg = interaction.options.getString("slot");
let slot: number | null = null;
if (slotArg) {
slot = normalizeSlot(slotArg);
if (slot === null) return void replyAndDelete(interaction, `❌ Could not parse slot "${slotArg}".`);
} else {
slot = detectSlot() ?? cfg("slots")[0]?.tgHour ?? 20;
}
const result = loadResult(todayString(), slot);
if (!result) return void replyAndDelete(interaction, `❌ No result found for ${slot}:00 TG.`);
const kd = result.nationKD;
const formatScores = (nation: "Capella" | "Procyon"): string => {
const scores = result.scores.filter((s) => s.nation === nation);
if (scores.length === 0) return "—";
return scores
.sort((a, b) => b.pts - a.pts)
.map((s) => `**${s.characterName}** (${s.class}) — ${s.pts} pts`)
.join("\n");
};
const embed = new EmbedBuilder()
.setTitle(`⚔️ TG Results — ${result.date} ${slot}:00`)
.setColor(0xe8a317)
.addFields(
{ name: "🔵 Capella", value: `${kd.capella.k}K / ${kd.capella.d}D\n${formatScores("Capella")}`, inline: true },
{ name: "🔴 Procyon", value: `${kd.procyon.k}K / ${kd.procyon.d}D\n${formatScores("Procyon")}`, inline: true },
)
.setFooter({ text: `Source of truth: ${kd.source}` })
.setTimestamp();
const channelId = cfg("resultsChannelId") || cfg("pollChannelId");
const channel = await interaction.client.channels.fetch(channelId) as TextChannel;
await channel.send({ embeds: [embed] });
return void replyAndDelete(interaction, "✅ Results posted.");
}
| 1 | import { ChatInputCommandInteraction, TextChannel, EmbedBuilder } from "discord.js"; |
| 2 | import { cfg } from "../../systems/config"; |
| 3 | import { loadResult, todayString } from "../../systems/history"; |
| 4 | import { normalizeSlot, detectSlot } from "../../systems/scores"; |
| 5 | import { replyAndDelete } from "../../utils"; |
| 6 | |
| 7 | export async function handleResultPost(interaction: ChatInputCommandInteraction): Promise<void> { |
| 8 | const slotArg = interaction.options.getString("slot"); |
| 9 | |
| 10 | let slot: number | null = null; |
| 11 | if (slotArg) { |
| 12 | slot = normalizeSlot(slotArg); |
| 13 | if (slot === null) return void replyAndDelete(interaction, `❌ Could not parse slot "${slotArg}".`); |
| 14 | } else { |
| 15 | slot = detectSlot() ?? cfg("slots")[0]?.tgHour ?? 20; |
| 16 | } |
| 17 | |
| 18 | const result = loadResult(todayString(), slot); |
| 19 | if (!result) return void replyAndDelete(interaction, `❌ No result found for ${slot}:00 TG.`); |
| 20 | |
| 21 | const kd = result.nationKD; |
| 22 | |
| 23 | const formatScores = (nation: "Capella" | "Procyon"): string => { |
| 24 | const scores = result.scores.filter((s) => s.nation === nation); |
| 25 | if (scores.length === 0) return "—"; |
| 26 | return scores |
| 27 | .sort((a, b) => b.pts - a.pts) |
| 28 | .map((s) => `**${s.characterName}** (${s.class}) — ${s.pts} pts`) |
| 29 | .join("\n"); |
| 30 | }; |
| 31 | |
| 32 | const embed = new EmbedBuilder() |
| 33 | .setTitle(`⚔️ TG Results — ${result.date} ${slot}:00`) |
| 34 | .setColor(0xe8a317) |
| 35 | .addFields( |
| 36 | { name: "🔵 Capella", value: `${kd.capella.k}K / ${kd.capella.d}D\n${formatScores("Capella")}`, inline: true }, |
| 37 | { name: "🔴 Procyon", value: `${kd.procyon.k}K / ${kd.procyon.d}D\n${formatScores("Procyon")}`, inline: true }, |
| 38 | ) |
| 39 | .setFooter({ text: `Source of truth: ${kd.source}` }) |
| 40 | .setTimestamp(); |
| 41 | |
| 42 | const channelId = cfg("resultsChannelId") || cfg("pollChannelId"); |
| 43 | const channel = await interaction.client.channels.fetch(channelId) as TextChannel; |
| 44 | await channel.send({ embeds: [embed] }); |
| 45 | return void replyAndDelete(interaction, "✅ Results posted."); |
| 46 | } |
| 47 |