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 = ({ autoSelect, 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);
50 if (autoSelect && !phrase && response.data.length === 1) {
52 channel: response.data[0],
53 target: { value: response.data[0].id },
60 }, 300), [autoSelect, joinable, manageable]);
69 .get(`/api/channels/${value}`)
71 setResolved(response.data);
79 return <div className="d-flex align-items-center justify-content-between">
80 <span>{resolved ? resolved.title : value}</span>
83 onClick={() => onChange({ channel: null, target: { value: '' }})}
84 title={t('button.unset')}
85 variant="outline-danger"
87 <Icon.REMOVE title="" />
91 return <div className={`channel-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
93 className="search-input"
94 name={Math.random().toString(20).substr(2, 10)}
95 onChange={e => setSearch(e.target.value)}
96 onFocus={() => setShowResults(true)}
100 <div className="search-results-holder">
102 <ListGroup className="search-results">
103 {results.map(result =>
107 onClick={() => onChange({
109 target: { value: result.id },
117 <Alert className="search-results" variant="info">
118 {t('search.noResults')}
125 ChannelSelect.propTypes = {
126 autoSelect: PropTypes.bool,
127 joinable: PropTypes.bool,
128 manageable: PropTypes.bool,
129 onChange: PropTypes.func,
130 value: PropTypes.oneOfType([
136 export default ChannelSelect;