/
SourceSearchAutocomplete.jsx
133 lines (128 loc) · 4.89 KB
/
SourceSearchAutocomplete.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import React from 'react';
import {
List as SourceIcon, LocalOfferOutlined as ConceptIcon,
Person as UserIcon, AccountBalance as OrgIcon,
} from '@mui/icons-material';
import { TextField, CircularProgress, ListItem, ListItemIcon, ListItemText, Divider, Typography } from '@mui/material';
import Autocomplete from '@mui/material/Autocomplete';
import { get, debounce, orderBy, isEmpty } from 'lodash'
import APIService from '../../services/APIService';
import { GREEN } from '../../common/constants';
const SourceSearchAutocomplete = ({onChange, label, id, required, minCharactersForSearch, size}) => {
const minLength = minCharactersForSearch || 2;
const [input, setInput] = React.useState('')
const [open, setOpen] = React.useState(false)
const [fetched, setFetched] = React.useState(false)
const [sources, setSources] = React.useState([])
const [selected, setSelected] = React.useState(undefined)
const isSearchable = input && input.length >= minLength;
const loading = Boolean(open && !fetched && isSearchable && isEmpty(sources))
const handleInputChange = debounce((event, value, reason) => {
setInput(value || '')
setFetched(false)
if(reason !== 'reset' && value && value.length >= minLength)
fetchSources(value)
}, 300)
const handleChange = (event, id, item) => {
event.preventDefault()
event.stopPropagation()
setSelected(item)
onChange(id, item)
}
const fetchSources = searchStr => {
const query = {limit: 25, q: searchStr, includeSummary: true}
APIService.sources().get(null, null, query).then(response => {
const sources = orderBy(response.data, ['name'])
setSources(sources)
setFetched(true)
})
}
return (
<Autocomplete
filterOptions={x => x}
openOnFocus
blurOnSelect
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
isOptionEqualToValue={(option, value) => option.url === get(value, 'url')}
value={selected}
id={id || 'source'}
size={size || 'medium'}
options={sources}
loading={loading}
loadingText={loading ? 'Loading...' : `Type atleast ${minLength} characters to search`}
noOptionsText={(isSearchable && !loading) ? "No results" : 'Start typing...'}
getOptionLabel={option => option ? option.name : ''}
fullWidth
required={required}
onInputChange={handleInputChange}
onChange={(event, item) => handleChange(event, id || 'source', item)}
renderInput={
params => (
<TextField
{...params}
value={input}
required
label={label || "Source"}
variant="outlined"
fullWidth
size={size || 'medium'}
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)
}
renderOption={
(props, option) => (
<React.Fragment key={option.url}>
<ListItem
{...props}
secondaryAction={
<span className='flex-vertical-center'>
{
option.owner_type === 'User' ?
<UserIcon style={{marginRight: '4px', color: 'rgba(0, 0, 0, 0.26)', fontSize: '13px' }}/> :
<OrgIcon style={{marginRight: '4px', color: 'rgba(0, 0, 0, 0.26)', fontSize: '13px'}} />
}
<span className='flex-vertical-center' style={{maxWidth: '70px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: 'rgba(0, 0, 0, 0.26)', fontSize: '13px'}}>
{option.owner}
</span>
</span>
}>
<ListItemIcon>
<SourceIcon style={{color: GREEN}} fontSize='large' />
</ListItemIcon>
<ListItemText
primary={
<Typography
sx={{ maxWidth: 'calc(100% - 90px)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
{option.name}
</Typography>
}
secondary={
<Typography
sx={{ display: 'inline', color: 'rgba(0, 0, 0, 0.6)' }}
component="span"
className='flex-vertical-center'>
<ConceptIcon size='small' style={{marginRight: '4px', fontSize: '1rem'}} />
{option.summary.active_concepts}
</Typography>
}
/>
</ListItem>
<Divider variant="inset" component="li" />
</React.Fragment>
)
}
/>
);
}
export default SourceSearchAutocomplete;