I’m using MUI Autocomplete and Formik and I wanted to group this into categories. If it has a sub_account, then get its children.
CODESANDBOX ——>
CLICK HERE
Expected outcome on the UI is something like:
-
Petty Cash
-
Cash In Bank – Bank of America
- Bank of America – Single Proprietor
- Bank of America – Corporate Entity
-
Cash
-
CIB – Bank of Vietnam
- Bank of Vietnam Personal
- Bank of Vietnam Checking Acc
CODE
export const CashAccountAutocomplete = ({
field,
form: { touched, errors, setFieldValue, values },
disabled,
...props
}) => {
const [inputValue, setInputValue] = useState("");
const handleChange = (_, newValue, reason) => {
if (reason === "clear") {
setFieldValue(field.name, { id: "", name: "" });
return;
}
setFieldValue(field.name, newValue);
};
const handleInputChange = (_, newInputValue) => {
setInputValue(newInputValue);
};
const extractSubAccounts = (accounts) => {
if (!Array.isArray(accounts)) {
console.error("Invalid accounts data. Expected an array.");
return [];
}
return accounts.flatMap(
({ id, name, sub_accounts }) =>
sub_accounts && sub_accounts.length > 0
? extractSubAccounts(sub_accounts) // Recursively extract sub-accounts
: [{ id, name }] // Include the account if it has no sub-accounts
);
};
const filteredData = extractSubAccounts(accounts);
return (
<Autocomplete
{...field}
disabled={disabled}
getOptionLabel={(option) =>
typeof option === "string" ? option : option?.name || ""
}
renderOption={(props, option) => {
return (
<li {...props} key={option.id}>
{option?.name}
</li>
);
}}
filterOptions={(x) => x}
options={filteredData || []}
autoComplete
includeInputInList
filterSelectedOptions
noOptionsText={"No data"}
onChange={handleChange}
inputValue={inputValue}
onInputChange={handleInputChange}
renderInput={(params) => (
<TextField
{...params}
{...props}
error={touched[field.name] && errors[field.name] ? true : false}
helperText={
touched[field.name] &&
errors[field.name] &&
String(errors[field.name].id)
}
/>
)}
fullWidth
/>
);
};
