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 GuildBox from '../discord-guilds/Box';
9 import debounce from '../../helpers/debounce';
11 const DiscordSelect = ({ onChange, value }) => {
12 const [resolved, setResolved] = useState(null);
13 const [results, setResults] = useState([]);
14 const [search, setSearch] = useState('');
15 const [showResults, setShowResults] = useState(false);
17 const ref = useRef(null);
18 const { t } = useTranslation();
21 const handleEventOutside = e => {
22 if (ref.current && !ref.current.contains(e.target)) {
23 setShowResults(false);
26 document.addEventListener('click', handleEventOutside, true);
27 document.addEventListener('focus', handleEventOutside, true);
29 document.removeEventListener('click', handleEventOutside, true);
30 document.removeEventListener('focus', handleEventOutside, true);
35 const fetch = useCallback(debounce(async phrase => {
39 ctrl = new AbortController();
41 const response = await axios.get(`/api/discord-guilds`, {
48 setResults(response.data);
62 .get(`/api/discord-guilds/${value}`)
64 setResolved(response.data);
72 return <div className="d-flex align-items-center justify-content-between">
73 <span>{resolved ? <GuildBox guild={resolved} /> : value}</span>
76 onClick={() => onChange({ guild: null, target: { value: '' }})}
77 title={t('button.unset')}
78 variant="outline-danger"
80 <Icon.REMOVE title="" />
84 return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
86 className="search-input"
87 name={Math.random().toString(20).substr(2, 10)}
88 onChange={e => setSearch(e.target.value)}
89 onFocus={() => setShowResults(true)}
93 <div className="search-results-holder">
95 <ListGroup className="search-results">
96 {results.map(result =>
100 onClick={() => onChange({
102 target: { value: result.guild_id },
105 <GuildBox guild={result} />
110 <Alert className="search-results" variant="info">
111 {t('search.noResults')}
118 DiscordSelect.propTypes = {
119 onChange: PropTypes.func,
120 value: PropTypes.string,
123 export default DiscordSelect;