Utoljára aktív 3 weeks ago

nuno gist felülvizsgálása 3 weeks ago. Revízióhoz ugrás

1 file changed, 165 insertions

interactions.ts(fájl létrehozva)

@@ -0,0 +1,165 @@
1 + import { Interaction, ChatInputCommandInteraction, ButtonInteraction, TextChannel, StringSelectMenuInteraction } from "discord.js";
2 + import { handleButton, handleScoreSubmitButton } from "@handlers/buttons";
3 + import { handleTgCommand } from "@commands/tg";
4 + import { handleTgConfigCommand } from "@commands/tgConfig";
5 + import { handleBorrowAcceptButton } from "@subcommands/char/accept";
6 + import { handleBorrowDeclineButton } from "@subcommands/char/decline";
7 + import { handleConflictButton } from "@systems/conflict";
8 + import { handleImpersonateButton } from "@subcommands/impersonate";
9 + import { handleAutocomplete } from "@handlers/autocomplete";
10 + import { setActiveCharacter, getCharacterByName, getCharacters } from "@systems/characters";
11 + import { Ephemeral } from "@registry/ephemeral-registry";
12 + import { getImpersonation } from "@systems/impersonate";
13 + import { format } from "@format";
14 + import { modals } from "@handlers/modals";
15 + import { Character } from "@systems/character";
16 + import { handleTgAdminCommand } from "@commands/tgAdmin";
17 + import fs from "fs";
18 + import path from "path";
19 +
20 + async function handleSwitchAfterReclaim(btn: ButtonInteraction): Promise<void> {
21 + const prefix = btn.customId.startsWith("companion_switch:") ? "companion_switch:" : "switch_after_reclaim:";
22 + const withoutPrefix = btn.customId.slice(prefix.length);
23 + const firstColon = withoutPrefix.indexOf(":");
24 + const userKey = withoutPrefix.slice(0, firstColon);
25 + const rest = withoutPrefix.slice(firstColon + 1);
26 + const lastColon = rest.lastIndexOf(":");
27 + const charName = rest.slice(0, lastColon);
28 + const prevVoteType = (rest.slice(lastColon + 1) || "yes") as "yes" | "no";
29 +
30 + const impersonating = getImpersonation(btn.user.id);
31 + const voteId = impersonating ? `impersonated:${impersonating}` : btn.user.id;
32 +
33 + const chars = JSON.parse(
34 + fs.readFileSync(path.join(__dirname, "../../data/characters.json"), "utf8")
35 + );
36 +
37 + await btn.deferUpdate()
38 +
39 + // Resolve char without switching
40 + let resolvedChar: any = null;
41 + let borrowedFrom: string | null = null;
42 +
43 + const ownEntry = chars[userKey]?.characters?.find((c: any) => c.name === charName);
44 + if (ownEntry) {
45 + resolvedChar = ownEntry;
46 + } else {
47 + for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) {
48 + const char = data.characters?.find(
49 + (c: any) => c.name === charName && c.sharedWith?.includes(userKey)
50 + );
51 + if (char) {
52 + resolvedChar = char;
53 + borrowedFrom = ownerKey;
54 + break;
55 + }
56 + }
57 + }
58 +
59 + if (!resolvedChar) {
60 + await btn.followUp({ content: `❌ Could not switch to **${charName}**.`, ephemeral: true });
61 + return;
62 + }
63 +
64 + // Delegate to shared switch logic
65 + const result = await Character.performSwitch(userKey, resolvedChar, borrowedFrom, btn, prevVoteType);
66 +
67 + if (result.replyData) {
68 + const { content, components } = result.replyData;
69 + console.log(`[switchAfterReclaim] replyData, isCompanion=${btn.customId.startsWith("companion_switch:")}`);
70 + if (btn.customId.startsWith("companion_switch:")) {
71 + await Ephemeral.update(voteId, "companion", content, components, { final: false });
72 + } else {
73 + await btn.followUp(result.replyData);
74 + }
75 + return;
76 + }
77 +
78 + if (result.success && result.message) {
79 + const companionExists = !!Ephemeral.get(voteId, "companion");
80 + console.log(`[switchAfterReclaim] success, companionExists=${companionExists} voteId=${voteId}`);
81 + await Ephemeral.update(voteId, "companion", result.message, []);
82 + // Ephemeral.delete(voteId, "companion"); // clean up after final switch
83 + if (!companionExists) {
84 + await btn.followUp({ content: result.message, ephemeral: true });
85 + }
86 + }
87 + }
88 +
89 + export async function handleInteraction(interaction: Interaction): Promise<void> {
90 + try {
91 + if (interaction.isAutocomplete()) {
92 + await handleAutocomplete(interaction);
93 + return;
94 + }
95 +
96 + if (interaction.isButton()) {
97 + const btn = interaction as ButtonInteraction;
98 +
99 + console.log("[interactions] interaction btnId:", btn.customId);
100 + if (btn.customId.startsWith("conflict_")) {
101 + console.log("[interactions] routing to conflict handler:", btn.customId);
102 + return await handleConflictButton(btn);
103 + }
104 +
105 + if (btn.customId.startsWith("impersonate_")) {
106 + return await handleImpersonateButton(btn);
107 + }
108 +
109 + if (btn.customId.startsWith("switch_after_reclaim:")) {
110 + return await handleSwitchAfterReclaim(btn);
111 + }
112 +
113 + if (btn.customId.startsWith("borrow_accept:")) {
114 + const [, ownerKey, requesterKey] = btn.customId.split(":");
115 + return await handleBorrowAcceptButton(btn, ownerKey, requesterKey);
116 + }
117 +
118 + if (btn.customId.startsWith("borrow_decline:")) {
119 + const [, ownerKey, requesterKey] = btn.customId.split(":");
120 + return await handleBorrowDeclineButton(btn, ownerKey, requesterKey);
121 + }
122 +
123 + if (btn.customId === "tg_score_submit") {
124 + return await handleScoreSubmitButton(btn);
125 + }
126 +
127 + if (btn.customId.startsWith("companion_switch:")) {
128 + return await handleSwitchAfterReclaim(btn);
129 + }
130 +
131 + return await handleButton(btn);
132 + }
133 +
134 + if (interaction.isModalSubmit()) {
135 + return await modals.handleModal(interaction);
136 + }
137 +
138 + if (interaction.isStringSelectMenu()) {
139 + const sel = interaction as StringSelectMenuInteraction;
140 + if (sel.customId.startsWith("score_slot_select:")) {
141 + const userKey = sel.customId.split(":")[1];
142 + const slot = parseInt(sel.values[0], 10);
143 + await sel.showModal(modals.buildScoreModal(userKey, slot));
144 + return;
145 + }
146 + }
147 +
148 + if (interaction.isChatInputCommand()) {
149 + const cmd = interaction as ChatInputCommandInteraction;
150 + if (cmd.commandName === "tg") await handleTgCommand(cmd);
151 + if (cmd.commandName === "tg-config") await handleTgConfigCommand(cmd);
152 + if (cmd.commandName === "tg-admin") await handleTgAdminCommand(cmd);
153 + }
154 + } catch (err) {
155 + console.error("Interaction error:", err);
156 + try {
157 + const msg = { content: "❌ An error occurred.", ephemeral: true };
158 + if ((interaction as any).replied || (interaction as any).deferred) {
159 + await (interaction as any).followUp(msg);
160 + } else {
161 + await (interaction as any).reply(msg);
162 + }
163 + } catch {}
164 + }
165 + }
Újabb Régebbi