Naposledy aktivní 4 weeks ago

Revize 6780461457f5d9e158c78187cf89a387221d4529

charSelect.ts Raw
1import {
2 ButtonBuilder,
3 ButtonStyle,
4 ActionRowBuilder,
5} from "discord.js";
6import { getCharacters, getCharacterByName } from "@systems/characters";
7import { getClassEmoji } from "@systems/emojis";
8import { format } from "@format";
9import { Character } from "@types";
10import fs from "fs";
11import path from "path";
12
13const CHARS_PATH = path.join(__dirname, "../../data/characters.json");
14
15export interface CharSelectOptions {
16 customIdPrefix: string; // e.g. "switch_after_reclaim:flash"
17 excludeCharName?: string; // exclude this char from the list
18 appendToCustomId?: string; // appended after charName e.g. ":yes"
19 pageSize?: number; // default 4
20 page?: number; // default 0
21}
22
23/**
24 * Builds paginated character selection button rows for a given user.
25 * Includes own characters + shared characters.
26 * Returns up to 2 rows: one for char buttons, one for pagination if needed.
27 */
28export function buildCharSelectButtons(
29 userKey: string,
30 options: CharSelectOptions
31): ActionRowBuilder<ButtonBuilder>[] {
32 const {
33 customIdPrefix,
34 excludeCharName,
35 appendToCustomId = "",
36 pageSize = 4,
37 page = 0,
38 } = options;
39
40 // Gather own + shared chars
41 const ownChars = getCharacters(userKey);
42
43 const sharedChars: Character[] = [];
44 try {
45 const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8"));
46 for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) {
47 if (ownerKey === userKey) continue;
48 for (const c of data.characters ?? []) {
49 if (c.sharedWith?.includes(userKey)) sharedChars.push(c);
50 }
51 }
52 } catch {}
53
54 const allChars = [...ownChars, ...sharedChars]
55 .filter((c) => c.name !== excludeCharName);
56
57 const pageChars = allChars.slice(page * pageSize, (page + 1) * pageSize);
58 const hasNext = allChars.length > (page + 1) * pageSize;
59 const hasPrev = page > 0;
60 const rows: ActionRowBuilder<ButtonBuilder>[] = [];
61
62 // Char buttons
63 if (pageChars.length > 0) {
64 const btns = pageChars.map((c) => {
65 const emojiStr = getClassEmoji(c.class);
66 const emoji = format.emoji(emojiStr);
67 const btn = new ButtonBuilder()
68 .setCustomId(`${customIdPrefix}:${c.name}${appendToCustomId}`)
69 .setStyle(ButtonStyle.Secondary)
70 .setLabel(`${c.level} ${c.name}`);
71 if (emoji) btn.setEmoji(emoji as any);
72 return btn;
73 });
74 rows.push(new ActionRowBuilder<ButtonBuilder>().addComponents(...btns));
75 }
76
77 // Pagination row
78 const navBtns: ButtonBuilder[] = [];
79 if (hasPrev) {
80 navBtns.push(
81 new ButtonBuilder()
82 .setCustomId(`${customIdPrefix}_page:${page - 1}`)
83 .setLabel("← Prev")
84 .setStyle(ButtonStyle.Primary)
85 );
86 }
87 if (hasNext) {
88 navBtns.push(
89 new ButtonBuilder()
90 .setCustomId(`${customIdPrefix}_page:${page + 1}`)
91 .setLabel("Next →")
92 .setStyle(ButtonStyle.Primary)
93 );
94 }
95 if (navBtns.length > 0) {
96 rows.push(new ActionRowBuilder<ButtonBuilder>().addComponents(...navBtns));
97 }
98
99 return rows;
100}