import React, { useState, useMemo, useCallback, useRef } from 'react'; import { useDebounce } from 'use-debounce'; import { useQuery } from 'react-query'; import PropTypes from 'prop-types'; import { Combobox, ComboboxInput, ComboboxPopover, ComboboxList, ComboboxOption } from '@reach/combobox'; import '@reach/combobox/styles.css'; import { fire } from '@utils'; import { useDeferredSubmit } from './shared/hooks'; function defaultTransformResults(_, results) { return results; } function ComboSearch({ placeholder, required, hiddenFieldId, onChange, scope, minimumInputLength, transformResult, allowInputValues = false, transformResults = defaultTransformResults, className }) { const label = scope; const hiddenValueField = useMemo( () => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`), [hiddenFieldId] ); const hiddenIdField = useMemo( () => document.querySelector( `input[data-uuid="${hiddenFieldId}"] + input[data-reference]` ), [hiddenFieldId] ); const initialValue = hiddenValueField && hiddenValueField.value; const [searchTerm, setSearchTerm] = useState(''); const [debouncedSearchTerm] = useDebounce(searchTerm, 300); const [value, setValue] = useState(initialValue); const resultsMap = useRef({}); const setExternalValue = useCallback( (value) => { if (hiddenValueField) { hiddenValueField.setAttribute('value', value); fire(hiddenValueField, 'autosave:trigger'); } }, [hiddenValueField] ); const setExternalId = useCallback( (key) => { if (hiddenIdField) { hiddenIdField.setAttribute('value', key); } }, [hiddenIdField] ); const setExternalValueAndId = useCallback((value) => { const [key, result] = resultsMap.current[value]; setExternalId(key); setExternalValue(value); if (onChange) { onChange(value, result); } }, []); const awaitFormSubmit = useDeferredSubmit(hiddenValueField); const handleOnChange = useCallback( ({ target: { value } }) => { setValue(value); if (value.length >= minimumInputLength) { setSearchTerm(value.trim()); if (allowInputValues) { setExternalId(''); setExternalValue(value); } } else if (!value) { setExternalId(''); setExternalValue(''); } }, [minimumInputLength] ); const handleOnSelect = useCallback((value) => { setExternalValueAndId(value); setValue(value); setSearchTerm(''); awaitFormSubmit.done(); }, []); const { isSuccess, data } = useQuery([scope, debouncedSearchTerm], { enabled: !!debouncedSearchTerm, notifyOnStatusChange: false, refetchOnMount: false }); const results = isSuccess ? transformResults(debouncedSearchTerm, data) : []; const onBlur = useCallback(() => { if (!allowInputValues && isSuccess && results[0]) { const [, value] = transformResult(results[0]); awaitFormSubmit(() => { handleOnSelect(value); }); } }, [data]); return ( {isSuccess && ( {results.length > 0 ? ( {results.map((result, index) => { const [key, str] = transformResult(result); resultsMap.current[str] = [key, result]; return ( ); })} ) : ( Aucun résultat trouvé )} )} ); } ComboSearch.propTypes = { placeholder: PropTypes.string, required: PropTypes.bool, hiddenFieldId: PropTypes.string, scope: PropTypes.string, minimumInputLength: PropTypes.number, transformResult: PropTypes.func, transformResults: PropTypes.func, allowInputValues: PropTypes.bool, onChange: PropTypes.func, className: PropTypes.string }; export default ComboSearch;