Files
Papo/src/commands/utility/task.ts
Pepe44DEV 2ff54970e2
All checks were successful
Deploy Discord Bot / deploy (push) Successful in -1m11s
SonarQube / sonar (push) Successful in -3s
add setup wizard, lockdown, team tasks, embed builder; fix admin dashboard
Four new independent features: /setup (guided onboarding wizard for
module/channel/automod-strength config), /lockdown (raid protection with
per-channel permission snapshot/restore and join-kick), /task (staff task
tracker with status buttons + dashboard view), /embed create (modal-driven
embed builder with optional link button). Also fixes the Admin dashboard,
which always showed "-" because loadAdminData() double-wrapped the overview
response and discarded activity data, plus mismatched field names against
adminService's actual shape (guildCount/activeGuilds24/uptimeMs).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 01:02:39 +02:00

67 lines
2.8 KiB
TypeScript

import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ChatInputCommandInteraction,
EmbedBuilder,
PermissionFlagsBits,
SlashCommandBuilder
} from 'discord.js';
import { SlashCommand } from '../../utils/types';
import { context } from '../../config/context';
const STATUS_LABELS: Record<string, string> = { open: 'Offen', in_progress: 'In Bearbeitung', done: 'Erledigt' };
export function buildTaskCard(task: { id: string; title: string; description: string | null; status: string; assigneeId: string | null; createdByTag: string }) {
const embed = new EmbedBuilder()
.setTitle(task.title)
.setDescription(task.description || 'Keine Beschreibung')
.setColor(0xf97316)
.addFields(
{ name: 'Status', value: STATUS_LABELS[task.status] || task.status, inline: true },
{ name: 'Zugewiesen an', value: task.assigneeId ? `<@${task.assigneeId}>` : 'Niemand', inline: true },
{ name: 'Erstellt von', value: task.createdByTag, inline: true }
);
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId(`task:status:${task.id}:open`).setLabel('Offen').setStyle(task.status === 'open' ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder().setCustomId(`task:status:${task.id}:in_progress`).setLabel('In Bearbeitung').setStyle(task.status === 'in_progress' ? ButtonStyle.Primary : ButtonStyle.Secondary),
new ButtonBuilder().setCustomId(`task:status:${task.id}:done`).setLabel('Erledigt').setStyle(task.status === 'done' ? ButtonStyle.Success : ButtonStyle.Secondary)
);
return { embeds: [embed], components: [row] };
}
const command: SlashCommand = {
guildOnly: true,
data: new SlashCommandBuilder()
.setName('task')
.setDescription('Verwaltet Team-Aufgaben.')
.addSubcommand((sub) =>
sub
.setName('create')
.setDescription('Erstellt eine neue Team-Aufgabe.')
.addStringOption((opt) => opt.setName('title').setDescription('Titel der Aufgabe').setRequired(true))
.addStringOption((opt) => opt.setName('description').setDescription('Beschreibung'))
.addUserOption((opt) => opt.setName('assignee').setDescription('Zuständige Person'))
)
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages),
async execute(interaction: ChatInputCommandInteraction) {
if (!interaction.guildId) return;
const title = interaction.options.getString('title', true);
const description = interaction.options.getString('description') ?? undefined;
const assignee = interaction.options.getUser('assignee');
const task = await context.tasks.createTask({
guildId: interaction.guildId,
title,
description,
assigneeId: assignee?.id,
createdBy: interaction.user.id,
createdByTag: interaction.user.tag
});
await interaction.reply(buildTaskCard(task));
}
};
export default command;