import React, { useEffect, useMemo, useState } from 'react'; import { fetchChannels, fetchSounds, playSound } from './api'; import type { VoiceChannelInfo, Sound } from './types'; export default function App() { const [sounds, setSounds] = useState([]); const [channels, setChannels] = useState([]); const [query, setQuery] = useState(''); const [selected, setSelected] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { (async () => { try { const [s, c] = await Promise.all([fetchSounds(), fetchChannels()]); setSounds(s); setChannels(c); if (c[0]) setSelected(`${c[0].guildId}:${c[0].channelId}`); } catch (e: any) { setError(e?.message || 'Fehler beim Laden'); } })(); const interval = setInterval(async () => { try { const s = await fetchSounds(query); setSounds(s); } catch {} }, 10000); return () => clearInterval(interval); }, []); const filtered = useMemo(() => { const q = query.trim().toLowerCase(); if (!q) return sounds; return sounds.filter((s) => s.name.toLowerCase().includes(q)); }, [sounds, query]); async function handlePlay(name: string) { setError(null); if (!selected) return setError('Bitte einen Voice-Channel auswählen'); const [guildId, channelId] = selected.split(':'); try { setLoading(true); await playSound(name, guildId, channelId); } catch (e: any) { setError(e?.message || 'Play fehlgeschlagen'); } finally { setLoading(false); } } return (

Discord Soundboard

Schicke dem Bot per privater Nachricht eine .mp3 — neue Sounds erscheinen automatisch.

setQuery(e.target.value)} placeholder="Nach Sounds suchen..." aria-label="Suche" />
{error &&
{error}
}
{filtered.map((s) => ( ))} {filtered.length === 0 &&
Keine Sounds gefunden.
}
); }