import React, { useEffect, useId, useRef, useState } from 'react'; import { AsyncPaginate } from 'react-select-async-paginate'; import axios from 'axios'; const areStringArraysEqual = (left = [], right = []) => left.length === right.length && left.every((value, index) => value === right[index]); const areSelectOptionsEqual = (left = [], right = []) => left.length === right.length && left.every( (option, index) => option?.value === right[index]?.value && option?.label === right[index]?.label, ); export const SelectFieldMany = ({ options, field, form, itemRef, showField, }) => { const [value, setValue] = useState([]); const appliedOptionsSignatureRef = useRef(null); const PAGE_SIZE = 50; useEffect(() => { if (field.value?.[0] && typeof field.value[0] !== 'string') { const normalizedValue = field.value.map((el) => el.id); const isAlreadyNormalized = Array.isArray(field.value) && areStringArraysEqual(field.value, normalizedValue); if (!isAlreadyNormalized) { form.setFieldValue(field.name, normalizedValue, false); } } else if (!field.value || field.value.length === 0) { setValue((currentValue) => currentValue.length === 0 ? currentValue : [], ); } }, [field.name, field.value, form]); useEffect(() => { if (Array.isArray(options) && options.length > 0) { const selectedOptions = options.map((el) => ({ value: el.id, label: el[showField], })); const selectedIds = options.map((el) => el.id); const optionsSignature = selectedIds.join('|'); const shouldApplyInitialOptions = appliedOptionsSignatureRef.current !== optionsSignature; const fieldValueMatchesInitialOptions = areStringArraysEqual( field.value, selectedIds, ); if (shouldApplyInitialOptions) { appliedOptionsSignatureRef.current = optionsSignature; form.setFieldValue(field.name, selectedIds, false); } if (shouldApplyInitialOptions || fieldValueMatchesInitialOptions) { setValue((currentValue) => areSelectOptionsEqual(currentValue, selectedOptions) ? currentValue : selectedOptions, ); } } }, [field.name, field.value, form, options, showField]); const mapResponseToValuesAndLabels = (data) => ({ value: data.id, label: data.label, }); const handleChange = ( data: Array<{ value: string; label: string }> | null, ) => { const selectedOptions = data || []; setValue(selectedOptions); form.setFieldValue( field.name, selectedOptions.map((el) => el?.value || null), ); }; async function callApi( inputValue: string, loadedOptions: Array<{ value: string; label: string }>, ) { const path = `/${itemRef}/autocomplete?limit=${PAGE_SIZE}&offset=${loadedOptions.length}${inputValue ? `&query=${inputValue}` : ''}`; const { data } = await axios(path); return { options: data.map(mapResponseToValuesAndLabels), hasMore: data.length === PAGE_SIZE, }; } return ( 'px-1 py-2', }} classNamePrefix='react-select' instanceId={useId()} value={value} isMulti debounceTimeout={1000} loadOptions={callApi} onChange={handleChange} defaultOptions isClearable /> ); };