]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/twitch-bot/Controls.js
chat bot protocol ui
[alttp.git] / resources / js / components / twitch-bot / Controls.js
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';
6
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';
15
16 const CHAT_CATEGORIES = ['unclassified', 'hi', 'gl', 'gg', 'lol', 'pog', 'hype', 'o7'];
17
18 const Controls = () => {
19         const [channel, setChannel] = React.useState(null);
20         const [chatText, setChatText] = React.useState('');
21         const [editCommand, setEditCommand] = React.useState('');
22         const [editCommandSettings, setEditCommandSettings] = React.useState({});
23         const [showCommandDialog, setShowCommandDialog] = React.useState(false);
24
25         const { t } = useTranslation();
26
27         const chat = React.useCallback(async (text, bot_nick) => {
28                 try {
29                         await axios.post(`/api/channels/${channel.id}/chat`, {
30                                 text,
31                                 bot_nick,
32                         });
33                         toastr.success(t('twitchBot.chatSuccess'));
34                 } catch (e) {
35                         toastr.error(t('twitchBot.chatError'));
36                 }
37         }, [channel, chatText, t]);
38
39         const randomChat = React.useCallback(async (category) => {
40                 try {
41                         await axios.post(`/api/channels/${channel.id}/chat`, {
42                                 bot_nick: 'horstiebot',
43                                 category,
44                         });
45                         toastr.success(t('twitchBot.chatSuccess'));
46                 } catch (e) {
47                         toastr.error(t('twitchBot.chatError'));
48                 }
49         }, [channel, chatText, t]);
50
51         const join = React.useCallback(async (bot_nick) => {
52                 try {
53                         const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
54                         setChannel(rsp.data);
55                         toastr.success(t('twitchBot.joinSuccess'));
56                 } catch (e) {
57                         toastr.error(t('twitchBot.joinError'));
58                 }
59         }, [channel, t]);
60
61         const part = React.useCallback(async (bot_nick) => {
62                 try {
63                         const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
64                         setChannel(rsp.data);
65                         toastr.success(t('twitchBot.partSuccess'));
66                 } catch (e) {
67                         toastr.error(t('twitchBot.partError'));
68                 }
69         }, [channel, t]);
70
71         const saveChatSettings = React.useCallback(async (values) => {
72                 try {
73                         const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
74                         setChannel(rsp.data);
75                         toastr.success(t('twitchBot.saveSuccess'));
76                 } catch (e) {
77                         toastr.error(t('twitchBot.saveError'));
78                 }
79         }, [channel, t]);
80
81         const onAddCommand = React.useCallback(() => {
82                 setEditCommand('');
83                 setEditCommandSettings({});
84                 setShowCommandDialog(true);
85         }, [channel]);
86
87         const onEditCommand = React.useCallback((name, settings) => {
88                 setEditCommand(name);
89                 setEditCommandSettings(settings);
90                 setShowCommandDialog(true);
91         }, [channel]);
92
93         const onRemoveCommand = React.useCallback(async (name) => {
94                 try {
95                         const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
96                         setChannel(rsp.data);
97                         toastr.success(t('twitchBot.saveSuccess'));
98                 } catch (e) {
99                         toastr.error(t('twitchBot.saveError'));
100                 }
101         }, [channel]);
102
103         const saveCommand = React.useCallback(async (values) => {
104                 try {
105                         const rsp = await axios.put(
106                                 `/api/channels/${channel.id}/commands/${values.name}`,
107                                 values,
108                         );
109                         setChannel(rsp.data);
110                         setShowCommandDialog(false);
111                         setEditCommand('');
112                         setEditCommandSettings({});
113                         toastr.success(t('twitchBot.saveSuccess'));
114                 } catch (e) {
115                         toastr.error(t('twitchBot.saveError'));
116                         throw e;
117                 }
118         }, [channel]);
119
120         const saveGuessingGame = React.useCallback(async (values) => {
121                 try {
122                         const rsp = await axios.put(
123                                 `/api/channels/${channel.id}/guessing-game/${values.name}`,
124                                 values,
125                         );
126                         setChannel(rsp.data);
127                         toastr.success(t('twitchBot.saveSuccess'));
128                 } catch (e) {
129                         toastr.error(t('twitchBot.saveError'));
130                         throw e;
131                 }
132         }, [channel]);
133
134         return <>
135                 <Row className="mb-4">
136                         <Form.Group as={Col} md={6}>
137                                 <Form.Label>{t('twitchBot.channel')}</Form.Label>
138                                 <Form.Control
139                                         as={ChannelSelect}
140                                         autoSelect
141                                         joinable
142                                         manageable
143                                         onChange={({ channel }) => { setChannel(channel); }}
144                                         value={channel ? channel.id : ''}
145                                 />
146                         </Form.Group>
147                         {channel ? <>
148                                 <Form.Group as={Col} md={3}>
149                                         <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
150                                         <div>
151                                                 <Form.Control
152                                                         as={ToggleSwitch}
153                                                         onChange={({ target: { value } }) => {
154                                                                 if (value) {
155                                                                         join('localhorsttv');
156                                                                 } else {
157                                                                         part('localhorsttv');
158                                                                 }
159                                                         }}
160                                                         value={channel.join}
161                                                 />
162                                         </div>
163                                 </Form.Group>
164                                 <Form.Group as={Col} md={3}>
165                                         <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
166                                         <div>
167                                                 <Form.Control
168                                                         as={ToggleSwitch}
169                                                         onChange={({ target: { value } }) => {
170                                                                 if (value) {
171                                                                         join('horstiebot');
172                                                                 } else {
173                                                                         part('horstiebot');
174                                                                 }
175                                                         }}
176                                                         value={channel.chat}
177                                                 />
178                                         </div>
179                                 </Form.Group>
180                         </> : null}
181                 </Row>
182                 {channel ?
183                         <Row>
184                                 <Col className="mt-5" md={6}>
185                                         <h3>{t('twitchBot.chat')}</h3>
186                                         <Form.Group>
187                                                 <Form.Label>{t('twitchBot.chat')}</Form.Label>
188                                                 <Form.Control
189                                                         as="textarea"
190                                                         onChange={({ target: { value } }) => {
191                                                                 setChatText(value);
192                                                         }}
193                                                         value={chatText}
194                                                 />
195                                                 <div className="button-bar">
196                                                         <Button
197                                                                 className="mt-2"
198                                                                 disabled={!chatText || !channel.join}
199                                                                 onClick={() => {
200                                                                         if (chatText) chat(chatText, 'localhorsttv');
201                                                                 }}
202                                                                 variant="twitch"
203                                                         >
204                                                                 {t('twitchBot.sendApp')}
205                                                         </Button>
206                                                         <Button
207                                                                 className="mt-2"
208                                                                 disabled={!chatText || !channel.chat}
209                                                                 onClick={() => {
210                                                                         if (chatText) chat(chatText, 'horstiebot');
211                                                                 }}
212                                                                 variant="twitch"
213                                                         >
214                                                                 {t('twitchBot.sendChat')}
215                                                         </Button>
216                                                 </div>
217                                         </Form.Group>
218                                         <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
219                                         <div className="button-bar">
220                                                 {CHAT_CATEGORIES.map(category =>
221                                                         <Button
222                                                                 key={category}
223                                                                 onClick={() => { randomChat(category); }}
224                                                                 variant="outline-secondary"
225                                                         >
226                                                                 {t(`twitchBot.chatCategories.${category}`)}
227                                                         </Button>
228                                                 )}
229                                         </div>
230                                 </Col>
231                                 <Col className="mt-5" md={6}>
232                                         <div className="d-flex justify-content-between">
233                                                 <h3>{t('twitchBot.chatSettings')}</h3>
234                                                 <div className="button-bar">
235                                                         <ChatBotLog id={channel.id} />
236                                                 </div>
237                                         </div>
238                                         <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
239                                 </Col>
240                                 <Col className="mt-5" md={12}>
241                                         <h3>{t('twitchBot.commands')}</h3>
242                                         <Commands
243                                                 channel={channel}
244                                                 onEditCommand={onEditCommand}
245                                                 onRemoveCommand={onRemoveCommand}
246                                         />
247                                         <CommandDialog
248                                                 name={editCommand}
249                                                 onHide={() => {
250                                                         setShowCommandDialog(false);
251                                                         setEditCommand('');
252                                                         setEditCommandSettings({});
253                                                 }}
254                                                 onSubmit={saveCommand}
255                                                 settings={editCommandSettings}
256                                                 show={showCommandDialog}
257                                         />
258                                         <div>
259                                                 <Button onClick={onAddCommand} variant="primary">
260                                                         {t('twitchBot.addCommand')}
261                                                 </Button>
262                                         </div>
263                                 </Col>
264                                 <Col className="mt-5" md={12}>
265                                         <div className="d-flex align-items-end justify-content-between">
266                                                 <h3>{t('twitchBot.guessingGame.settings')}</h3>
267                                                 <div className="button-bar">
268                                                         {channel.access_key ?
269                                                                 <Button
270                                                                         href={`/guessing-game/monitor/${channel.access_key}`}
271                                                                         target="_blank"
272                                                                         title={t('button.browserSource')}
273                                                                         variant="outline-secondary"
274                                                                 >
275                                                                         <Icon.BROWSER_SOURCE title="" />
276                                                                 </Button>
277                                                         : null}
278                                                         <Button
279                                                                 onClick={() => {
280                                                                         window.open(
281                                                                                 `/guessing-game/controls/${channel.id}`,
282                                                                                 '',
283                                                                                 'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
284                                                                         );
285                                                                 }}
286                                                                 title={t('twitchBot.guessingGame.popoutControls')}
287                                                                 variant="outline-secondary"
288                                                         >
289                                                                 <Icon.OPEN title="" />
290                                                         </Button>
291                                                 </div>
292                                         </div>
293                                         <GuessingSettingsForm
294                                                 name="gtbk"
295                                                 onSubmit={saveGuessingGame}
296                                                 settings={channel.guessing_settings?.gtbk || {}}
297                                         />
298                                 </Col>
299                         </Row>
300                 :
301                         <Alert variant="info">
302                                 {t('twitchBot.selectChannel')}
303                         </Alert>
304                 }
305         </>;
306 };
307
308 export default Controls;