You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.5 KiB
127 lines
3.5 KiB
import { Box } from '@mui/material'; |
|
import { ReactElement, useEffect, useMemo, useState } from 'react'; |
|
|
|
import Autocomplete from '../Autocomplete'; |
|
import CommonFenceInputGroup from './CommonFenceInputGroup'; |
|
import FlexBox from '../FlexBox'; |
|
import Spinner from '../Spinner'; |
|
import { BodyText } from '../Text'; |
|
import useIsFirstRender from '../../hooks/useIsFirstRender'; |
|
|
|
const INPUT_ID_FENCE_AGENT = 'add-fence-input-agent'; |
|
|
|
const AddFenceInputGroup = <M extends Record<string, string>>({ |
|
fenceTemplate: externalFenceTemplate, |
|
formUtils, |
|
loading: isExternalLoading, |
|
}: AddFenceInputGroupProps<M>): ReactElement => { |
|
const { setValidity } = formUtils; |
|
|
|
const isFirstRender = useIsFirstRender(); |
|
|
|
const [inputFenceTypeValue, setInputFenceTypeValue] = |
|
useState<FenceAutocompleteOption | null>(null); |
|
|
|
const fenceTypeOptions = useMemo<FenceAutocompleteOption[]>( |
|
() => |
|
externalFenceTemplate |
|
? Object.entries(externalFenceTemplate) |
|
.sort(([a], [b]) => (a > b ? 1 : -1)) |
|
.map(([id, { description: rawDescription }]) => { |
|
const description = |
|
typeof rawDescription === 'string' |
|
? rawDescription |
|
: 'No description.'; |
|
|
|
return { |
|
fenceDescription: description, |
|
fenceId: id, |
|
label: id, |
|
}; |
|
}) |
|
: [], |
|
[externalFenceTemplate], |
|
); |
|
|
|
const fenceTypeElement = useMemo( |
|
() => ( |
|
<Autocomplete |
|
id={INPUT_ID_FENCE_AGENT} |
|
isOptionEqualToValue={(option, value) => |
|
option.fenceId === value.fenceId |
|
} |
|
label="Fence device type" |
|
onChange={(event, newFenceType) => { |
|
setValidity(INPUT_ID_FENCE_AGENT, newFenceType !== null); |
|
setInputFenceTypeValue(newFenceType); |
|
}} |
|
openOnFocus |
|
options={fenceTypeOptions} |
|
renderOption={(props, { fenceDescription, fenceId }, { selected }) => ( |
|
<Box |
|
component="li" |
|
sx={{ |
|
display: 'flex', |
|
flexDirection: 'column', |
|
|
|
'& > *': { |
|
width: '100%', |
|
}, |
|
}} |
|
{...props} |
|
> |
|
<BodyText |
|
inverted |
|
sx={{ |
|
fontSize: '1.2em', |
|
fontWeight: selected ? 400 : undefined, |
|
}} |
|
> |
|
{fenceId} |
|
</BodyText> |
|
<BodyText selected={false}>{fenceDescription}</BodyText> |
|
</Box> |
|
)} |
|
sx={{ marginTop: '.3em' }} |
|
value={inputFenceTypeValue} |
|
/> |
|
), |
|
[fenceTypeOptions, inputFenceTypeValue, setValidity], |
|
); |
|
|
|
const fenceParameterElements = useMemo( |
|
() => ( |
|
<CommonFenceInputGroup |
|
fenceId={inputFenceTypeValue?.fenceId} |
|
fenceTemplate={externalFenceTemplate} |
|
formUtils={formUtils} |
|
/> |
|
), |
|
[externalFenceTemplate, inputFenceTypeValue?.fenceId, formUtils], |
|
); |
|
|
|
const content = useMemo( |
|
() => |
|
isExternalLoading ? ( |
|
<Spinner /> |
|
) : ( |
|
<FlexBox> |
|
{fenceTypeElement} |
|
{fenceParameterElements} |
|
</FlexBox> |
|
), |
|
[fenceTypeElement, fenceParameterElements, isExternalLoading], |
|
); |
|
|
|
useEffect(() => { |
|
if (isFirstRender) { |
|
setValidity(INPUT_ID_FENCE_AGENT, inputFenceTypeValue !== null); |
|
} |
|
}, [inputFenceTypeValue, isFirstRender, setValidity]); |
|
|
|
return <>{content}</>; |
|
}; |
|
|
|
export { INPUT_ID_FENCE_AGENT }; |
|
|
|
export default AddFenceInputGroup;
|
|
|