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 = [
38 const Controls = () => {
39 const [channel, setChannel] = React.useState(null);
40 const [chatText, setChatText] = React.useState('');
41 const [editCommand, setEditCommand] = React.useState('');
42 const [editCommandSettings, setEditCommandSettings] = React.useState({});
43 const [showCommandDialog, setShowCommandDialog] = React.useState(false);
45 const { t } = useTranslation();
47 const chat = React.useCallback(async (text, bot_nick) => {
49 await axios.post(`/api/channels/${channel.id}/chat`, {
53 toastr.success(t('twitchBot.chatSuccess'));
55 toastr.error(t('twitchBot.chatError'));
57 }, [channel, chatText, t]);
59 const randomChat = React.useCallback(async (category) => {
61 await axios.post(`/api/channels/${channel.id}/chat`, {
62 bot_nick: 'horstiebot',
65 toastr.success(t('twitchBot.chatSuccess'));
67 toastr.error(t('twitchBot.chatError'));
69 }, [channel, chatText, t]);
71 const join = React.useCallback(async (bot_nick) => {
73 const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
75 toastr.success(t('twitchBot.joinSuccess'));
77 toastr.error(t('twitchBot.joinError'));
81 const part = React.useCallback(async (bot_nick) => {
83 const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
85 toastr.success(t('twitchBot.partSuccess'));
87 toastr.error(t('twitchBot.partError'));
91 const saveChatSettings = React.useCallback(async (values) => {
93 const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
95 toastr.success(t('twitchBot.saveSuccess'));
97 toastr.error(t('twitchBot.saveError'));
101 const onAddCommand = React.useCallback(() => {
103 setEditCommandSettings({});
104 setShowCommandDialog(true);
107 const onEditCommand = React.useCallback((name, settings) => {
108 setEditCommand(name);
109 setEditCommandSettings(settings);
110 setShowCommandDialog(true);
113 const onRemoveCommand = React.useCallback(async (name) => {
115 const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
116 setChannel(rsp.data);
117 toastr.success(t('twitchBot.saveSuccess'));
119 toastr.error(t('twitchBot.saveError'));
123 const saveCommand = React.useCallback(async (values) => {
125 const rsp = await axios.put(
126 `/api/channels/${channel.id}/commands/${values.name}`,
129 setChannel(rsp.data);
130 setShowCommandDialog(false);
132 setEditCommandSettings({});
133 toastr.success(t('twitchBot.saveSuccess'));
135 toastr.error(t('twitchBot.saveError'));
140 const saveGuessingGame = React.useCallback(async (values) => {
142 const rsp = await axios.put(
143 `/api/channels/${channel.id}/guessing-game/${values.name}`,
146 setChannel(rsp.data);
147 toastr.success(t('twitchBot.saveSuccess'));
149 toastr.error(t('twitchBot.saveError'));
155 <Row className="mb-4">
156 <Form.Group as={Col} md={6}>
157 <Form.Label>{t('twitchBot.channel')}</Form.Label>
163 onChange={({ channel }) => { setChannel(channel); }}
164 value={channel ? channel.id : ''}
168 <Form.Group as={Col} md={3}>
169 <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
173 onChange={({ target: { value } }) => {
175 join('localhorsttv');
177 part('localhorsttv');
184 <Form.Group as={Col} md={3}>
185 <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
189 onChange={({ target: { value } }) => {
204 <Col className="mt-5" md={6}>
205 <h3>{t('twitchBot.chat')}</h3>
207 <Form.Label>{t('twitchBot.chat')}</Form.Label>
210 onChange={({ target: { value } }) => {
215 <div className="button-bar">
218 disabled={!chatText || !channel.join}
220 if (chatText) chat(chatText, 'localhorsttv');
224 {t('twitchBot.sendApp')}
228 disabled={!chatText || !channel.chat}
230 if (chatText) chat(chatText, 'horstiebot');
234 {t('twitchBot.sendChat')}
238 <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
239 <div className="button-bar">
240 {CHAT_CATEGORIES.map(category =>
243 onClick={() => { randomChat(category); }}
244 variant="outline-secondary"
246 {t(`twitchBot.chatCategories.${category}`)}
251 <Col className="mt-5" md={6}>
252 <div className="d-flex justify-content-between">
253 <h3>{t('twitchBot.chatSettings')}</h3>
254 <div className="button-bar">
255 <ChatBotLog id={channel.id} />
258 <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
260 <Col className="mt-5" md={12}>
261 <h3>{t('twitchBot.commands')}</h3>
264 onEditCommand={onEditCommand}
265 onRemoveCommand={onRemoveCommand}
270 setShowCommandDialog(false);
272 setEditCommandSettings({});
274 onSubmit={saveCommand}
275 settings={editCommandSettings}
276 show={showCommandDialog}
279 <Button onClick={onAddCommand} variant="primary">
280 {t('twitchBot.addCommand')}
284 <Col className="mt-5" md={12}>
285 <div className="d-flex align-items-end justify-content-between">
286 <h3>{t('twitchBot.guessingGame.settings')}</h3>
287 <div className="button-bar">
288 {channel.access_key ?
290 href={`/guessing-game/monitor/${channel.access_key}`}
292 title={t('button.browserSource')}
293 variant="outline-secondary"
295 <Icon.BROWSER_SOURCE title="" />
301 `/guessing-game/controls/${channel.id}`,
303 'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
306 title={t('twitchBot.guessingGame.popoutControls')}
307 variant="outline-secondary"
309 <Icon.OPEN title="" />
313 <GuessingSettingsForm
315 onSubmit={saveGuessingGame}
316 settings={channel.guessing_settings?.gtbk || {}}
321 <Alert variant="info">
322 {t('twitchBot.selectChannel')}
328 export default Controls;