import { forwardRef, memo, useCallback, useMemo, useState } from 'react'; import clsx from 'clsx'; import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; import type { DropDownMenuProps } from '../dropdown-menu'; import { Select } from '../@forms/select'; import { TextWithTooltip } from '../text-with-tooltip'; import createClasses from './styles'; import type { ClientImageProps, ClientImageMenuItemProps } from './types'; import { useEffect } from 'react'; // TODO: This could be written much cleaner.. // Should combine update functions to one, and have a single state const ClientImageMenuItemContent = ( props: ClientImageMenuItemProps['content'] & { labelId?: string; classes: Partial>; } ) => { const { src, title, subtitle, labelId, classes } = props; return ( {src && ( )} {typeof title === 'string' && ( )} {subtitle} ); }; const ClientImage = forwardRef((props: ClientImageProps, ref) => { const { width, parentChildrenSpace, controlled = false, ...otherProps } = props; const { classes: menuContentClasses, listItems: menuContentListItems } = props?.menuContentProps; const styles = createClasses({ width }); const defaultItemValue = useMemo( () => menuContentListItems.find(item => item.default)?.value, [menuContentListItems] ); const [selectValue, setSelectValue] = useState( props.value || props.defaultValue || defaultItemValue || '' ); const defaultListItemValue = useMemo( () => menuContentListItems?.map(({ content, ...itemProps }) => { const labelId = `lid-${itemProps.name}`; return { hidden: itemProps.default, selected: controlled && props.value === itemProps.value, textNode: ( ), ariaLabelledby: labelId, ...itemProps }; }), [controlled, menuContentListItems, props.value, styles] ); const [listItemsDisplay, setListItemsDisplay] = useState(defaultListItemValue); const [secondaryListItems, setSecondaryListItems] = useState(defaultListItemValue); const handleSelectChange: NonNullable = (name, value) => event => { const selected = selectValue === name ? selectValue : name.toString(); setSelectValue(selected); const newListItems = listItemsDisplay.map((item, index) => ({ ...item, selected: controlled ? item.value === props.value : item.name === selected, hidden: index === 0 && selected === listItemsDisplay[0].name ? true : undefined })); setListItemsDisplay(newListItems); setSecondaryListItems(newListItems); props.menuContentProps?.handleClick?.(name, value)(event); }; useEffect(() => { const updateListItems = (prev: typeof listItemsDisplay) => !props.value ? defaultListItemValue : prev.map((item, index) => ({ ...item, selected: props.value === item.value, hidden: index === 0 && props.value === prev[0].value })); if (controlled) { setListItemsDisplay(prev => updateListItems(prev)); setSecondaryListItems(prev => updateListItems(prev)); } }, [controlled, defaultListItemValue, props.value]); const handleTextChange = useCallback( e => { const value = (e?.target ? e.target.value : e).toString(); const lowerValue = value.toLowerCase(); const newListItems = listItemsDisplay.map(item => { const contentProps = (item.textNode as { props: ClientImageMenuItemProps['content'] }) ?.props; const keywords = [item.name, contentProps?.title, contentProps?.subtitle]; const isMatch = keywords.join(' ').toLowerCase().includes(lowerValue); return { ...item, hidden: !isMatch || item.default }; }); if (value !== '') { setListItemsDisplay(newListItems); } else { setListItemsDisplay(secondaryListItems); } }, [listItemsDisplay, secondaryListItems] ); const getValue = () => { if (controlled) return props.value || defaultItemValue; else return selectValue; }; return (