1 import axios from 'axios';
2 import React from 'react';
3 import { Alert, Button, Col, Form, Row } from 'react-bootstrap';
4 import { useTranslation } from 'react-i18next';
5 import toastr from 'toastr';
7 import ChatSettingsForm from './ChatSettingsForm';
8 import CommandDialog from './CommandDialog';
9 import Commands from './Commands';
10 import GuessingSettingsForm from './GuessingSettingsForm';
11 import ChatBotLog from '../chat-bot-logs/ChatBotLog';
12 import ChannelSelect from '../common/ChannelSelect';
13 import Icon from '../common/Icon';
14 import ToggleSwitch from '../common/ToggleSwitch';
16 const CHAT_CATEGORIES = [
31 const Controls = () => {
32 const [channel, setChannel] = React.useState(null);
33 const [chatText, setChatText] = React.useState('');
34 const [editCommand, setEditCommand] = React.useState('');
35 const [editCommandSettings, setEditCommandSettings] = React.useState({});
36 const [showCommandDialog, setShowCommandDialog] = React.useState(false);
38 const { t } = useTranslation();
40 const chat = React.useCallback(async (text, bot_nick) => {
42 await axios.post(`/api/channels/${channel.id}/chat`, {
46 toastr.success(t('twitchBot.chatSuccess'));
48 toastr.error(t('twitchBot.chatError'));
50 }, [channel, chatText, t]);
52 const randomChat = React.useCallback(async (category) => {
54 await axios.post(`/api/channels/${channel.id}/chat`, {
55 bot_nick: 'horstiebot',
58 toastr.success(t('twitchBot.chatSuccess'));
60 toastr.error(t('twitchBot.chatError'));
62 }, [channel, chatText, t]);
64 const join = React.useCallback(async (bot_nick) => {
66 const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
68 toastr.success(t('twitchBot.joinSuccess'));
70 toastr.error(t('twitchBot.joinError'));
74 const part = React.useCallback(async (bot_nick) => {
76 const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
78 toastr.success(t('twitchBot.partSuccess'));
80 toastr.error(t('twitchBot.partError'));
84 const saveChatSettings = React.useCallback(async (values) => {
86 const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
88 toastr.success(t('twitchBot.saveSuccess'));
90 toastr.error(t('twitchBot.saveError'));
94 const onAddCommand = React.useCallback(() => {
96 setEditCommandSettings({});
97 setShowCommandDialog(true);
100 const onEditCommand = React.useCallback((name, settings) => {
101 setEditCommand(name);
102 setEditCommandSettings(settings);
103 setShowCommandDialog(true);
106 const onRemoveCommand = React.useCallback(async (name) => {
108 const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
109 setChannel(rsp.data);
110 toastr.success(t('twitchBot.saveSuccess'));
112 toastr.error(t('twitchBot.saveError'));
116 const saveCommand = React.useCallback(async (values) => {
118 const rsp = await axios.put(
119 `/api/channels/${channel.id}/commands/${values.name}`,
122 setChannel(rsp.data);
123 setShowCommandDialog(false);
125 setEditCommandSettings({});
126 toastr.success(t('twitchBot.saveSuccess'));
128 toastr.error(t('twitchBot.saveError'));
133 const saveGuessingGame = React.useCallback(async (values) => {
135 const rsp = await axios.put(
136 `/api/channels/${channel.id}/guessing-game/${values.name}`,
139 setChannel(rsp.data);
140 toastr.success(t('twitchBot.saveSuccess'));
142 toastr.error(t('twitchBot.saveError'));
148 <Row className="mb-4">
149 <Form.Group as={Col} md={6}>
150 <Form.Label>{t('twitchBot.channel')}</Form.Label>
156 onChange={({ channel }) => { setChannel(channel); }}
157 value={channel ? channel.id : ''}
161 <Form.Group as={Col} md={3}>
162 <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
166 onChange={({ target: { value } }) => {
168 join('localhorsttv');
170 part('localhorsttv');
177 <Form.Group as={Col} md={3}>
178 <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
182 onChange={({ target: { value } }) => {
197 <Col className="mt-5" md={6}>
198 <h3>{t('twitchBot.chat')}</h3>
200 <Form.Label>{t('twitchBot.chat')}</Form.Label>
203 onChange={({ target: { value } }) => {
208 <div className="button-bar">
211 disabled={!chatText || !channel.join}
213 if (chatText) chat(chatText, 'localhorsttv');
217 {t('twitchBot.sendApp')}
221 disabled={!chatText || !channel.chat}
223 if (chatText) chat(chatText, 'horstiebot');
227 {t('twitchBot.sendChat')}
231 <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
232 <div className="button-bar">
233 {CHAT_CATEGORIES.map(category =>
236 onClick={() => { randomChat(category); }}
237 variant="outline-secondary"
239 {t(`twitchBot.chatCategories.${category}`)}
244 <Col className="mt-5" md={6}>
245 <div className="d-flex justify-content-between">
246 <h3>{t('twitchBot.chatSettings')}</h3>
247 <div className="button-bar">
248 <ChatBotLog id={channel.id} />
251 <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
253 <Col className="mt-5" md={12}>
254 <h3>{t('twitchBot.commands')}</h3>
257 onEditCommand={onEditCommand}
258 onRemoveCommand={onRemoveCommand}
263 setShowCommandDialog(false);
265 setEditCommandSettings({});
267 onSubmit={saveCommand}
268 settings={editCommandSettings}
269 show={showCommandDialog}
272 <Button onClick={onAddCommand} variant="primary">
273 {t('twitchBot.addCommand')}
277 <Col className="mt-5" md={12}>
278 <div className="d-flex align-items-end justify-content-between">
279 <h3>{t('twitchBot.guessingGame.settings')}</h3>
280 <div className="button-bar">
281 {channel.access_key ?
283 href={`/guessing-game/monitor/${channel.access_key}`}
285 title={t('button.browserSource')}
286 variant="outline-secondary"
288 <Icon.BROWSER_SOURCE title="" />
294 `/guessing-game/controls/${channel.id}`,
296 'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
299 title={t('twitchBot.guessingGame.popoutControls')}
300 variant="outline-secondary"
302 <Icon.OPEN title="" />
306 <GuessingSettingsForm
308 onSubmit={saveGuessingGame}
309 settings={channel.guessing_settings?.gtbk || {}}
314 <Alert variant="info">
315 {t('twitchBot.selectChannel')}
321 export default Controls;