public function search(Request $request) {
$validatedData = $request->validate([
+ 'id' => 'array',
+ 'id.*' => 'integer|numeric',
'joinable' => 'boolean|nullable',
'manageable' => 'boolean|nullable',
'phrase' => 'string|nullable',
]);
$channels = Channel::query();
+ if (!empty($validatedData['id'])) {
+ $channels = $channels->whereIn('id', $validatedData['id']);
+ }
if (isset($validatedData['joinable']) && $validatedData['joinable']) {
$channels = $channels->where('twitch_chat', '!=', '');
}
/>
<Route path="guessing-game">
<Route
- path="controls"
+ path="controls/:channelId?"
lazy={() => import(
/* webpackChunkName: "guessing" */
'../pages/GuessingGameControls'
import Icon from './Icon';
import debounce from '../../helpers/debounce';
-const ChannelSelect = ({ autoSelect, joinable, manageable, onChange, value }) => {
+const ChannelSelect = ({
+ autoSelect,
+ joinable,
+ manageable,
+ onChange,
+ readOnly,
+ value,
+}) => {
const [resolved, setResolved] = useState(null);
const [results, setResults] = useState([]);
const [search, setSearch] = useState('');
if (value) {
return <div className="d-flex align-items-center justify-content-between">
<span>{resolved ? resolved.title : value}</span>
- <Button
- className="ms-2"
- onClick={() => onChange({ channel: null, target: { value: '' }})}
- title={t('button.unset')}
- variant="outline-danger"
- >
- <Icon.REMOVE title="" />
- </Button>
+ {!readOnly ?
+ <Button
+ className="ms-2"
+ onClick={() => onChange({ channel: null, target: { value: '' }})}
+ title={t('button.unset')}
+ variant="outline-danger"
+ >
+ <Icon.REMOVE title="" />
+ </Button>
+ : null}
</div>;
}
return <div className={`channel-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
name={Math.random().toString(20).substr(2, 10)}
onChange={e => setSearch(e.target.value)}
onFocus={() => setShowResults(true)}
+ readOnly={readOnly}
type="search"
value={search}
/>
joinable: PropTypes.bool,
manageable: PropTypes.bool,
onChange: PropTypes.func,
+ readOnly: PropTypes.bool,
value: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
<div className="button-bar">
{channel.access_key ?
<Button
- onClick={() => {
- window.open(
- `/guessing-game/monitor/${channel.access_key}`,
- );
- }}
+ href={`/guessing-game/monitor/${channel.access_key}`}
+ target="_blank"
title={t('button.browserSource')}
variant="outline-secondary"
>
<Button
onClick={() => {
window.open(
- '/guessing-game/controls',
+ `/guessing-game/controls/${channel.id}`,
'',
'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
);
import { Alert, Col, Container, Form, Navbar, Row } from 'react-bootstrap';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router-dom';
import toastr from 'toastr';
import User from '../app/User';
const [guesses, setGuesses] = React.useState([]);
const [winners, setWinners] = React.useState([]);
+ const { channelId } = useParams();
const { t } = useTranslation();
+ React.useEffect(() => {
+ if (!channelId) return;
+ const fetchChannel = async () => {
+ const response = await axios.get(`/api/channels`, {
+ params: {
+ id: [channelId],
+ manageable: 1,
+ },
+ });
+ if (response.data.length) {
+ setChannel(response.data[0]);
+ }
+ };
+ fetchChannel();
+ }, [channelId]);
+
React.useEffect(() => {
if (!channel) {
setGuesses([]);
joinable
manageable
onChange={({ channel }) => { setChannel(channel); }}
- value={channel ? channel.id : ''}
+ readOnly={!!(channelId && channel)}
+ value={channel ? channel.id : channelId}
/>
<User />
</Container>