Utoljára aktív 1 month ago

Revízió b78811f00eae6f697a6be2c6d1de99636f8c2ecd

autocomplete.ts Eredeti
1import { AutocompleteInteraction } from "discord.js";
2import { resolveUser } from "@systems/users";
3import { getCharacters, getCharacterByName } from "@systems/characters";
4import { getPersistentPreference, getSessionBorrow } from "@systems/borrow";
5import { cfg } from "@systems/config";
6import fs from "fs";
7import path from "path";
8
9// ─── Autocomplete subsets ─────────────────────────────────────────────────────
10
11// Character names — own chars + shared chars accessible to this user
12async function autocompleteCharNames(
13 interaction: AutocompleteInteraction,
14 focused: string
15): Promise<void> {
16 const member = await interaction.guild!.members.fetch(interaction.user.id);
17 const user = await resolveUser(member);
18 if (!user.userKey) return interaction.respond([]);
19
20 const ownChars = getCharacters(user.userKey).map((c) => ({
21 name: `${c.class} ${c.level} ${c.name}`,
22 value: c.name,
23 }));
24
25 // Include shared chars (scan all users' sharedWith arrays)
26 const sharedChars: { name: string; value: string }[] = [];
27 try {
28 const chars = JSON.parse(
29 fs.readFileSync(path.join(__dirname, "../../data/characters.json"), "utf8")
30 );
31 for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) {
32 if (ownerKey === user.userKey) continue;
33 for (const char of data.characters ?? []) {
34 if (char.sharedWith?.includes(user.userKey)) {
35 sharedChars.push({
36 name: `${char.class} ${char.level} ${char.name} (shared by ${ownerKey})`,
37 value: char.name,
38 });
39 }
40 }
41 }
42 } catch {}
43
44 const all = [...ownChars, ...sharedChars]
45 .filter((c) => c.name.toLowerCase().includes(focused.toLowerCase()))
46 .slice(0, 25);
47
48 await interaction.respond(all);
49}
50
51// Usermap keys — all registered users (officer commands)
52async function autocompleteUserKeys(
53 interaction: AutocompleteInteraction,
54 focused: string
55): Promise<void> {
56 try {
57 const usermap = JSON.parse(
58 fs.readFileSync(path.join(__dirname, "../../data/usermap.json"), "utf8")
59 );
60 const choices = Object.entries(usermap)
61 .map(([, entry]: [string, any]) => {
62 const fileKey = typeof entry === "string" ? entry : entry.file;
63 const alias = typeof entry === "object" ? (entry.aliases?.[0] ?? fileKey) : fileKey;
64 return { name: `${alias} (${fileKey})`, value: fileKey };
65 })
66 .filter((c) => c.name.toLowerCase().includes(focused.toLowerCase()))
67 .slice(0, 25);
68 await interaction.respond(choices);
69 } catch {
70 await interaction.respond([]);
71 }
72}
73
74// TG slots — active slot hours
75async function autocompleteSlots(
76 interaction: AutocompleteInteraction,
77 focused: string
78): Promise<void> {
79 const slots = cfg("slots")
80 .filter((s) => s.active)
81 .map((s) => ({ name: `${s.tgHour}:00`, value: String(s.tgHour) }))
82 .filter((s) => s.name.includes(focused));
83 await interaction.respond(slots);
84}
85
86// ─── Router ───────────────────────────────────────────────────────────────────
87
88export async function handleAutocomplete(interaction: AutocompleteInteraction): Promise<void> {
89 try {
90 const focused = interaction.options.getFocused(true);
91 const optionName = focused.name;
92 const focusedValue = focused.value as string;
93
94 // Route by option name
95 if (optionName === "char_name") {
96 return await autocompleteCharNames(interaction, focusedValue);
97 }
98 if (optionName === "name") {
99 // Officer user key args
100 return await autocompleteUserKeys(interaction, focusedValue);
101 }
102 if (optionName === "slot") {
103 return await autocompleteSlots(interaction, focusedValue);
104 }
105
106 await interaction.respond([]);
107 } catch (err) {
108 console.error("[autocomplete] error:", err);
109 try { await interaction.respond([]); } catch {}
110 }
111}