mon-entreprise/source/components/SearchBar.js

123 lines
2.8 KiB
JavaScript

import { SitePathsContext } from 'Components/utils/withSitePaths'
import { encodeRuleName, parentName } from 'Engine/rules.js'
import { pick, sortBy, take } from 'ramda'
import React, { useContext, useEffect, useState } from 'react'
import Highlighter from 'react-highlight-words'
import { useTranslation } from 'react-i18next'
import { Link, Redirect } from 'react-router-dom'
import Worker from 'worker-loader!./SearchBar.worker.js'
import { capitalise0 } from '../utils'
const worker = new Worker()
export default function SearchBar({
rules,
showDefaultList,
finally: finallyCallback
}) {
const sitePaths = useContext(SitePathsContext)
const [input, setInput] = useState('')
const [selectedOption, setSelectedOption] = useState(null)
const [results, setResults] = useState([])
const { i18n } = useTranslation()
useEffect(() => {
worker.postMessage({
rules: rules.map(
pick(['title', 'espace', 'description', 'name', 'dottedName'])
)
})
worker.onmessage = ({ data: results }) => setResults(results)
}, [rules])
let renderOptions = rules => {
let options =
(rules && sortBy(rule => rule.dottedName, rules)) || take(5)(results)
return <ul>{options.map(option => renderOption(option))}</ul>
}
let renderOption = option => {
let { title, dottedName, name } = option
return (
<li
key={dottedName}
css={`
padding: 0.4rem;
border-radius: 0.3rem;
:hover {
background: var(--colour);
color: var(--textColour);
}
:hover a {
color: var(--textColour);
}
`}
onClick={() => setSelectedOption(option)}
>
<div
style={{
fontWeight: '300',
fontSize: '85%',
lineHeight: '.9em'
}}
>
<Highlighter
searchWords={[input]}
textToHighlight={
parentName(dottedName)
? parentName(dottedName)
.split(' . ')
.map(capitalise0)
.join(' - ')
: ''
}
/>
</div>
<Link
to={sitePaths.documentation.index + '/' + encodeRuleName(dottedName)}
>
<Highlighter
searchWords={[input]}
textToHighlight={title || capitalise0(name)}
/>
</Link>
</li>
)
}
if (selectedOption != null) {
finallyCallback && finallyCallback()
return (
<Redirect
to={
sitePaths.documentation.index +
'/' +
encodeRuleName(selectedOption.dottedName)
}
/>
)
}
return (
<>
<input
type="text"
value={input}
placeholder={i18n.t('Entrez des mots clefs ici')}
onChange={e => {
let input = e.target.value
setInput(input)
if (input.length > 2) worker.postMessage({ input })
}}
/>
{input.length > 2 &&
!results.length &&
i18n.t('noresults', {
defaultValue: "Nous n'avons rien trouvé…"
})}
{showDefaultList && !input ? renderOptions(rules) : renderOptions()}
</>
)
}