feat: simplified owned tanks command

This commit is contained in:
TrèsAbhi committed 2024-03-16 00:06:44 -05:00
1 parent d39ab43e74
commit 56321d9e33
6 files changed
+123 -127

No files matched your search

+27 -70
View File
@@ -1,14 +1,13 @@
import CommandWrapper from '../components/CommandWrapper';
import NoData from '../components/NoData';
import * as Tanks from '../components/Tanks';
import TitleBar from '../components/TitleBar';
import { chunk } from 'lodash';
import markdownEscape from 'markdown-escape';
import { TANK_CLASSES } from '../components/Tanks/components/Item/constants';
import { getAccountInfo } from '../core/blitz/getAccountInfo';
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
import getTankStats from '../core/blitz/getTankStats';
import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL';
import {
NATIONS,
TankDefinition,
Tier,
flags,
tankDefinitions,
} from '../core/blitzkrieg/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../core/blitzkrieg/tankDefinitions/constants';
@@ -20,6 +19,8 @@ import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
import { translator } from '../core/localization/translator';
import { CommandRegistry } from '../events/interactionCreate';
const TANKS_PER_MESSAGE = 64;
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
resolve({
inProduction: true,
@@ -43,7 +44,6 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
})),
)
).filter((tank) => tank.tankDefinitions?.tier === tier);
const clanAccountInfo = await getClanAccountInfo(region, id, ['clan']);
const groupedTanks: Record<string, TankDefinition[]> = {};
const nations: string[] = [];
@@ -56,71 +56,28 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
}
});
nations.sort();
const awaitedTankDefinitions = await tankDefinitions;
const awaitedNations = await NATIONS;
const lines = tankStats
.map(({ tank_id }) => awaitedTankDefinitions[tank_id])
.filter((tank) => tank.tier === tier)
.sort(
(a, b) =>
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
)
.sort(
(a, b) =>
awaitedNations.indexOf(a.nation) - awaitedNations.indexOf(b.nation),
)
.map((tank) => `${flags[tank.nation]} ${markdownEscape(tank.name)}`);
return (
<CommandWrapper>
<TitleBar
title={accountInfo.nickname}
image={
clanAccountInfo?.clan
? emblemIdToURL(clanAccountInfo.clan.emblem_set_id)
: undefined
}
description={translate('bot.commands.owned_tanks.body.subtitle', [
return chunk(lines, TANKS_PER_MESSAGE).map((lines, index) =>
index === 0
? `${translate('bot.commands.owned_tanks.body.title', [
markdownEscape(accountInfo.nickname),
TIER_ROMAN_NUMERALS[tier as Tier],
])}
/>
{filteredTanks.length === 0 && (
<NoData type="tanks_found" locale={interaction.locale} />
)}
{filteredTanks.length > 0 &&
(await Promise.all(
nations.map(async (nation) => {
const tanks = groupedTanks[nation];
const leftColumnSize = Math.ceil(tanks.length / 2);
const leftColumn = tanks.slice(0, leftColumnSize);
const rightColumn = tanks.slice(leftColumnSize);
return (
<Tanks.Root key={nation}>
<Tanks.Title>
{translate(`common.nations.${nation}`)}
</Tanks.Title>
<Tanks.Row>
<Tanks.Column>
{await Promise.all(
leftColumn.map(async (tank) => (
<Tanks.Item
key={tank.id}
name={tank.name}
tankType={tank.class}
treeType={tank.treeType}
/>
)),
)}
</Tanks.Column>
<Tanks.Column>
{await Promise.all(
rightColumn.map(async (tank) => (
<Tanks.Item
key={tank.id}
name={tank.name}
tankType={tank.class}
treeType={tank.treeType}
/>
)),
)}
</Tanks.Column>
</Tanks.Row>
</Tanks.Root>
);
}),
))}
</CommandWrapper>
])}${lines.join('\n')}`
: lines.join('\n'),
);
},
+4
View File
@@ -27,6 +27,10 @@ export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
interaction.appPermissions?.has('AttachFiles'),
t`bot.commands.permissions.body.attach_files`,
],
[
interaction.appPermissions?.has('UseExternalEmojis'),
t`bot.commands.permissions.body.external_emojis`,
],
];
const body = permissions
.map(([hasPermission, description]) => {
@@ -185,3 +185,15 @@ export const NATIONS = tanksDefinitionsArray.then((tanks) => {
return nations;
});
export const flags: Record<string, string> = {
ussr: '<:ussr:1218421042033197197>',
germany: '🇩🇪',
usa: '🇺🇸',
china: '🇨🇳',
uk: '🇬🇧',
france: '🇫🇷',
japan: '🇯🇵',
european: '🇪🇺',
other: '<:other:1218421572243558482>',
};
@@ -4,6 +4,7 @@ import {
ButtonBuilder,
EmbedBuilder,
InteractionEditReplyOptions,
InteractionReplyOptions,
} from 'discord.js';
import { InteractionReturnable } from '../../events/interactionCreate';
import jsxToPngThreaded from '../blitzkrieg/jsxToPngThreaded';
@@ -12,7 +13,7 @@ export default async function normalizeInteractionReturnable(
returnable: InteractionReturnable,
) {
const images: [number, Buffer][] = [];
const reply: InteractionEditReplyOptions = {};
const reply: InteractionEditReplyOptions & InteractionReplyOptions = {};
const awaitedReturnable = await returnable;
const normalizedReturnable = Array.isArray(awaitedReturnable)
@@ -7,7 +7,7 @@ import {
ChatInputCommandInteraction,
InteractionReplyOptions,
} from 'discord.js';
import { commands } from '..';
import { InteractionRawReturnable, commands } from '..';
import buttonLink from '../../../core/discord/buttonLink';
import embedWarning from '../../../core/discord/embedWarning';
import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable';
@@ -28,70 +28,91 @@ export default async function handleChatInputCommand(
if (registry.handlesInteraction) return;
const reply = await normalizeInteractionReturnable(returnable!);
const chunks: InteractionRawReturnable[][] = [[]];
if (
psa.data &&
!psa.data.secret &&
(psa.data.commands === undefined ||
psa.data.commands.includes(interaction.commandName))
) {
if (psa.data.type === 'embed') {
if (!reply.embeds) reply.embeds = [];
reply.embeds.push(embedWarning(psa.data.title, psa.data.description));
} else {
if (!reply.files) reply.files = [];
reply.files.push(new AttachmentBuilder(psa.data.image));
reply.content = reply.content ?? psa.data.title;
}
(Array.isArray(returnable) ? returnable : [returnable]).forEach(
(object) => {
if (typeof object === 'string') {
chunks.push([object]);
} else chunks.at(-1)?.push(object!);
},
);
if (psa.data.links) {
if (!reply.components?.[0]) {
reply.components = [new ActionRowBuilder<ButtonBuilder>()];
let index = 0;
for (const chunk of chunks.filter((chunk) => chunk.length > 0)) {
const reply = await normalizeInteractionReturnable(chunk);
if (
psa.data &&
!psa.data.secret &&
(psa.data.commands === undefined ||
psa.data.commands.includes(interaction.commandName))
) {
if (psa.data.type === 'embed') {
if (!reply.embeds) reply.embeds = [];
reply.embeds.push(embedWarning(psa.data.title, psa.data.description));
} else {
if (!reply.files) reply.files = [];
reply.files.push(new AttachmentBuilder(psa.data.image));
reply.content = reply.content ?? psa.data.title;
}
(reply.components[0] as ActionRowBuilder<ButtonBuilder>).addComponents(
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
);
if (psa.data.links) {
if (!reply.components?.[0]) {
reply.components = [new ActionRowBuilder<ButtonBuilder>()];
}
(
reply.components[0] as ActionRowBuilder<ButtonBuilder>
).addComponents(
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
);
}
}
}
await interaction.editReply(reply);
if (
psa.data &&
psa.data.secret &&
(psa.data.commands === undefined ||
psa.data.commands.includes(interaction.commandName))
) {
const followUp: InteractionReplyOptions = {
ephemeral: true,
};
if (psa.data.type === 'embed') {
if (!followUp.embeds) followUp.embeds = [];
followUp.embeds.push(
embedWarning(psa.data.title, psa.data.description),
);
if (index === 0) {
await interaction.editReply(reply);
} else {
if (!followUp.files) followUp.files = [];
followUp.files.push(new AttachmentBuilder(psa.data.image));
followUp.content = followUp.content ?? psa.data.title;
await interaction.followUp(reply);
}
if (psa.data.links) {
if (!followUp.components?.[0]) {
followUp.components = [new ActionRowBuilder<ButtonBuilder>()];
if (
psa.data &&
psa.data.secret &&
(psa.data.commands === undefined ||
psa.data.commands.includes(interaction.commandName))
) {
const followUp: InteractionReplyOptions = {
ephemeral: true,
};
if (psa.data.type === 'embed') {
if (!followUp.embeds) followUp.embeds = [];
followUp.embeds.push(
embedWarning(psa.data.title, psa.data.description),
);
} else {
if (!followUp.files) followUp.files = [];
followUp.files.push(new AttachmentBuilder(psa.data.image));
followUp.content = followUp.content ?? psa.data.title;
}
(
followUp.components[0] as ActionRowBuilder<ButtonBuilder>
).addComponents(
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
);
if (psa.data.links) {
if (!followUp.components?.[0]) {
followUp.components = [new ActionRowBuilder<ButtonBuilder>()];
}
(
followUp.components[0] as ActionRowBuilder<ButtonBuilder>
).addComponents(
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
);
}
interaction.followUp(followUp);
}
interaction.followUp(followUp);
index++;
}
} catch (error) {
const { t } = translator(interaction.locale);
+5 -4
View File
@@ -486,7 +486,7 @@
"description": "Shows all own tanks in a tier",
"body": {
"subtitle": "Tier %s tanks"
"title": "# %s's owned tier %s tanks\n\n"
}
},
@@ -496,9 +496,10 @@
"body": {
"title": "# Permissions\n\n%s",
"view_channels": "View channels: needed for the refresh button to work",
"read_message_history": "Read message history: needed for the refresh button to find the message to refresh",
"attach_files": "Attach files: needed for image-based commands to work"
"view_channels": "View channels: needed to find the message the refresh button was used on",
"read_message_history": "Read message history: needed to find the message to refresh",
"attach_files": "Attach files: needed to add images to image-based commands",
"external_emojis": "External emojis: needed to fill add national flags and tank class emojis"
}
},