import { Add as MUIAddIcon, Delete, Done as MUIDoneIcon, Edit as MUIEditIcon, } from '@mui/icons-material'; import { Box as MUIBox, List as MUIList, ListItem as MUIListItem, ListItemIcon as MUIListItemIcon, ListItemProps as MUIListItemProps, ListProps as MUIListProps, SxProps, Theme, } from '@mui/material'; import { FC, ReactNode, useMemo } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { BLUE, DIVIDER, GREY, RED } from '../lib/consts/DEFAULT_THEME'; import Checkbox, { CheckboxProps } from './Checkbox'; import FlexBox, { FlexBoxProps } from './FlexBox'; import IconButton, { IconButtonProps } from './IconButton'; import { BodyText } from './Text'; type ListOptionalProps = { header?: ReactNode; isAllowAddItem?: boolean; isAllowCheckItem?: boolean; isAllowDelete?: boolean; isAllowEdit?: boolean; isAllowEditItem?: boolean; isEdit?: boolean; isScroll?: boolean; listEmpty?: ReactNode; listItemKeyPrefix?: string; listItemProps?: MUIListItemProps; listProps?: MUIListProps; onAdd?: IconButtonProps['onClick']; onDelete?: IconButtonProps['onClick']; onEdit?: IconButtonProps['onClick']; onItemCheckboxChange?: CheckboxProps['onChange']; renderListItem?: (key: string, value: T) => ReactNode; }; type ListProps = FlexBoxProps & ListOptionalProps & { listItems: Record; }; const LIST_DEFAULT_PROPS: Required< Omit< ListOptionalProps, | 'header' | 'isAllowAddItem' | 'isAllowCheckItem' | 'isAllowDelete' | 'isAllowEditItem' | 'listEmpty' | 'onAdd' | 'onDelete' | 'onEdit' | 'onItemCheckboxChange' > > & Pick< ListOptionalProps, | 'header' | 'isAllowAddItem' | 'isAllowCheckItem' | 'isAllowDelete' | 'isAllowEditItem' | 'listEmpty' | 'onAdd' | 'onDelete' | 'onEdit' | 'onItemCheckboxChange' > = { header: undefined, isAllowAddItem: undefined, isAllowCheckItem: undefined, isAllowDelete: undefined, isAllowEdit: false, isAllowEditItem: undefined, isEdit: false, isScroll: false, listEmpty: undefined, listItemKeyPrefix: uuidv4(), listItemProps: {}, listProps: {}, onAdd: undefined, onDelete: undefined, onEdit: undefined, onItemCheckboxChange: undefined, renderListItem: (key) => {key}, }; const List = ({ header, isAllowEdit = LIST_DEFAULT_PROPS.isAllowEdit, isEdit = LIST_DEFAULT_PROPS.isEdit, isScroll = LIST_DEFAULT_PROPS.isScroll, listEmpty = LIST_DEFAULT_PROPS.listEmpty, listItemKeyPrefix = LIST_DEFAULT_PROPS.listItemKeyPrefix, listItemProps: { sx: listItemSx, ...restListItemProps } = LIST_DEFAULT_PROPS.listItemProps, listItems, listProps: { sx: listSx, ...restListProps } = LIST_DEFAULT_PROPS.listProps, onAdd, onDelete, onEdit, onItemCheckboxChange, renderListItem = LIST_DEFAULT_PROPS.renderListItem, // Input props that depend on other input props. isAllowAddItem = isAllowEdit, isAllowCheckItem = isAllowEdit, isAllowDelete = isAllowEdit, isAllowEditItem = isAllowEdit, ...rootProps }: ListProps): ReturnType>> => { const addItemButton = useMemo( () => isAllowAddItem ? ( ) : undefined, [isAllowAddItem, onAdd], ); const deleteItemButton = useMemo( () => isEdit && isAllowDelete ? ( ) : undefined, [isAllowDelete, isEdit, onDelete], ); const editItemButton = useMemo(() => { if (isAllowEditItem) { return ( {isEdit ? : } ); } return undefined; }, [isAllowEditItem, isEdit, onEdit]); const headerElement = useMemo( () => typeof header === 'string' ? ( {header} {deleteItemButton} {editItemButton} {addItemButton} ) : ( header ), [addItemButton, deleteItemButton, editItemButton, header], ); const listEmptyElement = useMemo( () => typeof listEmpty === 'string' ? ( {listEmpty} ) : ( listEmpty ), [listEmpty], ); const listItemCheckbox = useMemo( () => isEdit && isAllowCheckItem ? ( ) : undefined, [isAllowCheckItem, isEdit, onItemCheckboxChange], ); const listItemElements = useMemo(() => { const entries = Object.entries(listItems); return entries.length > 0 ? entries.map(([key, value]) => ( {listItemCheckbox} {renderListItem(key, value)} )) : listEmptyElement; }, [ listEmptyElement, listItemCheckbox, listItemKeyPrefix, listItems, listItemSx, renderListItem, restListItemProps, ]); const listScrollSx: SxProps | undefined = useMemo( () => (isScroll ? { maxHeight: '100%', overflowY: 'scroll' } : undefined), [isScroll], ); return ( {headerElement} {listItemElements} ); }; List.defaultProps = LIST_DEFAULT_PROPS; export default List;