Last active
January 22, 2022 11:48
Autocomplete
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormForTesting } from '@epic/testing/react'; | |
import { render, waitFor } from '@testing-library/react'; | |
import userEvent from '@testing-library/user-event'; | |
import { useForm } from 'react-hook-form'; | |
import { EpicAutocomplete } from './EpicAutocomplete'; | |
import { EpicAutocompleteProps } from './EpicAutocompleteProps'; | |
const onSubmit = jest.fn(); | |
jest.mock('../../locale', () => { | |
return { | |
useTranslation: jest.fn(() => ({ | |
t: (key: string) => key, | |
})), | |
}; | |
}); | |
afterEach(() => { | |
jest.clearAllMocks(); | |
}); | |
type Model = { test: string }; | |
function TestComponent( | |
props: Omit< | |
EpicAutocompleteProps, | |
'name' | 'label' | 'options' | 'formContext' | 'getOptionLabel' | |
> | |
) { | |
const formContext = useForm<Model>(); | |
const { | |
formState: { errors }, | |
} = formContext; | |
const submit = (data: Model) => { | |
onSubmit(data); | |
}; | |
return ( | |
<FormForTesting formContext={formContext} submit={submit}> | |
<EpicAutocomplete | |
name="test" | |
label="Test" | |
placeholder="Test" | |
options={['1', '2', '3']} | |
formContext={formContext} | |
getOptionLabel={(option: string) => option} | |
error={!!errors} | |
helperText={errors?.test?.message} | |
{...props} | |
/> | |
<button type={'submit'}>Submit</button> | |
</FormForTesting> | |
); | |
} | |
describe('Behaviours', function () { | |
it('should bind to form context', async function () { | |
const { getByLabelText, findByText, getByText } = render(<TestComponent />); | |
getByLabelText('Test'); | |
const openButton = getByLabelText('Open'); | |
userEvent.click(openButton); | |
const option1 = await findByText('1'); | |
userEvent.click(option1); | |
expect(getByLabelText('Test')).toHaveValue('1'); | |
const submit = getByText('Submit'); | |
userEvent.click(submit); | |
await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ test: '1' })); | |
}); | |
it('should render disabled input without buttons in read only mode', async function () { | |
const { getByLabelText, queryByLabelText } = render(<TestComponent canEdit={false} />); | |
const input = getByLabelText('Test'); | |
const openButton = queryByLabelText('Open'); | |
expect(input).toBeDisabled(); | |
expect(input).not.toHaveAttribute('aria-autocomplete'); | |
expect(openButton).toBeNull(); | |
}); | |
it('should render readonly input without buttons in readonly edit mode', async function () { | |
const lockedReason = 'For Testing'; | |
const { getByLabelText, queryByLabelText } = render( | |
<TestComponent canEdit={true} readOnly readOnlyReason={lockedReason} /> | |
); | |
const input = getByLabelText('Test'); | |
const openButton = queryByLabelText('Open'); | |
expect(getByLabelText('Locked. For Testing')).toBeInTheDocument(); | |
expect(input).toHaveAttribute('readonly'); | |
expect(input).not.toHaveAttribute('aria-autocomplete'); | |
expect(openButton).toBeNull(); | |
}); | |
it('should set default value', async function () { | |
const { getByLabelText, getByText } = render(<TestComponent defaultValue={'1'} />); | |
getByLabelText('Test'); | |
const submit = getByText('Submit'); | |
userEvent.click(submit); | |
await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ test: '1' })); | |
}); | |
it('should be full width by default', function () { | |
const { getByLabelText } = render(<TestComponent />); | |
const input = getByLabelText('Test'); | |
expect(input.closest('div')?.className).toMatch(/fullwidth/i); | |
}); | |
it('should support multiple selections', async function () { | |
const { getByLabelText, findByText, getByText, debug } = render(<TestComponent multiple />); | |
getByLabelText('Test', { selector: 'input' }); | |
const openButton = getByLabelText('Open'); | |
userEvent.click(openButton); | |
const option1 = await findByText('1'); | |
const option2 = await findByText('2'); | |
userEvent.click(option1); | |
userEvent.click(option2); | |
expect(await findByText('1', { selector: 'span.MuiChip-label' })).toBeInTheDocument(); | |
expect(await findByText('2', { selector: 'span.MuiChip-label' })).toBeInTheDocument(); | |
const submit = getByText('Submit'); | |
userEvent.click(submit); | |
await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ test: ['1', '2'] })); | |
}); | |
it('should enforce option limit', async function () { | |
const { getByLabelText, findByText, queryByText, rerender } = render(<TestComponent />); | |
userEvent.click(getByLabelText('Open')); | |
expect(await findByText('3')).toBeInTheDocument(); | |
rerender(<TestComponent optionLimit={2} />); | |
await findByText('1'); | |
expect(queryByText('3')).toBeNull(); | |
userEvent.type(getByLabelText('Test', { selector: 'input' }), '3'); | |
expect(await findByText('3')).toBeInTheDocument(); | |
}); | |
it('should trigger given onChange event on change', async function () { | |
const onChange = jest.fn(); | |
const { getByLabelText, findByText } = render(<TestComponent onChange={onChange} />); | |
getByLabelText('Test'); | |
const openButton = getByLabelText('Open'); | |
userEvent.click(openButton); | |
const option1 = await findByText('1'); | |
userEvent.click(option1); | |
await waitFor(() => expect(onChange).toHaveBeenCalledWith('1')); | |
}); | |
it('should apply text field configurations', function () { | |
const { getByLabelText } = render( | |
<TestComponent textFieldProps={{ style: { color: 'black' } }} /> | |
); | |
const input = getByLabelText('Test', { selector: 'input' }); | |
expect(input.closest('div[style="color: black;"]')).toBeInTheDocument(); | |
}); | |
}); | |
describe('Validations', function () { | |
it('should validate required rule', async function () { | |
const { getByLabelText, findByText, getByText, debug } = render(<TestComponent required />); | |
getByLabelText(/Test/); | |
getByLabelText(/\*/); | |
userEvent.click(getByLabelText('Open')); | |
userEvent.click(getByText('Submit')); | |
expect(await findByText('Required')).toBeInTheDocument(); | |
expect(onSubmit).not.toHaveBeenCalled(); | |
}); | |
it('should enforce given rules', async function () { | |
const minSelection = (minSelection = 2) => ({ | |
validate: (value: string[]) => { | |
if (!value?.length || value.length < minSelection) { | |
return `Must select at least ${minSelection} options`; | |
} | |
}, | |
}); | |
const { getByLabelText, findByText, getByText, queryByText } = render( | |
<TestComponent multiple rules={minSelection()} /> | |
); | |
const openButton = getByLabelText('Open'); | |
userEvent.click(openButton); | |
const option1 = await findByText('1'); | |
userEvent.click(option1); | |
const submit = getByText('Submit'); | |
userEvent.click(submit); | |
expect(await findByText('Must select at least 2 options')).toBeInTheDocument(); | |
expect(onSubmit).not.toHaveBeenCalled(); | |
userEvent.click(openButton); | |
const option2 = await findByText('2'); | |
userEvent.click(option2); | |
userEvent.click(submit); | |
await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ test: ['1', '2'] })); | |
expect(queryByText('Must select at least 2 options')).toBeNull(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { EpicAutocompleteProps } from './EpicAutocompleteProps'; | |
import { EpicAutoCompleteBase } from './EpicAutoCompleteBase'; | |
export function EpicAutocomplete(props: EpicAutocompleteProps) { | |
return <EpicAutoCompleteBase {...props} />; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
/> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { InputProps } from '@mui/material'; | |
import { AutocompleteChangeDetails, AutocompleteChangeReason } from '@mui/material/Autocomplete'; | |
import { EpicAutocompleteProps } from './EpicAutocompleteProps'; | |
export interface EpicAutocompleteBaseProps extends EpicAutocompleteProps { | |
onChangeFactory?: ( | |
onChange: (...event: any[]) => void | |
) => ( | |
event: React.SyntheticEvent, | |
value: string | string[] | null, | |
reason: AutocompleteChangeReason, | |
details?: AutocompleteChangeDetails<unknown> | |
) => void; | |
InputPropsFactory?: (value: string) => Partial<InputProps>; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
FilledTextFieldProps, | |
OutlinedTextFieldProps, | |
StandardTextFieldProps, | |
} from '@mui/material'; | |
import { AutocompleteProps } from '@mui/material/Autocomplete'; | |
import { RegisterOptions, UseFormReturn } from 'react-hook-form'; | |
export interface EpicAutocompleteProps | |
extends Partial<Omit<AutocompleteProps<string, boolean, boolean, boolean>, 'getOptionLabel'>> { | |
canEdit?: boolean; | |
formContext: UseFormReturn<any>; | |
name: string; | |
label: string; | |
options: string[]; | |
multiple?: boolean; | |
defaultValue?: string | string[]; | |
getOptionLabel: (option: string) => string; | |
textFieldProps?: StandardTextFieldProps | OutlinedTextFieldProps | FilledTextFieldProps; | |
optionLimit?: number; | |
onChange?: (value: any) => void; | |
error?: boolean; | |
helperText?: string; | |
rules?: Omit<RegisterOptions, 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>; | |
required?: boolean; | |
readOnly?: boolean; | |
readOnlyReason?: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormForTesting } from '@epic/testing/react'; | |
import { render } from '@testing-library/react'; | |
import userEvent from '@testing-library/user-event'; | |
import { useForm } from 'react-hook-form'; | |
import { | |
EpicAutocompleteWithManager, | |
EpicAutocompleteWithManagerProps, | |
} from './EpicAutocompleteWithManager'; | |
const onSubmit = jest.fn(); | |
const manager = jest.fn(); | |
jest.mock('../../locale', () => { | |
return { | |
useTranslation: jest.fn(() => ({ | |
t: (key: string) => key, | |
})), | |
}; | |
}); | |
afterEach(() => { | |
jest.clearAllMocks(); | |
}); | |
type Model = { test: string }; | |
function TestComponent( | |
props: Omit< | |
EpicAutocompleteWithManagerProps, | |
'name' | 'label' | 'options' | 'formContext' | 'getOptionLabel' | 'manager' | |
> | |
) { | |
const formContext = useForm<Model>(); | |
const { | |
formState: { errors }, | |
} = formContext; | |
const submit = (data: Model) => { | |
onSubmit(data); | |
}; | |
return ( | |
<FormForTesting formContext={formContext} submit={submit}> | |
<EpicAutocompleteWithManager | |
name="test" | |
label="Test" | |
placeholder="Test" | |
options={['1', '2', '3']} | |
formContext={formContext} | |
getOptionLabel={(option: string) => option} | |
error={!!errors} | |
manager={manager} | |
helperText={errors?.test?.message} | |
{...props} | |
/> | |
<button type={'submit'}>Submit</button> | |
</FormForTesting> | |
); | |
} | |
describe('Autocomplete with manager', function () { | |
it('should render extra option at the end and clicking it launches the given function', async function () { | |
const { getByLabelText, findByText } = render(<TestComponent />); | |
const button = getByLabelText('Open'); | |
userEvent.click(button); | |
const masterDetail = await findByText('Manage...'); | |
masterDetail.click(); | |
expect(manager).toHaveBeenCalled(); | |
}); | |
it('should change to given label', async function () { | |
const { getByLabelText, findByText } = render(<TestComponent managerLabel={'Add/Edit'} />); | |
const button = getByLabelText('Open'); | |
userEvent.click(button); | |
const masterDetail = await findByText('Add/Edit...'); | |
masterDetail.click(); | |
expect(manager).toHaveBeenCalled(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { FC, ReactNode, useCallback, useMemo } from 'react'; | |
import { useTranslation } from '../../locale'; | |
import { callAll } from '../../utils'; | |
import { EpicAutoCompleteBase } from './EpicAutoCompleteBase'; | |
import { EpicAutocompleteProps } from './EpicAutocompleteProps'; | |
export interface EpicAutocompleteWithManagerProps extends EpicAutocompleteProps { | |
manager: () => void; | |
managerLabel?: string; | |
} | |
export const EpicAutocompleteWithManager: FC<EpicAutocompleteWithManagerProps> = ({ | |
options, | |
getOptionLabel, | |
manager, | |
managerLabel, | |
multiple, | |
onChange, | |
...props | |
}) => { | |
const { t } = useTranslation(); | |
const manageKey = 'manage'; | |
const _options = useMemo(() => [...options, manageKey], [options]); | |
const getLabel = useCallback( | |
(option: string) => { | |
if (option === manageKey) { | |
return `${managerLabel ?? t('Manage')}...`; | |
} | |
return getOptionLabel(option) ?? option; | |
}, | |
[getOptionLabel, managerLabel, t] | |
); | |
const renderOption = useCallback( | |
(props: React.HTMLAttributes<HTMLLIElement>, option: string, _): ReactNode => { | |
if (option === manageKey) { | |
return `${managerLabel ?? t('Manage')}...`; | |
} | |
return getOptionLabel(option) ?? option; | |
}, | |
[getOptionLabel, managerLabel, t] | |
); | |
return ( | |
<EpicAutoCompleteBase | |
getOptionLabel={getLabel} | |
options={_options} | |
renderOption={renderOption} | |
onChangeFactory={(_onChange) => (_, data) => { | |
if (data === manageKey) { | |
_onChange(multiple ? [] : null); | |
manager && manager(); | |
return; | |
} | |
callAll(_onChange, onChange)(data); | |
}} | |
{...props} | |
/> | |
); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormForTesting } from '@epic/testing/react'; | |
import { render } from '@testing-library/react'; | |
import userEvent from '@testing-library/user-event'; | |
import { useForm } from 'react-hook-form'; | |
import { BrowserRouter } from 'react-router-dom'; | |
import { EpicAutocompleteWithUrl, EpicAutocompleteWithUrlProps } from './EpicAutocompleteWithUrl'; | |
const onSubmit = jest.fn(); | |
jest.mock('../../locale', () => { | |
return { | |
useTranslation: jest.fn(() => ({ | |
t: (key: string) => key, | |
})), | |
}; | |
}); | |
afterEach(() => { | |
jest.clearAllMocks(); | |
}); | |
type Model = { test: string }; | |
function TestComponent( | |
props: Omit< | |
EpicAutocompleteWithUrlProps, | |
'name' | 'label' | 'options' | 'formContext' | 'getOptionLabel' | 'url' | |
> | |
) { | |
const formContext = useForm<Model>(); | |
const { | |
formState: { errors }, | |
} = formContext; | |
const submit = (data: Model) => { | |
onSubmit(data); | |
}; | |
return ( | |
<BrowserRouter> | |
<FormForTesting formContext={formContext} submit={submit}> | |
<EpicAutocompleteWithUrl | |
name="test" | |
label="Test" | |
placeholder="Test" | |
options={['1', '2', '3']} | |
formContext={formContext} | |
getOptionLabel={(option: string) => option} | |
error={!!errors} | |
url={'/sales/customers'} | |
helperText={errors?.test?.message} | |
{...props} | |
/> | |
<button type={'submit'}>Submit</button> | |
</FormForTesting> | |
</BrowserRouter> | |
); | |
} | |
describe('Autocomplete with url', function () { | |
it('should navigate to url on clicking the link icon button in read only mode', async function () { | |
const { findByLabelText, getByTestId } = render( | |
<TestComponent defaultValue={'1'} canEdit={false} /> | |
); | |
await findByLabelText('Test'); | |
userEvent.click(getByTestId('goToUrl')); | |
expect(window.location.href).toBe('http://localhost/sales/customers/1'); | |
}); | |
it('should not show go to url button if there is no value', async function () { | |
const { findByLabelText, queryByTestId } = render(<TestComponent canEdit={false} />); | |
await findByLabelText('Test'); | |
expect(queryByTestId('goToUrl')).toBeNull(); | |
}); | |
it('should not show go to url button in edit mode', async function () { | |
const { findByLabelText, queryByTestId } = render(<TestComponent defaultValue={'1'} canEdit />); | |
await findByLabelText('Test'); | |
expect(queryByTestId('goToUrl')).toBeNull(); | |
}); | |
it('should not show go to url button in edit mode and readonly', async function () { | |
const { findByLabelText, queryByTestId } = render( | |
<TestComponent defaultValue={'1'} canEdit readOnly /> | |
); | |
await findByLabelText('Test'); | |
expect(queryByTestId('goToUrl')).toBeNull(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { OpenInBrowser } from '@mui/icons-material'; | |
import { IconButton, Tooltip } from '@mui/material'; | |
import { useCallback } from 'react'; | |
import { useNavigate } from 'react-router'; | |
import { useTranslation } from '../../locale'; | |
import { EpicAutocompleteProps } from './EpicAutocompleteProps'; | |
import { EpicAutoCompleteBase } from './EpicAutoCompleteBase'; | |
export interface EpicAutocompleteWithUrlProps extends EpicAutocompleteProps { | |
url: string; | |
} | |
export function EpicAutocompleteWithUrl(props: EpicAutocompleteWithUrlProps) { | |
const { url, ...rest } = props; | |
const { t } = useTranslation(); | |
const navigate = useNavigate(); | |
const navigateToItem = useCallback( | |
(id: string) => { | |
if (!url || !id) { | |
return; | |
} | |
navigate(`${url}/${id}`); | |
}, | |
[navigate, url] | |
); | |
return ( | |
<EpicAutoCompleteBase | |
{...rest} | |
InputPropsFactory={(value) => ({ | |
startAdornment: | |
url && value ? ( | |
<Tooltip title={t('Open...')}> | |
<IconButton | |
onClick={() => navigateToItem(value)} | |
size={'small'} | |
data-testid={'goToUrl'} | |
> | |
<OpenInBrowser fontSize={'inherit'} /> | |
</IconButton> | |
</Tooltip> | |
) : undefined, | |
})} | |
/> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment