mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: simplified owned tanks command
This commit is contained in:
1 parent
d39ab43e74
commit
56321d9e33
6 files changed
+123
-127
No files matched your search
+27
-70
@@ -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'),
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in new issue
Block a user