Skip to content

Commit 8a167c1

Browse files
authored
fix: reconcile tags when changes occur (#18)
1 parent f51f4b6 commit 8a167c1

File tree

5 files changed

+96
-7
lines changed

5 files changed

+96
-7
lines changed

bun.lockb

384 Bytes
Binary file not shown.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"dependencies": {
2323
"@uwu/configmasher": "latest",
2424
"discord.js": "^14.15.3",
25-
"ofetch": "^1.4.1"
25+
"ofetch": "^1.4.1",
26+
"throttle-debounce": "^5.0.2"
2627
},
2728
"trustedDependencies": [
2829
"@biomejs/biome"

src/commands/util/close.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ import {
1717
const getStateWord = (close) => (close ? "closed" : "reopened");
1818
const getStateVerb = (close) => (close ? "close" : "reopen");
1919

20+
export function getTagsForCloseState(close: boolean) {
21+
return {
22+
tagToAdd: close
23+
? config.helpChannel.closedTag
24+
: config.helpChannel.openedTag,
25+
tagToRemove: close
26+
? config.helpChannel.openedTag
27+
: config.helpChannel.closedTag,
28+
};
29+
}
30+
2031
export async function handleIssueState(
2132
interaction: ChatInputCommandInteraction,
2233
close = true,
@@ -29,12 +40,7 @@ export async function handleIssueState(
2940
const stateWord = getStateWord(close);
3041
const stateVerb = getStateVerb(close);
3142

32-
const tagToAdd = close
33-
? config.helpChannel.closedTag
34-
: config.helpChannel.openedTag;
35-
const tagToRemove = close
36-
? config.helpChannel.openedTag
37-
: config.helpChannel.closedTag;
43+
const { tagToAdd, tagToRemove } = getTagsForCloseState(close);
3844

3945
const postTags = threadChannel.appliedTags;
4046

src/events/channels.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { config } from "../lib/config.js";
2+
import { getTagsForCloseState } from "../commands/util/close.js";
3+
import { isHelpPost } from "../lib/discord/channels.js";
4+
5+
import { debounce } from "throttle-debounce";
6+
7+
import { type Client, Events, type ThreadChannel } from "discord.js";
8+
9+
// Map to store initial thread states
10+
const threadUpdateMap = new Map<string, ThreadChannel>();
11+
12+
// Create a debounced handler for processing thread updates
13+
const handleEvent = debounce(
14+
1000,
15+
async (threadId: string, newThread: ThreadChannel) => {
16+
const initialThread = threadUpdateMap.get(threadId);
17+
if (!initialThread) return;
18+
19+
// Remove from map
20+
threadUpdateMap.delete(threadId);
21+
22+
// Handle tag additions
23+
const addedTags = newThread.appliedTags.filter(
24+
(t) => !initialThread.appliedTags.includes(t),
25+
);
26+
if (addedTags.length > 0) {
27+
for (const tag of addedTags) {
28+
// If closed/opened tag is added, remove the opposite tag
29+
if (
30+
tag === config.helpChannel.closedTag ||
31+
tag === config.helpChannel.openedTag
32+
) {
33+
const isClose = tag === config.helpChannel.closedTag;
34+
const { tagToRemove } = getTagsForCloseState(isClose);
35+
if (newThread.appliedTags.includes(tagToRemove)) {
36+
await newThread.setAppliedTags(
37+
newThread.appliedTags.filter((t) => t !== tagToRemove),
38+
);
39+
}
40+
}
41+
}
42+
}
43+
44+
// Handle tag removals
45+
const removedTags = initialThread.appliedTags.filter(
46+
(t) => !newThread.appliedTags.includes(t),
47+
);
48+
if (removedTags.length > 0) {
49+
for (const tag of removedTags) {
50+
// If closed or opened tag is removed, add it back only if its opposite isn't present
51+
if (
52+
tag === config.helpChannel.closedTag ||
53+
tag === config.helpChannel.openedTag
54+
) {
55+
const isClose = tag === config.helpChannel.closedTag;
56+
const { tagToRemove } = getTagsForCloseState(isClose);
57+
if (!newThread.appliedTags.includes(tagToRemove)) {
58+
await newThread.setAppliedTags([...newThread.appliedTags, tag]);
59+
}
60+
}
61+
}
62+
}
63+
},
64+
);
65+
66+
export default function registerEvents(client: Client) {
67+
client.on(Events.ThreadUpdate, async (oldThread, newThread) => {
68+
if (!(await isHelpPost(newThread))) {
69+
return;
70+
}
71+
72+
// Store the initial state if this is the first update
73+
if (!threadUpdateMap.has(newThread.id)) {
74+
threadUpdateMap.set(newThread.id, oldThread);
75+
}
76+
77+
// Trigger the debounced handler
78+
handleEvent(newThread.id, newThread);
79+
});
80+
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { config } from "./lib/config.js";
33
import registerCommandEvents from "./events/commands.js";
44
import registerWalkthroughEvents from "./events/walkthrough.js";
55
import registerMessageEvents from "./events/messages.js";
6+
import registerChannelEvents from "./events/channels.js";
67

78
import { Client, Events, GatewayIntentBits, ActivityType } from "discord.js";
89

@@ -37,6 +38,7 @@ client.once(Events.ClientReady, () => {
3738
registerCommandEvents(client);
3839
registerWalkthroughEvents(client);
3940
registerMessageEvents(client);
41+
registerChannelEvents(client);
4042

4143
shufflePresence();
4244
setInterval(shufflePresence, config.presenceDelay);

0 commit comments

Comments
 (0)