react-app/src/components/form/MultiselectFormField.tsx
import React from 'react';
import {
Autocomplete,
SxProps,
TextField,
Paper,
Chip,
Box,
autocompleteClasses,
ListItemText,
} from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
import { ISelectMenuItem } from '@/components/form/SelectFormField';
interface MultiselectFormFieldProps {
name: string;
label: string;
options: ISelectMenuItem[];
allowNestedIndent?: boolean;
sx?: SxProps;
required?: boolean;
}
const CustomPaper = (props) => {
return <Paper elevation={4} {...props} />;
};
/**
* MultiselectFormField component for rendering a multiselect form field with autocomplete functionality.
*
* @param {MultiselectFormFieldProps} props - The props object containing the necessary configurations for the multiselect field.
* @returns {JSX.Element} - Returns the JSX element for the MultiselectFormField component.
*/
const MultiselectFormField = (props: MultiselectFormFieldProps) => {
const { control, getValues, formState } = useFormContext();
const { name, label, sx, required, options, allowNestedIndent, ...rest } = props;
return (
<Controller
name={name}
control={control}
rules={{
required: { value: required, message: 'Required field.' },
}}
render={({ field: { onChange } }) => (
<Autocomplete
multiple
freeSolo={false}
disablePortal={false}
id={`multiselect-input-${label}`}
options={options}
PaperComponent={CustomPaper}
sx={sx}
limitTags={2}
fullWidth
getOptionLabel={(option: ISelectMenuItem) => option.label}
isOptionEqualToValue={(sourceOption, selectedOption) =>
sourceOption.value === selectedOption.value
}
renderTags={(selectedOptions, props) =>
selectedOptions.map((option, index) => (
<Chip
{...props({ index })}
key={option.value}
label={option.label ?? 'N/A'}
variant="outlined"
/>
))
}
renderInput={(params) => (
<TextField
{...params}
error={!!formState.errors?.[name]}
required={required}
label={label}
helperText={(formState.errors?.[name]?.message as string) ?? undefined}
/>
)}
renderOption={(props, option) => (
<Box
sx={{
[`&.${autocompleteClasses.option}`]: {
padding: 1,
paddingLeft: allowNestedIndent && option.parentId ? 2 : 1,
},
}}
component="li"
{...props}
key={option.label}
>
<ListItemText
primary={option.label}
secondary={option.tooltip}
sx={{
margin: 0,
}}
primaryTypographyProps={{
sx: {
fontWeight: allowNestedIndent && !option.parentId ? 900 : 500,
},
}}
/>
</Box>
)}
onChange={(_, data) => {
return data && onChange(data);
}}
value={getValues()[name]}
{...rest}
/>
)}
/>
);
};
export default MultiselectFormField;