Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions src/features/quote/embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { clampText } from '@/util/text.js';
import {
ActionRowBuilder,
type APIEmbedField,
type APIMessageTopLevelComponent,
type APITextDisplayComponent,
ButtonBuilder,
ButtonStyle,
ComponentType,
Expand All @@ -14,9 +16,27 @@ import {
type User,
} from 'discord.js';

import { DELETE_EMOJIS } from '../reactions/remove-user-bot-message.js';

const EMBED_DESC_LIMIT = 4096;
const FIELD_VALUE_LIMIT = 1024;
const JUMP_BUTTON_LABEL = 'Jump to message';
const EMOJIS = DELETE_EMOJIS.join('/');
const DELETE_HINT = `React with ${EMOJIS} to delete`;
const DELETE_HINT_LINE = `-# ${DELETE_HINT}`;

const isTextDisplayComponent = (
component: APIMessageTopLevelComponent
): component is APITextDisplayComponent =>
component.type === ComponentType.TextDisplay;

const applyDeleteHint = (embed: EmbedBuilder): void => {
if (!embed.data.footer?.text) {
embed.setFooter({ text: DELETE_HINT });
} else if (!embed.data.footer.text.includes(DELETE_HINT)) {
embed.setFooter({ text: `${embed.data.footer.text} | ${DELETE_HINT}` });
}
};

type OriginalQuoteInfo = {
authorMention: string;
Expand Down Expand Up @@ -104,9 +124,10 @@ export const createQuoteEmbed = ({
const existingLineIndex = components.findIndex(
(component) => component.type === ComponentType.TextDisplay
);
const existingComponent = components[existingLineIndex];
const existingContent =
existingLineIndex !== -1
? (components[existingLineIndex] as { content: string }).content
existingComponent && isTextDisplayComponent(existingComponent)
? existingComponent.content
: null;

const parsed =
Expand All @@ -130,6 +151,17 @@ export const createQuoteEmbed = ({
components.push(attributionLine);
}

const hasDeleteHint = components.some(
(component) =>
isTextDisplayComponent(component) &&
component.content === DELETE_HINT_LINE
);
if (!hasDeleteHint) {
components.push(
new TextDisplayBuilder().setContent(DELETE_HINT_LINE).toJSON()
);
}

return {
allowedMentions: { parse: [] },
components,
Expand All @@ -152,12 +184,14 @@ export const createQuoteEmbed = ({

// Find an existing "Quoted by" field, if quotedMessage is itself a quote.
let existingField: APIEmbedField | null = null;
let existingFieldEmbed: EmbedBuilder | null = null;
for (const embed of embeds) {
const found = embed.data.fields?.find(
(field) => /^quoted by$/i.test(field.name) && parseQuoteLine(field.value)
);
if (found) {
existingField = found;
existingFieldEmbed = embed;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed, you are just renaming embed to something else. could just use embed directly from what i see.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is needed, existingField is a field in the embed, existingFieldEmbed is the whole embed containing the specific field, which we're using later to check it's footer for the existing hint or add a new one.

break;
}
}
Expand Down Expand Up @@ -188,15 +222,21 @@ export const createQuoteEmbed = ({
// Already a quote: swap the field's value in place, keep everything
// else (original author/description/image/timestamp) untouched.
existingField.value = quotedByField.value;
if (existingFieldEmbed) {
applyDeleteHint(existingFieldEmbed);
}
} else {
// First-time quote: build the wrapper/annotation.
const authorOptions = {
name: quotedMessage.author.username,
iconURL: quotedMessage.author.displayAvatarURL({ size: 64 }),
};

const stampAsQuote = (embed: EmbedBuilder) =>
const stampAsQuote = (embed: EmbedBuilder) => {
embed.setAuthor(authorOptions).addFields(quotedByField).setTimestamp();
applyDeleteHint(embed);
return embed;
};

const hasContent = quotedMessage.content.length > 0;
const hasEmbeds = embeds.length > 0;
Expand Down
2 changes: 1 addition & 1 deletion src/features/reactions/remove-user-bot-message.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ClientEvents, Events, GuildMember } from 'discord.js';
import { UserBotMessagesService } from '@/services/user-bot-messages/user-bot-messages-service.js';

const DELETE_EMOJIS = ['🗑️', '❌'];
export const DELETE_EMOJIS = ['🗑️', '❌'];

export const removeUserBotMessage: (
...args: ClientEvents[Events.MessageReactionAdd]
Expand Down
Loading