First pass on bot management page

This commit is contained in:
Benjamin Sherriff
2023-10-08 00:18:39 -04:00
parent 0ec6264bfa
commit 1035d3bc21
8 changed files with 233 additions and 4 deletions

33
ui/src/api/guilds.ts Normal file
View File

@@ -0,0 +1,33 @@
import { getRequest, postRequest } from '.';
import { GuildChannel, GuildInfo } from './guilds.types';
export async function getGuilds(): Promise<GuildInfo[]> {
const response = await getRequest('guilds', {});
return response?.data || { data: [] };
}
export async function getTextChannels(guildId: number): Promise<GuildChannel[]> {
const response = await getRequest(`guilds/${guildId}/text`, {});
return response?.data || { data: [] };
}
export async function getVoiceChannels(guildId: number): Promise<GuildChannel[]> {
const response = await getRequest(`guilds/${guildId}/voice`, {});
return response?.data || { data: [] };
}
export async function playTrack(guildId: number, channelId: number, track: string): Promise<void> {
await postRequest(`guilds/${guildId}/voice/${channelId}/play`, { track_url: track });
}
export async function stopTrack(guildId: number, channelId: number): Promise<void> {
await postRequest(`guilds/${guildId}/voice/${channelId}/stop`, {});
}
export async function pauseTrack(guildId: number, channelId: number): Promise<void> {
await postRequest(`guilds/${guildId}/voice/${channelId}/pause`, {});
}
export async function resumeTrack(guildId: number, channelId: number): Promise<void> {
await postRequest(`guilds/${guildId}/voice/${channelId}/resume`, {});
}

View File

@@ -0,0 +1,13 @@
export interface GuildInfo {
id: number;
icon?: string;
name: string;
owner: boolean;
}
export interface GuildChannel {
id: number;
name: string;
type: string;
guild_id: number;
}

View File

@@ -12,7 +12,7 @@ export async function getRequest(endpoint: string, params: any): Promise<AxiosRe
export async function postRequest(endpoint: string, body: any): Promise<AxiosResponse<any, any> | undefined> {
const response = await axios
.post(`${serviceHost}:${servicePort}/${endpoint}`, { body })
.post(`${serviceHost}:${servicePort}/${endpoint}`, body || {})
.catch((error) => console.error(error));
return response || undefined;
}

View File

@@ -0,0 +1,106 @@
'use client';
import {
getGuilds,
getTextChannels,
getVoiceChannels,
pauseTrack,
playTrack,
resumeTrack,
stopTrack
} from '@/api/guilds';
import { GuildChannel, GuildInfo } from '@/api/guilds.types';
import { Button, Slider, Tabs, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';
import React, { useEffect, useState } from 'react';
export default function Page() {
const [guilds, setGuilds] = useState<GuildInfo[]>([]);
const [activeGuild, setActiveGuild] = useState<GuildInfo | null>(null);
const [textChannels, setTextChannels] = useState<GuildChannel[]>([]);
const [voiceChannels, setVoiceChannels] = useState<GuildChannel[]>([]);
useEffect(() => {
getGuilds().then((g) => {
setGuilds(g);
if (g.length > 0) {
setActiveGuild(g[0]);
}
});
}, []);
useEffect(() => {
if (activeGuild) {
getTextChannels(activeGuild.id).then((c) => setTextChannels(c));
getVoiceChannels(activeGuild.id).then((c) => setVoiceChannels(c));
}
}, [activeGuild]);
const playForm = useForm({
initialValues: {
trackUrl: ''
}
});
return (
<Tabs orientation='vertical' defaultValue={activeGuild?.name}>
<Tabs.List>
{guilds.map((guild) => (
<Tabs.Tab key={guild.id} value={guild.name} onClick={() => setActiveGuild(guild)}>
{guild.name}
</Tabs.Tab>
))}
</Tabs.List>
{guilds.map((guild) => (
<Tabs.Panel key={guild.id} value={guild.name}>
<h1>{guild.name}</h1>
<h2>Text Channels</h2>
<Tabs orientation='horizontal' defaultValue={textChannels[0]?.name}>
<Tabs.List>
{textChannels.map((channel) => (
<Tabs.Tab key={channel.id} value={channel.name}>
{channel.name}
</Tabs.Tab>
))}
</Tabs.List>
{textChannels.map((channel) => (
<Tabs.Panel key={channel.id} value={channel.name}>
{channel.name}
</Tabs.Panel>
))}
</Tabs>
<h2>Voice Channels</h2>
<Tabs orientation='horizontal' defaultValue={voiceChannels[0]?.name}>
<Tabs.List>
{voiceChannels.map((channel) => (
<Tabs.Tab key={channel.id} value={channel.name}>
{channel.name}
</Tabs.Tab>
))}
</Tabs.List>
{voiceChannels.map((channel) => (
<Tabs.Panel key={channel.id} value={channel.name}>
{channel.name}
<form
style={{ display: 'flex' }}
onSubmit={playForm.onSubmit((values) => {
playTrack(activeGuild!.id, channel.id, values.trackUrl);
})}
>
<TextInput placeholder='Youtube URL...' {...playForm.getInputProps('trackUrl')} />
<Button type='submit'>Play Track</Button>
</form>
<Button onClick={() => stopTrack(activeGuild!.id, channel.id)}>Stop</Button>
<Button onClick={() => pauseTrack(activeGuild!.id, channel.id)}>Pause</Button>
<Button onClick={() => resumeTrack(activeGuild!.id, channel.id)}>Resume</Button>
<div>
<Slider label='Volume' style={{ width: '20%' }} defaultValue={50} onChange={(v) => {}} />
</div>
</Tabs.Panel>
))}
</Tabs>
</Tabs.Panel>
))}
</Tabs>
);
}

View File

@@ -32,6 +32,10 @@ const headerItems = [
{
name: 'Spells',
link: '/spells'
},
{
name: 'Management',
link: '/management'
}
];