]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/common/DiscordSelect.js
tournament/guild connection
[alttp.git] / resources / js / components / common / DiscordSelect.js
1 import axios from 'axios';
2 import PropTypes from 'prop-types';
3 import React, { useCallback, useEffect, useRef, useState } from 'react';
4 import { Form, ListGroup } from 'react-bootstrap';
5
6 import GuildBox from '../discord-guilds/Box';
7 import debounce from '../../helpers/debounce';
8
9 const DiscordSelect = ({ onChange, value }) => {
10         const [resolved, setResolved] = useState(null);
11         const [results, setResults] = useState([]);
12         const [search, setSearch] = useState('');
13         const [showResults, setShowResults] = useState(false);
14
15         const ref = useRef(null);
16
17         useEffect(() => {
18                 const handleEventOutside = e => {
19                         if (ref.current && !ref.current.contains(e.target)) {
20                                 setShowResults(false);
21                         }
22                 };
23                 document.addEventListener('click', handleEventOutside, true);
24                 document.addEventListener('focus', handleEventOutside, true);
25                 return () => {
26                         document.removeEventListener('click', handleEventOutside, true);
27                         document.removeEventListener('focus', handleEventOutside, true);
28                 };
29         }, []);
30
31         let ctrl = null;
32         const fetch = useCallback(debounce(async phrase => {
33                 if (ctrl) {
34                         ctrl.abort();
35                 }
36                 ctrl = new AbortController();
37                 try {
38                         const response = await axios.get(`/api/discord-guilds`, {
39                                 params: {
40                                         phrase,
41                                 },
42                                 signal: ctrl.signal,
43                         });
44                         ctrl = null;
45                         setResults(response.data);
46                 } catch (e) {
47                         ctrl = null;
48                         console.error(e);
49                 }
50         }, 300), []);
51
52         useEffect(() => {
53                 fetch(search);
54         }, [search]);
55
56         useEffect(() => {
57                 if (value) {
58                         axios
59                                 .get(`/api/discord-guilds/${value}`)
60                         .then(response => {
61                                 setResolved(response.data);
62                         });
63                 } else {
64                         setResolved(null);
65                 }
66         }, [value]);
67
68         if (value) {
69                 return <div>{resolved ? <GuildBox guild={resolved} /> : value}</div>;
70         }
71         return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
72                 <Form.Control
73                         className="search-input"
74                         name={Math.random().toString(20).substr(2, 10)}
75                         onChange={e => setSearch(e.target.value)}
76                         onFocus={() => setShowResults(true)}
77                         type="search"
78                         value={search}
79                 />
80                 <div className="search-results-holder">
81                         <ListGroup className="search-results">
82                                 {results.map(result =>
83                                         <ListGroup.Item
84                                                 action
85                                                 key={result.id}
86                                                 onClick={() => onChange({ target: { value: result.guild_id }})}
87                                         >
88                                                 <GuildBox guild={result} />
89                                         </ListGroup.Item>
90                                 )}
91                         </ListGroup>
92                 </div>
93         </div>;
94 };
95
96 DiscordSelect.propTypes = {
97         onChange: PropTypes.func,
98         value: PropTypes.string,
99 };
100
101 export default DiscordSelect;