Skip to content

Commit 4e69cd3

Browse files
committed
refactor: make walkthrough data-driven and self-contained
Replace the index-driven interaction state machine with a single ordered list of steps that colocate each step's selector, question, and embed field. A generic engine seeds the data embed up front, records each answer, then renders the next question or finalises and pins. Fold the three selector components into src/ui/walkthrough.ts and drop the now-unused generateQuestion helper.
1 parent a4897f6 commit 4e69cd3

7 files changed

Lines changed: 194 additions & 188 deletions

File tree

‎src/commands/util/walkthrough.ts‎

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import { config } from "@lib/config.js";
22

33
import { isHelpPost as isHelpThread } from "@lib/discord/channels.js";
4-
import issueCategorySelector from "@components/issueCategorySelector.js";
4+
import { startWalkthrough } from "@ui/walkthrough.js";
55

66
import {
77
type ChatInputCommandInteraction,
88
SlashCommandBuilder,
9-
ActionRowBuilder,
10-
type StringSelectMenuBuilder,
11-
EmbedBuilder,
12-
type Embed,
13-
Colors,
149
type PublicThreadChannel,
1510
type GuildTextBasedChannel,
1611
ButtonBuilder,
@@ -71,22 +66,6 @@ const resourcesMessage = {
7166
],
7267
};
7368

74-
export function generateQuestion(
75-
question: string,
76-
component: StringSelectMenuBuilder,
77-
embeds: (EmbedBuilder | Embed)[] = [],
78-
) {
79-
return {
80-
embeds: [
81-
...embeds,
82-
new EmbedBuilder().setColor(Colors.White).setDescription(question),
83-
],
84-
components: [
85-
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(component),
86-
],
87-
};
88-
}
89-
9069
export async function doWalkthrough(
9170
channel: GuildTextBasedChannel,
9271
interaction?: ChatInputCommandInteraction,
@@ -131,13 +110,8 @@ export async function doWalkthrough(
131110
await channel.send(resourcesMessage as MessageCreateOptions);
132111
}
133112

134-
// Generate the walkthrough message asking the user what they're creating this issue for
135-
const message = generateQuestion(
136-
"What are you creating this issue for?",
137-
issueCategorySelector,
138-
);
139-
140-
return channel.send(message);
113+
// Send the walkthrough message asking what the user is creating this issue for
114+
return channel.send(startWalkthrough(channel.id));
141115
}
142116
}
143117

‎src/events/walkthrough.ts‎

Lines changed: 6 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,16 @@
1-
import { doWalkthrough, generateQuestion } from "@commands/util/walkthrough.js";
1+
import { doWalkthrough } from "@commands/util/walkthrough.js";
2+
import { handleSelection } from "@ui/walkthrough.js";
23

3-
import issueCategorySelector from "@components/issueCategorySelector.js";
4-
import productSelector from "@components/productSelector.js";
5-
import operatingSystemFamilySelector from "@components/operatingSystemFamilySelector.js";
4+
import { type Client, Events } from "discord.js";
65

7-
import {
8-
type Client,
9-
EmbedBuilder,
10-
Events,
11-
type InteractionUpdateOptions,
12-
} from "discord.js";
13-
14-
// This has to follow the order of the walkthrough steps
15-
const selectors = [
16-
issueCategorySelector,
17-
productSelector,
18-
operatingSystemFamilySelector,
19-
];
20-
21-
function getLabelFromValue(value, selector: (typeof selectors)[number]) {
22-
return selector.options.filter((option) => option.data.value === value)[0]
23-
.data.label;
24-
}
25-
26-
// TODO: make this readable
276
export default function registerEvents(client: Client) {
28-
// Do walkthrough whenever a thread is opened
7+
// Run the walkthrough whenever a thread is opened.
298
client.on(Events.ThreadCreate, async (channel) => doWalkthrough(channel));
309

31-
// Register events for the actual walkthrough steps
10+
// Advance the walkthrough as the user answers each select menu.
3211
client.on(Events.InteractionCreate, async (interaction) => {
3312
if (interaction.isStringSelectMenu()) {
34-
let messageData: InteractionUpdateOptions;
35-
36-
const selector = selectors.filter(
37-
(element) => element.data.custom_id === interaction.customId,
38-
)[0];
39-
const index = selectors.indexOf(selector);
40-
41-
const lastStep = index + 1 === selectors.length;
42-
43-
if (index === 0) {
44-
const dataEmbed = new EmbedBuilder()
45-
.setTitle(`<#${interaction.channelId}>`)
46-
.addFields([
47-
{
48-
name: "Category",
49-
value: getLabelFromValue(interaction.values[0], selector),
50-
inline: true,
51-
},
52-
{ name: "Product", value: "N/A", inline: true },
53-
{ name: "Platform", value: "N/A", inline: true },
54-
{
55-
name: "Logs",
56-
value: "Please post any relevant logs/error messages.",
57-
},
58-
]);
59-
60-
messageData = generateQuestion(
61-
"What product are you using?",
62-
productSelector,
63-
[dataEmbed],
64-
);
65-
} else {
66-
// Grab the embed from the last message and edit the corresponding field with the human-readable field (instead of the ID)
67-
const dataEmbed = interaction.message.embeds[0];
68-
dataEmbed.fields[index].value = getLabelFromValue(
69-
interaction.values[0],
70-
selector,
71-
);
72-
73-
// TODO : make this part more generic once we have more questions
74-
if (selector === productSelector) {
75-
messageData = generateQuestion(
76-
`What operating system are you running ${dataEmbed.fields[index].value} on?`,
77-
selectors[index + 1], // next selector
78-
[dataEmbed],
79-
);
80-
} else if (lastStep) {
81-
// This is the last step of the walkthrough, so we generate an empty message with just the data embed
82-
messageData = { components: [], embeds: [dataEmbed] };
83-
} else {
84-
throw new Error("No case matches this walkthrough step");
85-
}
86-
}
87-
88-
await interaction.update(messageData);
89-
90-
// If this is the last step of the walkthrough, we pin the message
91-
if (lastStep) {
92-
await interaction.message.pin();
93-
}
13+
await handleSelection(interaction);
9414
}
9515
});
9616
}

‎src/ui/components/issueCategorySelector.ts‎

Lines changed: 0 additions & 21 deletions
This file was deleted.

‎src/ui/components/operatingSystemFamilySelector.ts‎

Lines changed: 0 additions & 28 deletions
This file was deleted.

‎src/ui/components/productSelector.ts‎

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)