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 = [
35 const Controls = () => {
36 const [channel, setChannel] = React.useState(null);
37 const [chatText, setChatText] = React.useState('');
38 const [editCommand, setEditCommand] = React.useState('');
39 const [editCommandSettings, setEditCommandSettings] = React.useState({});
40 const [showCommandDialog, setShowCommandDialog] = React.useState(false);
42 const { t } = useTranslation();
44 const chat = React.useCallback(async (text, bot_nick) => {
46 await axios.post(`/api/channels/${channel.id}/chat`, {
50 toastr.success(t('twitchBot.chatSuccess'));
52 toastr.error(t('twitchBot.chatError'));
54 }, [channel, chatText, t]);
56 const randomChat = React.useCallback(async (category) => {
58 await axios.post(`/api/channels/${channel.id}/chat`, {
59 bot_nick: 'horstiebot',
62 toastr.success(t('twitchBot.chatSuccess'));
64 toastr.error(t('twitchBot.chatError'));
66 }, [channel, chatText, t]);
68 const join = React.useCallback(async (bot_nick) => {
70 const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
72 toastr.success(t('twitchBot.joinSuccess'));
74 toastr.error(t('twitchBot.joinError'));
78 const part = React.useCallback(async (bot_nick) => {
80 const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
82 toastr.success(t('twitchBot.partSuccess'));
84 toastr.error(t('twitchBot.partError'));
88 const saveChatSettings = React.useCallback(async (values) => {
90 const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
92 toastr.success(t('twitchBot.saveSuccess'));
94 toastr.error(t('twitchBot.saveError'));
98 const onAddCommand = React.useCallback(() => {
100 setEditCommandSettings({});
101 setShowCommandDialog(true);
104 const onEditCommand = React.useCallback((name, settings) => {
105 setEditCommand(name);
106 setEditCommandSettings(settings);
107 setShowCommandDialog(true);
110 const onRemoveCommand = React.useCallback(async (name) => {
112 const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
113 setChannel(rsp.data);
114 toastr.success(t('twitchBot.saveSuccess'));
116 toastr.error(t('twitchBot.saveError'));
120 const saveCommand = React.useCallback(async (values) => {
122 const rsp = await axios.put(
123 `/api/channels/${channel.id}/commands/${values.name}`,
126 setChannel(rsp.data);
127 setShowCommandDialog(false);
129 setEditCommandSettings({});
130 toastr.success(t('twitchBot.saveSuccess'));
132 toastr.error(t('twitchBot.saveError'));
137 const saveGuessingGame = React.useCallback(async (values) => {
139 const rsp = await axios.put(
140 `/api/channels/${channel.id}/guessing-game/${values.name}`,
143 setChannel(rsp.data);
144 toastr.success(t('twitchBot.saveSuccess'));
146 toastr.error(t('twitchBot.saveError'));
152 <Row className="mb-4">
153 <Form.Group as={Col} md={6}>
154 <Form.Label>{t('twitchBot.channel')}</Form.Label>
160 onChange={({ channel }) => { setChannel(channel); }}
161 value={channel ? channel.id : ''}
165 <Form.Group as={Col} md={3}>
166 <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
170 onChange={({ target: { value } }) => {
172 join('localhorsttv');
174 part('localhorsttv');
181 <Form.Group as={Col} md={3}>
182 <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
186 onChange={({ target: { value } }) => {
201 <Col className="mt-5" md={6}>
202 <h3>{t('twitchBot.chat')}</h3>
204 <Form.Label>{t('twitchBot.chat')}</Form.Label>
207 onChange={({ target: { value } }) => {
212 <div className="button-bar">
215 disabled={!chatText || !channel.join}
217 if (chatText) chat(chatText, 'localhorsttv');
221 {t('twitchBot.sendApp')}
225 disabled={!chatText || !channel.chat}
227 if (chatText) chat(chatText, 'horstiebot');
231 {t('twitchBot.sendChat')}
235 <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
236 <div className="button-bar">
237 {CHAT_CATEGORIES.map(category =>
240 onClick={() => { randomChat(category); }}
241 variant="outline-secondary"
243 {t(`twitchBot.chatCategories.${category}`)}
248 <Col className="mt-5" md={6}>
249 <div className="d-flex justify-content-between">
250 <h3>{t('twitchBot.chatSettings')}</h3>
251 <div className="button-bar">
252 <ChatBotLog id={channel.id} />
255 <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
257 <Col className="mt-5" md={12}>
258 <h3>{t('twitchBot.commands')}</h3>
261 onEditCommand={onEditCommand}
262 onRemoveCommand={onRemoveCommand}
267 setShowCommandDialog(false);
269 setEditCommandSettings({});
271 onSubmit={saveCommand}
272 settings={editCommandSettings}
273 show={showCommandDialog}
276 <Button onClick={onAddCommand} variant="primary">
277 {t('twitchBot.addCommand')}
281 <Col className="mt-5" md={12}>
282 <div className="d-flex align-items-end justify-content-between">
283 <h3>{t('twitchBot.guessingGame.settings')}</h3>
284 <div className="button-bar">
285 {channel.access_key ?
287 href={`/guessing-game/monitor/${channel.access_key}`}
289 title={t('button.browserSource')}
290 variant="outline-secondary"
292 <Icon.BROWSER_SOURCE title="" />
298 `/guessing-game/controls/${channel.id}`,
300 'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
303 title={t('twitchBot.guessingGame.popoutControls')}
304 variant="outline-secondary"
306 <Icon.OPEN title="" />
310 <GuessingSettingsForm
312 onSubmit={saveGuessingGame}
313 settings={channel.guessing_settings?.gtbk || {}}
318 <Alert variant="info">
319 {t('twitchBot.selectChannel')}
325 export default Controls;