feat: added all buttons to dynamic commands

This commit is contained in:
TresAbhi committed 2023-06-28 18:45:14 +00:00
1 parent dd39563d6d
commit d1d8aad6c7
9 files changed
+157 -57

No files matched your search

+50 -15
View File
@@ -1,17 +1,26 @@
import { SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import { CYCLIC_API } from '../constants/cyclic.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
import resolveTankId from '../core/blitz/resolveTankId.js'; import resolveTankId from '../core/blitz/resolveTankId.js';
import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js';
import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js';
import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js';
import interactionToURL from '../core/discord/interactionToURL.js';
import linkButton from '../core/discord/linkButton.js';
import primaryButton from '../core/discord/primaryButton.js';
import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js';
import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js';
import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js';
import { CommandRegistry } from '../events/interactionCreate/index.js'; import { CommandRegistry } from '../events/interactionCreate/index.js';
import evolution from '../renderers/evolution.js'; import evolution from '../renderers/evolution.js';
import { StatType } from '../renderers/statsfull.js'; import { StatType } from '../renderers/statsfull.js';
import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: addStatTypeSubCommandGroups( command: addStatTypeSubCommandGroups(
@@ -27,25 +36,51 @@ export default {
const player = await resolvePlayerFromCommand(interaction); const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(interaction); const period = resolvePeriodFromCommand(interaction);
const tankIdRaw = interaction.options.getString('tank')!; const tankIdRaw = interaction.options.getString('tank')!;
const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
return await evolution(commandGroup, period, player, tankId); return [
await evolution(commandGroup, period, player, tankId),
// TODO: implement this primaryButton(path, 'Refresh'),
// new ButtonBuilder() linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
// .setStyle(ButtonStyle.Link) linkButton(
// .setLabel('View on BlitzStars') `https://www.blitzstars.com/player/${player.server}/${nickname}${
// .setURL( commandGroup === 'tank' ? `/tank/${tankId!}` : ''
// commandGroup === 'tank' }`,
// ? `https://www.blitzstars.com/player/com/${ 'BlitzStars',
// accountInfo[id].nickname ),
// }/tank/${tankId!}` ];
// : `https://www.blitzstars.com/player/com/${accountInfo[id].nickname}`,
// );
}, },
autocomplete: (interaction) => { autocomplete: (interaction) => {
autocompleteUsername(interaction); autocompleteUsername(interaction);
autocompleteTanks(interaction); autocompleteTanks(interaction);
}, },
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const period = resolvePeriodFromButton(interaction);
const player = await resolvePlayerFromButton(interaction);
return await evolution(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
);
},
} satisfies CommandRegistry; } satisfies CommandRegistry;
+21 -9
View File
@@ -1,19 +1,22 @@
import { SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import { CYCLIC_API } from '../constants/cyclic.js'; import { CYCLIC_API } from '../constants/cyclic.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
import resolveTankId from '../core/blitz/resolveTankId.js'; import resolveTankId from '../core/blitz/resolveTankId.js';
import { Period } from '../core/discord/addPeriodSubCommands.js';
import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js';
import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js';
import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js';
import interactionToURL from '../core/discord/interactionToURL.js';
import linkButton from '../core/discord/linkButton.js'; import linkButton from '../core/discord/linkButton.js';
import primaryButton from '../core/discord/primaryButton.js'; import primaryButton from '../core/discord/primaryButton.js';
import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'; import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js';
import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js';
import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js';
import { CommandRegistry } from '../events/interactionCreate/index.js'; import { CommandRegistry } from '../events/interactionCreate/index.js';
import stats from '../renderers/stats.js'; import stats from '../renderers/stats.js';
import { StatType } from '../renderers/statsfull.js'; import { StatType } from '../renderers/statsfull.js';
import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
@@ -30,23 +33,32 @@ export default {
const commandGroup = interaction.options.getSubcommandGroup( const commandGroup = interaction.options.getSubcommandGroup(
true, true,
) as StatType; ) as StatType;
const subcommand = interaction.options.getSubcommand() as Period;
const player = await resolvePlayerFromCommand(interaction); const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(interaction); const period = resolvePeriodFromCommand(interaction);
const tankIdRaw = interaction.options.getString('tank')!; const tankIdRaw = interaction.options.getString('tank')!;
const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start'); const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end'); const end = interaction.options.getInteger('end');
const path = `stats/${commandGroup}/${subcommand}?server=${ const path = interactionToURL(interaction, {
player.server ...player,
}&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; tankId,
start,
// interactionToURL(interaction); end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
return [ return [
await stats(commandGroup, period, player, tankId), await stats(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'), primaryButton(path, 'Refresh'),
linkButton(path, 'Embed'), linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.server}/${nickname}`,
'BlitzStars',
),
]; ];
}, },
+19 -8
View File
@@ -1,7 +1,7 @@
import { SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import { CYCLIC_API } from '../constants/cyclic.js'; import { CYCLIC_API } from '../constants/cyclic.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
import resolveTankId from '../core/blitz/resolveTankId.js'; import resolveTankId from '../core/blitz/resolveTankId.js';
import { Period } from '../core/discord/addPeriodSubCommands.js';
import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js'; import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups.js';
import autocompleteTanks from '../core/discord/autocompleteTanks.js'; import autocompleteTanks from '../core/discord/autocompleteTanks.js';
import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js';
@@ -12,8 +12,10 @@ import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton.js'
import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js'; import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand.js';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js';
import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js';
import { CommandRegistry } from '../events/interactionCreate/index.js'; import { CommandRegistry } from '../events/interactionCreate/index.js';
import statsfull, { StatType } from '../renderers/statsfull.js'; import statsfull, { StatType } from '../renderers/statsfull.js';
import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
@@ -30,23 +32,32 @@ export default {
const commandGroup = interaction.options.getSubcommandGroup( const commandGroup = interaction.options.getSubcommandGroup(
true, true,
) as StatType; ) as StatType;
const subcommand = interaction.options.getSubcommand() as Period;
const player = await resolvePlayerFromCommand(interaction); const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(interaction); const period = resolvePeriodFromCommand(interaction);
const tankIdRaw = interaction.options.getString('tank')!; const tankIdRaw = interaction.options.getString('tank')!;
const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0; const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0;
const start = interaction.options.getInteger('start'); const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end'); const end = interaction.options.getInteger('end');
const path = `statsfull/${commandGroup}/${subcommand}?server=${ const path = interactionToURL(interaction, {
player.server ...player,
}&id=${player.id}&tankId=${tankId}&start=${start ?? 0}&end=${end ?? 0}`; tankId,
start,
interactionToURL(interaction); end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
return [ return [
await statsfull(commandGroup, period, player, tankId), await statsfull(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'), primaryButton(path, 'Refresh'),
linkButton(path, 'Embed'), linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.server}/${nickname}`,
'BlitzStars',
),
]; ];
}, },
+30 -2
View File
@@ -1,13 +1,21 @@
import { SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import { CYCLIC_API } from '../constants/cyclic.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
import addUsernameChoices from '../core/discord/addUsernameChoices.js'; import addUsernameChoices from '../core/discord/addUsernameChoices.js';
import autocompleteUsername from '../core/discord/autocompleteUsername.js'; import autocompleteUsername from '../core/discord/autocompleteUsername.js';
import interactionToURL from '../core/discord/interactionToURL.js';
import linkButton from '../core/discord/linkButton.js';
import primaryButton from '../core/discord/primaryButton.js';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton.js';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.js';
import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js';
import { CommandRegistry } from '../events/interactionCreate/index.js'; import { CommandRegistry } from '../events/interactionCreate/index.js';
import today from '../renderers/today.js'; import today from '../renderers/today.js';
import { AccountInfo } from '../types/accountInfo.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: new SlashCommandBuilder() command: new SlashCommandBuilder()
@@ -17,9 +25,29 @@ export default {
async handler(interaction) { async handler(interaction) {
const player = await resolvePlayerFromCommand(interaction); const player = await resolvePlayerFromCommand(interaction);
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
const path = interactionToURL(interaction, player);
return await today(player); return [
await today(player),
primaryButton(path, 'Refresh'),
linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.server}/${nickname}`,
'BlitzStars',
),
];
}, },
autocomplete: autocompleteUsername, autocomplete: autocompleteUsername,
async button(interaction) {
const player = await resolvePlayerFromButton(interaction);
return await today(player);
},
} satisfies CommandRegistry; } satisfies CommandRegistry;
+22 -9
View File
@@ -1,20 +1,33 @@
import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import {
CacheType,
ChatInputCommandInteraction,
CommandInteractionOption,
} from 'discord.js';
export interface Parameters {
[key: string]: CommandInteractionOption['value'] | undefined | null;
}
export default function interactionToURL( export default function interactionToURL(
interaction: ChatInputCommandInteraction<CacheType>, interaction: ChatInputCommandInteraction<CacheType>,
parameters?: Parameters,
) { ) {
const pathname = [ const pathname = [
interaction.commandName, interaction.commandName,
interaction.options.getSubcommandGroup(), interaction.options.getSubcommandGroup(false),
interaction.options.getSubcommand(), interaction.options.getSubcommand(false),
] ]
.filter(Boolean) .filter(Boolean)
.join('/'); .join('/');
const urlSearchParams = new URLSearchParams(); const params = [
...interaction.options.data.map(
(option) => [option.name, option.value] as const,
),
...Object.entries(parameters ?? {}),
]
.filter(([, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${key}=${value}`)
.join('&');
interaction.options.data.forEach((option) => { return `${pathname}${params.length > 0 ? `?${params}` : ''}`;
if (option.value) urlSearchParams.set(option.name, `${option.value}`);
});
console.log(`${urlSearchParams}`);
} }
+2 -3
View File
@@ -3,16 +3,15 @@ import {
ButtonStyle, ButtonStyle,
ComponentEmojiResolvable, ComponentEmojiResolvable,
} from 'discord.js'; } from 'discord.js';
import { CYCLIC_API } from '../../constants/cyclic.js';
export default function linkButton( export default function linkButton(
id: string, url: string,
label: string, label: string,
emoji?: ComponentEmojiResolvable, emoji?: ComponentEmojiResolvable,
) { ) {
const button = new ButtonBuilder() const button = new ButtonBuilder()
.setStyle(ButtonStyle.Link) .setStyle(ButtonStyle.Link)
.setURL(`${CYCLIC_API}/${id}`) .setURL(url)
.setLabel(label); .setLabel(label);
if (emoji) button.setEmoji(emoji); if (emoji) button.setEmoji(emoji);
@@ -1,11 +1,13 @@
import { ButtonInteraction, CacheType } from 'discord.js'; import { ButtonInteraction, CacheType } from 'discord.js';
import { CYCLIC_API } from '../../../constants/cyclic.js';
import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable.js';
import { commands } from '../index.js'; import { commands } from '../index.js';
export default async function handleButton( export default async function handleButton(
interaction: ButtonInteraction<CacheType>, interaction: ButtonInteraction<CacheType>,
) { ) {
const commandName = interaction.customId.split('/')[0]; const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const commandName = url.pathname.split('/')[1];
const button = commands[commandName]?.button; const button = commands[commandName]?.button;
if (!button) { if (!button) {
+4 -4
View File
@@ -21,7 +21,7 @@ export default async function evolution<Type extends StatType>(
type: Type, type: Type,
{ start, end, evolutionName }: ResolvedPeriod, { start, end, evolutionName }: ResolvedPeriod,
{ server, id }: ResolvedPlayer, { server, id }: ResolvedPlayer,
tankId: Type extends 'tank' ? number : never, tankId: Type extends 'tank' ? number : null,
) { ) {
let nameDiscriminator: string | undefined; let nameDiscriminator: string | undefined;
let image: string | undefined; let image: string | undefined;
@@ -38,8 +38,8 @@ export default async function evolution<Type extends StatType>(
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
: undefined; : undefined;
} else { } else {
nameDiscriminator = `(${resolveTankName(tankId)})`; nameDiscriminator = `(${resolveTankName(tankId!)})`;
image = tankopedia[tankId].images.normal; image = tankopedia[tankId!].images.normal;
} }
let histories: Histories; let histories: Histories;
@@ -53,7 +53,7 @@ export default async function evolution<Type extends StatType>(
}); });
} else { } else {
histories = await getTankHistories(server, id, { histories = await getTankHistories(server, id, {
tankId, tankId: tankId!,
start, start,
end, end,
includeLatestHistories: true, includeLatestHistories: true,
+6 -6
View File
@@ -28,7 +28,7 @@ export default async function stats<Type extends StatType>(
type: Type, type: Type,
{ start, end, statsName }: ResolvedPeriod, { start, end, statsName }: ResolvedPeriod,
{ server, id }: ResolvedPlayer, { server, id }: ResolvedPlayer,
tankId: Type extends 'tank' ? number : never, tankId: Type extends 'tank' ? number : null,
) { ) {
let nameDiscriminator: string | undefined; let nameDiscriminator: string | undefined;
let image: string | undefined; let image: string | undefined;
@@ -45,8 +45,8 @@ export default async function stats<Type extends StatType>(
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
: undefined; : undefined;
} else if (type === 'tank') { } else if (type === 'tank') {
nameDiscriminator = `(${resolveTankName(tankId)})`; nameDiscriminator = `(${resolveTankName(tankId!)})`;
image = tankopedia[tankId].images.normal; image = tankopedia[tankId!].images.normal;
} }
const tankStats = await getTankStatsDiffed(server, id, start, end); const tankStats = await getTankStatsDiffed(server, id, start, end);
@@ -112,11 +112,11 @@ export default async function stats<Type extends StatType>(
{}, {},
); );
} else { } else {
stats = tankStats[tankId]; stats = tankStats[tankId!];
supplementaryStats = { supplementaryStats = {
WN8: calculateWN8(tankAverages[tankId].all, tankStats[tankId]), WN8: calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]),
tier: tankopedia[tankId].tier, tier: tankopedia[tankId!].tier,
}; };
} }