1 import axios from 'axios';
2 import PropTypes from 'prop-types';
3 import React, { useCallback, useEffect, useRef, useState } from 'react';
4 import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
5 import { useTranslation } from 'react-i18next';
7 import Icon from './Icon';
8 import debounce from '../../helpers/debounce';
10 const ChannelSelect = ({ joinable, manageable, onChange, value }) => {
11 const [resolved, setResolved] = useState(null);
12 const [results, setResults] = useState([]);
13 const [search, setSearch] = useState('');
14 const [showResults, setShowResults] = useState(false);
16 const ref = useRef(null);
17 const { t } = useTranslation();
20 const handleEventOutside = e => {
21 if (ref.current && !ref.current.contains(e.target)) {
22 setShowResults(false);
25 document.addEventListener('click', handleEventOutside, true);
26 document.addEventListener('focus', handleEventOutside, true);
28 document.removeEventListener('click', handleEventOutside, true);
29 document.removeEventListener('focus', handleEventOutside, true);
34 const fetch = useCallback(debounce(async phrase => {
38 ctrl = new AbortController();
40 const response = await axios.get(`/api/channels`, {
42 joinable: joinable ? 1 : 0,
43 manageable: manageable ? 1 : 0,
49 setResults(response.data);
54 }, 300), [manageable]);
63 .get(`/api/channels/${value}`)
65 setResolved(response.data);
73 return <div className="d-flex align-items-center justify-content-between">
74 <span>{resolved ? resolved.title : value}</span>
77 onClick={() => onChange({ channel: null, target: { value: '' }})}
78 title={t('button.unset')}
79 variant="outline-danger"
81 <Icon.REMOVE title="" />
85 return <div className={`channel-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
87 className="search-input"
88 name={Math.random().toString(20).substr(2, 10)}
89 onChange={e => setSearch(e.target.value)}
90 onFocus={() => setShowResults(true)}
94 <div className="search-results-holder">
96 <ListGroup className="search-results">
97 {results.map(result =>
101 onClick={() => onChange({
103 target: { value: result.id },
111 <Alert className="search-results" variant="info">
112 {t('search.noResults')}
119 ChannelSelect.propTypes = {
120 joinable: PropTypes.bool,
121 manageable: PropTypes.bool,
122 onChange: PropTypes.func,
123 value: PropTypes.oneOfType([
129 export default ChannelSelect;