import { PureComponent } from 'react'; import Dialog from '@mui/material/Dialog'; import DialogTitle from '@mui/material/DialogTitle'; import DialogContent from '@mui/material/DialogContent'; import DialogActions from '@mui/material/DialogActions'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; import IconButton from '@mui/material/IconButton'; import CloseIcon from '@mui/icons-material/Close'; import CheckIcon from '@mui/icons-material/Check'; import FolderIcon from '@mui/icons-material/Folder'; import Breadcrumbs from '@mui/material/Breadcrumbs'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import CategoryTree from '../category/CategoryTree'; import categoryAutomat from '../../automats/categoryAutomat'; import { getCategoryBreadcrumbs, categoryDisplayName } from '../../utils/categoryUtils'; const EMPTY_ARRAY = []; export default class CategoryPickerDialog extends PureComponent { constructor(props) { super(props); const categories = props.categories ?? categoryAutomat.state.categories; const rootCategoryId = props.rootCategoryId ?? categoryAutomat.state.rootCategoryId; const currentCategoryIds = props.currentCategoryIds ?? EMPTY_ARRAY; let selectedId = null; if (props.selectedId != null) { selectedId = props.selectedId; } else if (currentCategoryIds.length > 0) { selectedId = currentCategoryIds[0]; } else if (rootCategoryId != null) { selectedId = rootCategoryId; } this.state = { categories, rootCategoryId, selectedId, }; } componentDidMount() { if (this.props.categories === undefined || this.props.rootCategoryId === undefined) { this._unsub = categoryAutomat.subscribe((s) => { this.setState((prev) => ({ categories: this.props.categories ?? s.categories, rootCategoryId: this.props.rootCategoryId ?? s.rootCategoryId, })); }); } } componentDidUpdate(prevProps) { if (this.props.open && !prevProps.open) { const currentCategoryIds = this.props.currentCategoryIds ?? EMPTY_ARRAY; let nextSelectedId = null; if (this.props.selectedId != null) { nextSelectedId = this.props.selectedId; } else if (currentCategoryIds.length > 0) { nextSelectedId = currentCategoryIds[0]; } else if (this.state.rootCategoryId != null) { nextSelectedId = this.state.rootCategoryId; } this.setState({ selectedId: nextSelectedId }); } if ( this.props.categories !== prevProps.categories || this.props.rootCategoryId !== prevProps.rootCategoryId ) { this.setState({ categories: this.props.categories ?? categoryAutomat.state.categories, rootCategoryId: this.props.rootCategoryId ?? categoryAutomat.state.rootCategoryId, }); } } componentWillUnmount() { this._unsub?.(); } handleSelect = (id) => { this.setState({ selectedId: id }); }; handleDoubleClick = (id) => { this.handleConfirmWithId(id); }; handleConfirmWithId = (targetId) => { if (targetId == null) return; const { disabledIds = EMPTY_ARRAY, excludeIds = EMPTY_ARRAY, mode = 'assign', onSelect, onSelectCategory, onClose } = this.props; if (disabledIds.some((id) => String(id) === String(targetId))) return; if (excludeIds.some((id) => String(id) === String(targetId))) return; const { categories } = this.state; const targetNode = categories ? categories[String(targetId)] : null; if (mode === 'single') { onSelectCategory?.(targetId, targetNode); onSelect?.(targetId, targetNode); } else { const currentCategoryIds = this.props.currentCategoryIds ?? EMPTY_ARRAY; const ids = currentCategoryIds.filter((id) => String(id) !== String(targetId)); ids.push(targetId); onSelectCategory?.(targetId, targetNode); onSelect?.(ids); } onClose?.(); }; handleConfirm = () => { this.handleConfirmWithId(this.state.selectedId); }; render() { const { open, onClose, currentCategoryIds = EMPTY_ARRAY, title, confirmLabel, mode = 'assign', disabledIds = EMPTY_ARRAY, excludeIds = EMPTY_ARRAY, } = this.props; const { categories, rootCategoryId, selectedId } = this.state; const dialogTitle = title || (mode === 'single' ? 'Kategorie auswählen' : 'Kategorie zuweisen'); const actionLabel = confirmLabel || (mode === 'single' ? 'Auswählen' : 'Zuweisen'); const selectedNode = categories && selectedId != null ? categories[String(selectedId)] : null; const isAlreadyAssigned = mode !== 'single' && currentCategoryIds.some((id) => String(id) === String(selectedId)); const isSelectedDisabled = selectedId == null || disabledIds.some((id) => String(id) === String(selectedId)) || excludeIds.some((id) => String(id) === String(selectedId)); const breadcrumbs = categories && selectedId != null ? getCategoryBreadcrumbs(categories, selectedId, rootCategoryId) : EMPTY_ARRAY; return ( {/* Header */} {dialogTitle} {/* Breadcrumb Path Preview */} {breadcrumbs.length > 0 && ( } sx={{ mt: 1, '& .MuiBreadcrumbs-li': { fontSize: '0.8rem' } }} > {breadcrumbs.map((bc, idx) => { const isLast = idx === breadcrumbs.length - 1; return ( {categoryDisplayName(bc.name, bc.id, rootCategoryId)} ); })} )} {/* Tree Content */} {/* Footer / Actions */} {isAlreadyAssigned && ( (bereits zugewiesen) )} ); } }