diff --git a/src/commands/inactive.ts b/src/commands/inactive.ts deleted file mode 100644 index 1b8b5d257..000000000 --- a/src/commands/inactive.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; -import markdownEscape from 'markdown-escape'; -import { NEGATIVE_COLOR, POSITIVE_COLOR } from '../constants/colors.js'; -import clanAutocomplete from '../core/autocomplete/clan.js'; -import getBlitzClan from '../core/blitz/getBlitzClan.js'; -import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; -import cmdName from '../core/interaction/cmdName.js'; -import addClanChoices from '../core/options/addClanChoices.js'; -import { args } from '../core/process/args.js'; -import { CommandRegistry } from '../events/interactionCreate.js'; -import { AccountInfo } from '../types/accountInfo.js'; -import { ClanInfo } from '../types/clanInfo.js'; - -const DEFAULT_THRESHOLD = 7; - -export default { - inProduction: true, - inDevelopment: false, - inPublic: true, - - command: new SlashCommandBuilder() - .setName(cmdName('inactive')) - .setDescription('Lists all inactive players') - .addStringOption(addClanChoices) - .addNumberOption((option) => - option - .setName('threshold') - .setDescription( - `The number of days inactive (default: ${DEFAULT_THRESHOLD})`, - ) - .setMinValue(0), - ), - - async execute(interaction) { - const clanName = interaction.options.getString('clan')!; - const clan = await getBlitzClan(interaction, clanName); - const { server, id } = clan; - - const threshold = - interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD; - const time = new Date().getTime() / 1000; - const clanInfo = await getWargamingResponse( - `https://api.wotblitz.${server}/wotb/clans/info/?application_id=${args['wargaming-application-id']}&clan_id=${id}`, - ); - const memberIds = clanInfo[id].members_ids; - const accountInfo = await getWargamingResponse( - `https://api.wotblitz.${server}/wotb/account/info/?application_id=${ - args['wargaming-application-id'] - }&account_id=${memberIds.join(',')}`, - ); - const inactiveInfo = memberIds - .map((memberId) => { - const member = accountInfo[memberId]; - const inactiveDays = (time - member.last_battle_time) / 60 / 60 / 24; - - return [member.nickname, inactiveDays] as const; - }) - .filter(([, inactiveDays]) => inactiveDays >= threshold) - .sort((a, b) => b[1] - a[1]) - .map(([nickname, inactiveDays]) => { - const days = Math.floor(inactiveDays); - return `**${markdownEscape(nickname)}**: ${days} day${ - days === 1 ? '' : 's' - }`; - }); - const hasInactiveMembers = inactiveInfo.length > 0; - - await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setColor(hasInactiveMembers ? NEGATIVE_COLOR : POSITIVE_COLOR) - .setTitle( - hasInactiveMembers - ? `${markdownEscape(clanInfo[id].name)}'s inactive members` - : `No inactive members in ${markdownEscape(clanInfo[id].name)}`, - ) - .setDescription( - hasInactiveMembers - ? `Players that exceed the threshold of ${threshold} days:\n\n${inactiveInfo.join( - '\n', - )}` - : `No players exceed the threshold of ${threshold} days.`, - ), - ], - }); - }, - - autocomplete: clanAutocomplete, -} satisfies CommandRegistry; diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx new file mode 100644 index 000000000..3fd4a59c5 --- /dev/null +++ b/src/commands/inactive.tsx @@ -0,0 +1,92 @@ +import { SlashCommandBuilder } from 'discord.js'; +import GenericStats from '../components/GenericStats/index.js'; +import NoData, { NoDataType } from '../components/NoData.js'; +import PoweredByWargaming from '../components/PoweredByWargaming.js'; +import TitleBar from '../components/TitleBar.js'; +import Wrapper from '../components/Wrapper.js'; +import { BLITZ_SERVERS } from '../constants/servers.js'; +import clanAutocomplete from '../core/autocomplete/clan.js'; +import getBlitzClan from '../core/blitz/getBlitzClan.js'; +import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; +import cmdName from '../core/interaction/cmdName.js'; +import addClanChoices from '../core/options/addClanChoices.js'; +import { args } from '../core/process/args.js'; +import render from '../core/ui/render.js'; +import { CommandRegistry } from '../events/interactionCreate.js'; +import { AccountInfo } from '../types/accountInfo.js'; +import { ClanInfo } from '../types/clanInfo.js'; + +const DEFAULT_THRESHOLD = 7; + +export default { + inProduction: true, + inDevelopment: true, + inPublic: true, + + command: new SlashCommandBuilder() + .setName(cmdName('inactive')) + .setDescription('Lists all inactive players') + .addStringOption(addClanChoices) + .addNumberOption((option) => + option + .setName('threshold') + .setDescription( + `The number of days inactive (default: ${DEFAULT_THRESHOLD})`, + ) + .setMinValue(0), + ), + + async execute(interaction) { + const clanName = interaction.options.getString('clan')!; + const { server, id } = await getBlitzClan(interaction, clanName); + const threshold = + interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD; + const time = new Date().getTime() / 1000; + const clanData = ( + await getWargamingResponse( + `https://api.wotblitz.${server}/wotb/clans/info/?application_id=${args['wargaming-application-id']}&clan_id=${id}`, + ) + )[id]; + const memberIds = clanData.members_ids; + const accounts = await getWargamingResponse( + `https://api.wotblitz.${server}/wotb/account/info/?application_id=${ + args['wargaming-application-id'] + }&account_id=${memberIds.join(',')}`, + ); + const inactive = memberIds + .map((memberId) => { + const member = accounts[memberId]; + const inactiveDays = (time - member.last_battle_time) / 60 / 60 / 24; + + return [member.nickname, inactiveDays] as [string, number]; + }) + .filter(([, inactiveDays]) => inactiveDays >= threshold) + .sort((a, b) => b[1] - a[1]) + .map( + ([name, days]) => [name, `${days.toFixed(0)} days`] as [string, string], + ); + const hasInactiveMembers = inactive.length > 0; + + const image = await render( + + + + {!hasInactiveMembers && } + {hasInactiveMembers && } + + + , + ); + + await interaction.editReply({ files: [image] }); + }, + + autocomplete: clanAutocomplete, +} satisfies CommandRegistry; diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index f9354e72e..e5f13ae4e 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -4,7 +4,7 @@ import { SlashCommandBuilder, } from 'discord.js'; import GenericAllStats from '../components/GenericAllStats.js'; -import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js'; +import NoData, { NoDataType } from '../components/NoData.js'; import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; import TitleBar from '../components/TitleBar.js'; import Wrapper from '../components/Wrapper.js'; @@ -151,7 +151,7 @@ export default { } • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`} /> - {stats.battles === 0 && } + {stats.battles === 0 && } {stats.battles > 0 && ( - {stats.battles === 0 && } + {stats.battles === 0 && } {stats.battles > 0 && ( - {rows.length === 0 && } + {rows.length === 0 && } {rows.length > 0 && {rows}} diff --git a/src/components/NoBattlesInPeriod.tsx b/src/components/NoBattlesInPeriod.tsx deleted file mode 100644 index 1f30a4913..000000000 --- a/src/components/NoBattlesInPeriod.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { theme } from '../stitches.config.js'; - -export default function NoBattlesInPeriod() { - return ( -
- - No battles played in this period - -
- ); -} diff --git a/src/components/NoData.tsx b/src/components/NoData.tsx new file mode 100644 index 000000000..1b4231829 --- /dev/null +++ b/src/components/NoData.tsx @@ -0,0 +1,31 @@ +import { theme } from '../stitches.config.js'; + +export enum NoDataType { + Battles, + Players, +} + +export interface NoDataProps { + type: NoDataType; +} + +const NO_DATA_MESSAGES: Record = { + [NoDataType.Battles]: 'No battles played in this period', + [NoDataType.Players]: 'No players in this period', +}; + +export default function NoData({ type }: NoDataProps) { + return ( +
+ + {NO_DATA_MESSAGES[type]} + +
+ ); +}