import { PlusIcon } from '@radix-ui/react-icons';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { useModule } from '../../lib/react-utils';
import { modules } from '../../store/api/reducer';
import {
accessLevels,
AccessLevelType,
TwitchBotCustomCommand,
} from '../../store/api/types';
import AlertContent from '../components/AlertContent';
import DialogContent from '../components/DialogContent';
import {
Button,
ComboBox,
Dialog,
DialogActions,
DialogClose,
Field,
FieldNote,
FlexRow,
InputBox,
Label,
MultiButton,
PageContainer,
PageHeader,
PageTitle,
styled,
Textarea,
TextBlock,
} from '../theme';
import { Alert, AlertTrigger } from '../theme/alert';
const CommandList = styled('div', { marginTop: '1rem' });
const CommandItemContainer = styled('article', {
backgroundColor: '$gray2',
margin: '0.5rem 0',
padding: '0.5rem',
borderLeft: '5px solid $teal8',
borderRadius: '0.25rem',
borderBottom: '1px solid $gray4',
transition: 'all 50ms',
'&:hover': {
backgroundColor: '$gray3',
},
variants: {
status: {
enabled: {},
disabled: {
borderLeftColor: '$red7',
backgroundColor: '$gray3',
color: '$gray10',
},
},
},
});
const CommandHeader = styled('header', {
display: 'flex',
gap: '0.5rem',
alignItems: 'center',
marginBottom: '0.4rem',
});
const CommandName = styled('span', {
color: '$teal10',
fontWeight: 'bold',
variants: {
status: {
enabled: {},
disabled: {
color: '$gray10',
},
},
},
});
const CommandDescription = styled('span', {
flex: 1,
});
const CommandActions = styled('div', {
display: 'flex',
alignItems: 'center',
gap: '0.25rem',
});
const CommandText = styled('div', {
fontFamily: 'Space Mono',
fontSize: '10pt',
margin: '-0.5rem',
marginTop: '0',
padding: '0.5rem',
backgroundColor: '$gray4',
lineHeight: '1.2rem',
});
const ACLIndicator = styled('span', {
fontFamily: 'Space Mono',
fontSize: '10pt',
marginRight: '0.5rem',
});
interface CommandItemProps {
name: string;
item: TwitchBotCustomCommand;
onToggle?: () => void;
onEdit?: () => void;
onDelete?: () => void;
}
function CommandItem({
name,
item,
onToggle,
onEdit,
onDelete,
}: CommandItemProps): React.ReactElement {
const { t } = useTranslation();
return (
{name}
{item.description}
{item.access_level !== 'everyone' && (
{t(`pages.botcommands.acl.${item.access_level}`)}
{item.access_level !== 'streamer' && '+'}
)}
(onDelete ? onDelete() : null)}
/>
{item.response}
);
}
type DialogPrompt =
| { kind: 'new' }
| { kind: 'edit'; name: string; item: TwitchBotCustomCommand };
function CommandDialog({
kind,
name,
item,
onSubmit,
}: {
kind: 'new' | 'edit';
name?: string;
item?: TwitchBotCustomCommand;
onSubmit?: (name: string, item: TwitchBotCustomCommand) => void;
}) {
const [commandName, setCommandName] = useState(name ?? '');
const [description, setDescription] = useState(item?.description ?? '');
const [response, setResponse] = useState(item?.response ?? '');
const [accessLevel, setAccessLevel] = useState(
item?.access_level ?? 'everyone',
);
const { t } = useTranslation();
return (
);
}
export default function TwitchBotCommandsPage(): React.ReactElement {
const [commands, setCommands] = useModule(modules.twitchBotCommands);
const [filter, setFilter] = useState('');
const [activeDialog, setActiveDialog] = useState(null);
const { t } = useTranslation();
const dispatch = useDispatch();
const filterLC = filter.toLowerCase();
const setCommand = (newName: string, data: TwitchBotCustomCommand): void => {
switch (activeDialog.kind) {
case 'new':
dispatch(
setCommands({
...commands,
[newName]: {
...data,
enabled: true,
},
}),
);
break;
case 'edit': {
const oldName = activeDialog.name;
dispatch(
setCommands({
...commands,
[oldName]: undefined,
[newName]: data,
}),
);
break;
}
}
setActiveDialog(null);
};
const deleteCommand = (cmd: string): void => {
dispatch(
setCommands({
...commands,
[cmd]: undefined,
}),
);
};
const toggleCommand = (cmd: string): void => {
dispatch(
setCommands({
...commands,
[cmd]: {
...commands[cmd],
enabled: !commands[cmd].enabled,
},
}),
);
};
return (
{t('pages.botcommands.title')}
{t('pages.botcommands.desc')}
setFilter(e.target.value)}
/>
{Object.keys(commands ?? {})
?.filter((cmd) => cmd.toLowerCase().includes(filterLC))
.sort()
.map((cmd) => (
toggleCommand(cmd)}
onEdit={() =>
setActiveDialog({
kind: 'edit',
name: cmd,
item: commands[cmd],
})
}
onDelete={() => deleteCommand(cmd)}
/>
))}
);
}