feat: simpler subcommands

This commit is contained in:
TrèsAbhi committed 2023-10-11 18:26:35 -05:00
1 parent f965452c5d
commit 78e4c82f20
28 files changed
+397 -461

No files matched your search

+19 -32
View File
@@ -1,55 +1,42 @@
import {
SlashCommandSubcommandBuilder,
SlashCommandSubcommandGroupBuilder,
} from 'discord.js';
import { SlashCommandBuilder, SlashCommandSubcommandBuilder } from 'discord.js';
export type PeriodType = 'period' | 'custom';
export type PeriodSize = `${number}` | 'career';
export type PeriodType = 'today' | '30' | '60' | '90' | 'custom';
export type PeriodSize = 'today' | `${number}` | 'career';
export default function addPeriodSubCommands(
option: SlashCommandSubcommandGroupBuilder,
option: SlashCommandBuilder,
extra: (
option: SlashCommandSubcommandBuilder,
) => SlashCommandSubcommandBuilder = (option) => option,
) {
return option
option
.addSubcommand((option) =>
extra(
option
.setName('period' satisfies PeriodType)
.setDescription("Preset period's statistics")
.addStringOption((option) =>
option
.setName('period')
.setDescription('A preset period')
.setChoices(
{ name: 'Today', value: '1' satisfies PeriodSize },
{ name: '30 days', value: '30' satisfies PeriodSize },
{ name: '60 days', value: '60' satisfies PeriodSize },
{ name: '90 days', value: '90' satisfies PeriodSize },
{ name: 'Career', value: 'career' satisfies PeriodSize },
)
.setRequired(true),
),
),
extra(option.setName('today').setDescription('Today')),
)
.addSubcommand((option) =>
extra(option.setName('30').setDescription('30 days')),
)
.addSubcommand((option) =>
extra(option.setName('60').setDescription('60 days')),
)
.addSubcommand((option) =>
extra(option.setName('90').setDescription('90 days')),
)
.addSubcommand((option) =>
extra(
option
.setName('custom' satisfies PeriodType)
.setDescription("Custom period's statistics")
.setName('custom')
.setDescription('Custom range')
.addIntegerOption((option) =>
option
.setName('start')
.setDescription('Days ago from today')
.setMinValue(0)
.setDescription('Start in number of days ago from today')
.setRequired(true),
)
.addIntegerOption((option) =>
option
.setName('end')
.setDescription('Days ago from today')
.setMinValue(0)
.setDescription('End in number of days')
.setRequired(true),
),
),
+53 -74
View File
@@ -1,91 +1,70 @@
import { SlashCommandBuilder } from 'discord.js';
import { TreeTypeString } from '../../components/Tanks';
import { StatType } from '../../renderers/stats';
import { SlashCommandBuilder, SlashCommandSubcommandBuilder } from 'discord.js';
import { TREE_TYPE_NAMES, TreeTypeString } from '../../components/Tanks';
import { tankopediaInfo } from '../blitz/tankopedia';
import addPeriodSubCommands from './addPeriodSubCommands';
import addTankChoices from './addTankChoices';
import addTierChoices from './addTierChoices';
import addUsernameChoices from './addUsernameChoices';
export default async function addStatTypeSubCommandGroups(
option: SlashCommandBuilder,
addMultiTank = true,
extra: (
option: SlashCommandSubcommandBuilder,
) => SlashCommandSubcommandBuilder = (option) => option,
) {
const awaitedTankopediaInfo = await tankopediaInfo;
option
.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
option.addStringOption(addUsernameChoices),
)
.setName('player' satisfies StatType)
.setDescription('Player statistics'),
)
.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
option
.addStringOption(addTankChoices)
.addStringOption(addUsernameChoices),
)
.setName('tank' satisfies StatType)
.setDescription('Tank statistics'),
);
addPeriodSubCommands(option, (option) => {
extra(option);
if (addMultiTank)
option.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
return option
.addStringOption((option) =>
option
.addStringOption(addUsernameChoices)
.addStringOption((option) => {
option
.setName('nation')
.setDescription('Nation')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_nations).map(
([type, name]) => ({ name, value: type }),
),
);
return option;
})
.addStringOption((option) =>
option
.setName('tank-type')
.setDescription('Type')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_types).map(
([type, name]) => ({
name: name.replace(' Tank', ''),
value: type,
}),
),
)
.setRequired(false),
.setName('nation')
.setDescription('Nation')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_nations).map(
([type, name]) => ({ name, value: type }),
),
)
.addStringOption((option) =>
addTierChoices(option).setRequired(false),
)
.addStringOption((option) =>
option
.setName('tree-type')
.setDescription('Tech tree type')
.addChoices(
{
name: 'Tech Tree',
value: 'techtree' satisfies TreeTypeString,
},
{ name: 'Premium', value: 'premium' satisfies TreeTypeString },
{
name: 'Collector',
value: 'collector' satisfies TreeTypeString,
},
)
.setRequired(false),
),
.setRequired(false),
)
.setName('multi-tank' satisfies StatType)
.setDescription('Multiple tanks'),
);
.addStringOption((option) => addTierChoices(option).setRequired(false))
.addStringOption((option) =>
option
.setName('tank-type')
.setDescription('Tank type')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_types).map(
([type, name]) => ({
name: name.replace(' Tank', ''),
value: type,
}),
),
)
.setRequired(false),
)
.addStringOption((option) =>
option
.setName('tree-type')
.setDescription('Tech tree type')
.addChoices(
{
name: TREE_TYPE_NAMES['tech-tree'],
value: 'tech-tree' satisfies TreeTypeString,
},
{
name: TREE_TYPE_NAMES.premium,
value: 'premium' satisfies TreeTypeString,
},
{
name: TREE_TYPE_NAMES.collector,
value: 'collector' satisfies TreeTypeString,
},
)
.setRequired(false),
)
.addStringOption((option) => addTankChoices(option).setRequired(false));
});
return option;
}
+2 -6
View File
@@ -1,11 +1,7 @@
import {
CacheType,
ChatInputCommandInteraction,
CommandInteractionOption,
} from 'discord.js';
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
export interface Parameters {
[key: string]: CommandInteractionOption['value'] | undefined | null;
[key: string]: string | number | boolean | undefined | null;
}
export default function interactionToURL(
+16
View File
@@ -0,0 +1,16 @@
import { ChatInputCommandInteraction } from 'discord.js';
import primaryButton from './primaryButton';
export function refreshButton(
interaction: ChatInputCommandInteraction,
path: string,
) {
if (
interaction.appPermissions?.has('AttachFiles') &&
interaction.appPermissions?.has('ViewChannel')
) {
return primaryButton(path, 'Refresh');
}
return null;
}
+4 -2
View File
@@ -1,5 +1,4 @@
import { ButtonInteraction, CacheType } from 'discord.js';
import { CYCLIC_API } from '../../constants/cyclic';
import { Region } from '../../constants/regions';
import resolvePeriodFromURL from './resolvePeriodFromURL';
@@ -7,5 +6,8 @@ export default function resolvePeriodFromButton(
server: Region,
interaction: ButtonInteraction<CacheType>,
) {
return resolvePeriodFromURL(server, `${CYCLIC_API}/${interaction.customId}`);
return resolvePeriodFromURL(
server,
`https://example.com/${interaction.customId}`,
);
}
+13 -17
View File
@@ -6,12 +6,13 @@ import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo';
import { PeriodSize, PeriodType } from '../discord/addPeriodSubCommands';
export function getPeriodOptionName(period: PeriodSize) {
return period === 'career' ? 'Career' : `${period}-day`;
if (period === 'career') return 'Career';
if (period === 'today') return 'Today';
return `${period} days`;
}
export interface ResolvedPeriod {
statsName: string;
evolutionName: string;
name: string;
start: number;
end: number;
}
@@ -20,33 +21,28 @@ export default function resolvePeriodFromCommand(
region: Region,
interaction: ChatInputCommandInteraction<CacheType>,
) {
let statsName: string;
let evolutionName: string;
let name: string;
let start: number;
let end: number;
const periodSubcommand = interaction.options.getSubcommand() as PeriodType;
const periodOption = interaction.options.getString('period') as PeriodSize;
if (periodSubcommand === 'custom') {
const startRaw = interaction.options.getInteger('start', true);
const endRaw = interaction.options.getInteger('end', true);
const startDaysAgoMin = Math.min(startRaw, endRaw);
const endDaysAgoMax = Math.max(startRaw, endRaw);
const startOption = interaction.options.getInteger('start', true);
const endOption = interaction.options.getInteger('end', true);
const startDaysAgoMin = Math.min(startOption, endOption);
const endDaysAgoMax = Math.max(startOption, endOption);
statsName = `${startDaysAgoMin} to ${endDaysAgoMax} days' statistics`;
evolutionName = `${startDaysAgoMin} to ${endDaysAgoMax} days' evolution`;
name = `${startDaysAgoMin} - ${endDaysAgoMax} days`;
start = getTimeDaysAgo(region, endDaysAgoMax);
end = getTimeDaysAgo(region, startDaysAgoMin);
} else {
statsName = `${getPeriodOptionName(periodOption)} Statistics`;
evolutionName = `${getPeriodOptionName(periodOption)} Evolution`;
start = getPeriodStart(region, periodOption);
name = getPeriodOptionName(periodSubcommand);
start = getPeriodStart(region, periodSubcommand);
end = getPeriodNow();
}
return {
statsName,
evolutionName,
name,
start,
end,
} satisfies ResolvedPeriod;
+15 -15
View File
@@ -2,24 +2,22 @@ import { Region } from '../../constants/regions';
import getPeriodNow from '../blitzstars/getPeriodNow';
import getPeriodStart from '../blitzstars/getPeriodStart';
import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo';
import { PeriodSize, PeriodType } from './addPeriodSubCommands';
import { PeriodType } from './addPeriodSubCommands';
import {
ResolvedPeriod,
getPeriodOptionName,
} from './resolvePeriodFromCommand';
export default function resolvePeriodFromURL(
server: Region,
region: Region,
urlString: string,
) {
let statsName: string;
let evolutionName: string;
let name: string;
let start: number;
let end: number;
const url = new URL(urlString);
const path = url.pathname.split('/').filter(Boolean);
const periodSubcommand = path[path.length - 1] as PeriodType;
const periodOption = url.searchParams.get('period') as PeriodSize;
const path = url.pathname.split('/');
const periodSubcommand = path[2] as PeriodType;
if (periodSubcommand === 'custom') {
const startRaw = parseInt(url!.searchParams.get('start')!);
@@ -27,16 +25,18 @@ export default function resolvePeriodFromURL(
const startDaysAgoMin = Math.min(startRaw, endRaw);
const endDaysAgoMax = Math.max(startRaw, endRaw);
statsName = `${startDaysAgoMin} to ${endDaysAgoMax} days' statistics`;
evolutionName = `${startDaysAgoMin} to ${endDaysAgoMax} days' evolution`;
start = getTimeDaysAgo(server, endDaysAgoMax);
end = getTimeDaysAgo(server, startDaysAgoMin);
name = `${startDaysAgoMin} - ${endDaysAgoMax} days`;
start = getTimeDaysAgo(region, endDaysAgoMax);
end = getTimeDaysAgo(region, startDaysAgoMin);
} else {
statsName = `${getPeriodOptionName(periodOption)} Statistics`;
evolutionName = `${getPeriodOptionName(periodOption)} Evolution`;
start = getPeriodStart(server, periodOption);
name = getPeriodOptionName(periodSubcommand);
start = getPeriodStart(region, periodSubcommand);
end = getPeriodNow();
}
return { statsName, evolutionName, start, end } satisfies ResolvedPeriod;
return {
name,
start,
end,
} satisfies ResolvedPeriod;
}
+1 -2
View File
@@ -1,9 +1,8 @@
import { ButtonInteraction, CacheType } from 'discord.js';
import { CYCLIC_API } from '../../constants/cyclic';
import resolvePlayerFromURL from './resolvePlayerFromURL';
export default async function resolvePlayerFromButton(
interaction: ButtonInteraction<CacheType>,
) {
return resolvePlayerFromURL(`${CYCLIC_API}/${interaction.customId}`);
return resolvePlayerFromURL(`https://exmaple.com/${interaction.customId}`);
}