mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: /inactive face lift
This commit is contained in:
1 parent
26e78c72b9
commit
1875f30cf5
7 files changed
+129
-112
No files matched your search
@@ -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<ClanInfo>(
|
|
||||||
`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<AccountInfo>(
|
|
||||||
`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;
|
|
||||||
@@ -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<ClanInfo>(
|
||||||
|
`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<AccountInfo>(
|
||||||
|
`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(
|
||||||
|
<Wrapper>
|
||||||
|
<TitleBar
|
||||||
|
name={clanData.name}
|
||||||
|
nameDiscriminator="(Inactivity)"
|
||||||
|
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData.emblem_set_id}.png`}
|
||||||
|
description={`${threshold}+ Days • ${new Date().toDateString()} • ${
|
||||||
|
BLITZ_SERVERS[server]
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!hasInactiveMembers && <NoData type={NoDataType.Players} />}
|
||||||
|
{hasInactiveMembers && <GenericStats stats={inactive} />}
|
||||||
|
|
||||||
|
<PoweredByWargaming />
|
||||||
|
</Wrapper>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.editReply({ files: [image] });
|
||||||
|
},
|
||||||
|
|
||||||
|
autocomplete: clanAutocomplete,
|
||||||
|
} satisfies CommandRegistry;
|
||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import GenericAllStats from '../components/GenericAllStats.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 PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
import TitleBar from '../components/TitleBar.js';
|
import TitleBar from '../components/TitleBar.js';
|
||||||
import Wrapper from '../components/Wrapper.js';
|
import Wrapper from '../components/Wrapper.js';
|
||||||
@@ -151,7 +151,7 @@ export default {
|
|||||||
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
|
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{stats.battles === 0 && <NoBattlesInPeriod />}
|
{stats.battles === 0 && <NoData type={NoDataType.Battles} />}
|
||||||
{stats.battles > 0 && (
|
{stats.battles > 0 && (
|
||||||
<GenericAllStats
|
<GenericAllStats
|
||||||
stats={stats}
|
stats={stats}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import GenericAllStats from '../components/GenericAllStats.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 PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
import TitleBar from '../components/TitleBar.js';
|
import TitleBar from '../components/TitleBar.js';
|
||||||
import Wrapper from '../components/Wrapper.js';
|
import Wrapper from '../components/Wrapper.js';
|
||||||
@@ -92,7 +92,7 @@ export default {
|
|||||||
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
|
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{stats.battles === 0 && <NoBattlesInPeriod />}
|
{stats.battles === 0 && <NoData type={NoDataType.Battles} />}
|
||||||
{stats.battles > 0 && (
|
{stats.battles > 0 && (
|
||||||
<GenericAllStats
|
<GenericAllStats
|
||||||
stats={stats}
|
stats={stats}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import * as Breakdown from '../components/Breakdown/index.js';
|
import * as Breakdown from '../components/Breakdown/index.js';
|
||||||
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
|
import NoData, { NoDataType } from '../components/NoData.js';
|
||||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
import TitleBar from '../components/TitleBar.js';
|
import TitleBar from '../components/TitleBar.js';
|
||||||
import Wrapper from '../components/Wrapper.js';
|
import Wrapper from '../components/Wrapper.js';
|
||||||
@@ -176,7 +176,7 @@ export default {
|
|||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{rows.length === 0 && <NoBattlesInPeriod />}
|
{rows.length === 0 && <NoData type={NoDataType.Battles} />}
|
||||||
{rows.length > 0 && <Breakdown.Root>{rows}</Breakdown.Root>}
|
{rows.length > 0 && <Breakdown.Root>{rows}</Breakdown.Root>}
|
||||||
|
|
||||||
<PoweredByBlitzStars />
|
<PoweredByBlitzStars />
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { theme } from '../stitches.config.js';
|
|
||||||
|
|
||||||
export default function NoBattlesInPeriod() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
|
||||||
No battles played in this period
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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, string> = {
|
||||||
|
[NoDataType.Battles]: 'No battles played in this period',
|
||||||
|
[NoDataType.Players]: 'No players in this period',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NoData({ type }: NoDataProps) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||||
|
{NO_DATA_MESSAGES[type]}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user