import { FormikValues, useFormikContext } from 'formik'; import { equals, isEmpty, path, propEq, reject, split } from 'ramda'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { buildListingEndpoint, SingleConnectedAutocompleteField, useMemoComponent } from '../..'; import type { SelectEntry } from '../../InputField/Select'; import type { GetEndpointParams } from '../../InputField/Select/Autocomplete/Connected'; import MultiConnectedAutocompleteField from '../../InputField/Select/Autocomplete/Connected/Multi'; import { InputPropsWithoutGroup, InputType } from './models'; const defaultFilterKey = 'name'; const ConnectedAutocomplete = ({ dataTestId, getDisabled, required, getRequired, fieldName, label, connectedAutocomplete, change, additionalMemoProps, type, disableSortedOptions = false }: InputPropsWithoutGroup): JSX.Element => { const { t } = useTranslation(); const { values, touched, errors, setFieldValue, setFieldTouched, setValues, setTouched } = useFormikContext(); const filterKey = connectedAutocomplete?.filterKey || defaultFilterKey; const isMultiple = equals(type, InputType.MultiConnectedAutocomplete); const getEndpoint = (parameters: GetEndpointParams): string => { const nameQueryParameters = connectedAutocomplete?.useNewAPIFormat && parameters?.search ? [ { name: 'name[lk]', value: ( parameters.search.conditions?.[0].values?.$lk as string ).slice(1, -1) } ] : []; return buildListingEndpoint({ apiFormat: connectedAutocomplete?.useNewAPIFormat ? 'JSON-LD' : 'Standard', baseEndpoint: connectedAutocomplete?.endpoint, customQueryParameters: [ ...(connectedAutocomplete?.customQueryParameters || []), ...nameQueryParameters ], parameters: { ...parameters, search: { conditions: [ ...(connectedAutocomplete?.additionalConditionParameters || []), ...(parameters.search?.conditions || []) ], ...parameters.search }, sort: { [filterKey]: 'ASC' } } }); }; const fieldNamePath = split('.', fieldName); const changeAutocomplete = useCallback( ( _: React.SyntheticEvent, value: | NonNullable | Array | null ): void => { if (change) { change({ setFieldTouched, setFieldValue, setTouched, setValues, value, values }); return; } setFieldTouched(fieldName, true, false); setFieldValue(fieldName, value); }, [fieldName, touched, additionalMemoProps] ); const blur = (): void => void setFieldTouched(fieldName, true); const isOptionEqualToValue = useCallback( (option: SelectEntry, value: SelectEntry): boolean => { return isEmpty(value) ? false : equals( option[filterKey as keyof SelectEntry], value[filterKey as keyof SelectEntry] ); }, [filterKey] ); const value = path(fieldNamePath, values) as | Record | Array> | undefined; const error = path(fieldNamePath, touched) ? (path(fieldNamePath, errors) as string | undefined) : undefined; const disabled = getDisabled?.(values) || false; const isRequired = required || getRequired?.(values) || false; const AutocompleteField = useMemo( () => isMultiple ? MultiConnectedAutocompleteField : SingleConnectedAutocompleteField, [isMultiple] ); const deleteItem = (_: React.SyntheticEvent, option: SelectEntry): void => { const newValue = reject( propEq(option.id, 'id'), (value ?? []) as Array as Array<{ id: string | number }> ); setFieldTouched(fieldName, true, false); setFieldValue(fieldName, newValue); }; const chipProps = connectedAutocomplete && { color: connectedAutocomplete?.chipColor || 'default', onDelete: deleteItem }; const TypedAutocompleteField = AutocompleteField as unknown as React.ComponentType< Record >; return useMemoComponent({ Component: ( ), memoProps: [ value, error, disabled, isRequired, additionalMemoProps, connectedAutocomplete ] }); }; export default ConnectedAutocomplete;