import { Checkbox, IconButton, Tooltip } from '@mui/material'; import { Lock } from '@mui/icons-material'; import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete'; import React, { FC, ReactNode, useCallback } from 'react'; import { Controller, ControllerRenderProps } from 'react-hook-form'; import { RiCheckboxBlankCircleLine, RiCheckboxCircleLine } from 'react-icons/ri'; import { useTranslation } from '../../locale'; import { callAll, useGeneratedId } from '../../utils'; import { EpicTextField } from '../TextField/EpicTextField'; import { EpicAutocompleteBaseProps } from './EpicAutocompleteBaseProps'; type RHFRenderProps = { field: ControllerRenderProps; }; export const EpicAutoCompleteBase: FC<EpicAutocompleteBaseProps> = ({ canEdit = true, formContext, name, label, options, multiple, getOptionLabel, defaultValue, textFieldProps, onChange, renderInput, size = 'small', optionLimit, error, helperText, rules, required, onChangeFactory, readOnly, renderOption, readOnlyReason, disableCloseOnSelect, InputPropsFactory, ...autoCompleteProps }) => { const { t } = useTranslation(); const filterOptions = createFilterOptions<any>({ matchFrom: 'any', limit: optionLimit, }); const { control } = formContext; const renderText = useCallback( (value: string | string[] | number | null | undefined): ReactNode => { if (!value) { return ''; } if (typeof value === 'string' || typeof value === 'number') { return getOptionLabel(`${value}`) || `${value}`; } return (value as string[]).map((x) => getOptionLabel(x)).join(','); }, [getOptionLabel] ); const generatedId = useGeneratedId(); const renderAutocomplete = ({ field: { onChange: _onChange, value, ...controllerProps }, }: RHFRenderProps) => ( <Autocomplete id={generatedId} value={value ?? (multiple ? [] : null)} multiple={multiple || false} disableCloseOnSelect={disableCloseOnSelect ?? (multiple || false)} options={options} size={size} disableClearable={required} filterOptions={optionLimit ? filterOptions : undefined} onChange={ (onChangeFactory && onChangeFactory(_onChange)) ?? ((e, data) => { callAll(_onChange, onChange)(data); }) } renderOption={ multiple ? (props, option, state) => { const { selected } = state; return ( <li {...props}> <Checkbox icon={<RiCheckboxBlankCircleLine />} checkedIcon={<RiCheckboxCircleLine />} style={{ marginRight: 8 }} checked={selected} /> {(renderOption && renderOption(props, option, state)) ?? getOptionLabel(option)} </li> ); } : (props, option, state) => ( <li {...props}> {(renderOption && renderOption(props, option, state)) ?? getOptionLabel(option)} </li> ) } getOptionLabel={getOptionLabel} renderInput={ renderInput || ((params) => ( <EpicTextField autoComplete={'off'} variant={'outlined'} label={label} ref={params.InputProps.ref} error={error} helperText={helperText} {...textFieldProps} required={textFieldProps?.required ?? required} {...params} inputProps={{ ...params.inputProps, autoComplete: 'off', 'data-testid': name, }} InputLabelProps={{ shrink: true, }} /> )) } {...controllerProps} {...autoCompleteProps} /> ); const renderReadOnlyLockedTextField = ({ field: { onChange: _onChange, value, ...controllerProps }, }: RHFRenderProps) => ( <EpicTextField value={renderText(value) || ''} label={label} size={size} fullWidth variant={canEdit ? 'outlined' : 'standard'} {...textFieldProps} {...controllerProps} required={false} InputLabelProps={{ shrink: true, }} inputProps={{ 'data-testid': name, }} InputProps={{ ...(textFieldProps?.InputProps ?? {}), readOnly: true, endAdornment: canEdit ? ( <Tooltip title={`${t('Locked')}. ${readOnlyReason ?? ''}`}> <IconButton size={'small'}> <Lock fontSize={'inherit'} /> </IconButton> </Tooltip> ) : undefined, }} /> ); const renderDisabledTextField = ({ field: { onChange: _onChange, value, ...controllerProps }, }: RHFRenderProps) => ( <EpicTextField value={renderText(value) || ''} label={label} id={generatedId} size={size} fullWidth variant={'standard'} {...textFieldProps} {...controllerProps} required={false} InputLabelProps={{ shrink: true, }} inputProps={{ 'data-testid': name, }} InputProps={{ ...(textFieldProps?.InputProps ?? {}), disabled: true, ...((InputPropsFactory && InputPropsFactory(value)) ?? {}), }} /> ); return ( <Controller control={control} name={name} rules={{ required: { value: (textFieldProps?.required || required) ?? false, message: `Required`, }, ...rules, }} defaultValue={defaultValue} render={(renderPops) => canEdit ? readOnly ? renderReadOnlyLockedTextField(renderPops) : renderAutocomplete(renderPops) : renderDisabledTextField(renderPops) } /> ); };