import pick from 'lodash/pick'; import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { DragDropContext, Droppable } from 'react-beautiful-dnd'; import { Button } from 'semantic-ui-react'; import { Input, Popup } from '../../lib/custom-ui'; import { useField, useSteps } from '../../hooks'; import DroppableTypes from '../../constants/DroppableTypes'; import AddStep from './AddStep'; import EditStep from './EditStep'; import Item from './Item'; import styles from './LabelsStep.module.scss'; const StepTypes = { ADD: 'ADD', EDIT: 'EDIT', }; const LabelsStep = React.memo( ({ items, currentIds, title, canEdit, onSelect, onDeselect, onCreate, onUpdate, onMove, onDelete, onBack, onCopyCard, }) => { const [t] = useTranslation(); const [step, openStep, handleBack] = useSteps(); const [search, handleSearchChange] = useField(''); const cleanSearch = useMemo(() => search.trim().toLowerCase(), [search]); const filteredItems = useMemo( () => items.filter( (label) => (label.name && label.name.toLowerCase().includes(cleanSearch)) || label.color.includes(cleanSearch), ), [items, cleanSearch], ); const searchField = useRef(null); const handleAddClick = useCallback(() => { openStep(StepTypes.ADD); }, [openStep]); const handleEdit = useCallback( (id) => { openStep(StepTypes.EDIT, { id, }); }, [openStep], ); const handleSelect = useCallback( (id) => { onSelect(id); }, [onSelect], ); const handleDeselect = useCallback( (id) => { onDeselect(id); }, [onDeselect], ); const handleDragEnd = useCallback( ({ draggableId, source, destination }) => { if (!destination || source.index === destination.index) { return; } onMove(draggableId, destination.index); }, [onMove], ); const handleUpdate = useCallback( (id, data) => { onUpdate(id, data); }, [onUpdate], ); const handleDelete = useCallback( (id) => { onDelete(id); }, [onDelete], ); useEffect(() => { searchField.current.focus({ preventScroll: true, }); }, []); if (step) { switch (step.type) { case StepTypes.ADD: return ( ); case StepTypes.EDIT: { const currentItem = items.find((item) => item.id === step.params.id); if (currentItem) { return ( handleUpdate(currentItem.id, data)} onDelete={() => handleDelete(currentItem.id)} onBack={handleBack} onCopyCard={onCopyCard} /> ); } openStep(null); break; } default: } } return ( <> {t(title, { context: 'title', })} {filteredItems.length > 0 && ( {({ innerRef, droppableProps, placeholder }) => ( {filteredItems.map((item, index) => ( handleSelect(item.id)} onDeselect={() => handleDeselect(item.id)} onEdit={() => handleEdit(item.id)} onCopyCard={onCopyCard} /> ))} {placeholder} )} {({ innerRef, droppableProps, placeholder }) => ( {placeholder} )} )} {canEdit && ( )} > ); }, ); LabelsStep.propTypes = { /* eslint-disable react/forbid-prop-types */ items: PropTypes.array.isRequired, currentIds: PropTypes.array.isRequired, /* eslint-enable react/forbid-prop-types */ title: PropTypes.string, canEdit: PropTypes.bool, onSelect: PropTypes.func.isRequired, onDeselect: PropTypes.func.isRequired, onCreate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired, onMove: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, onBack: PropTypes.func, onCopyCard: PropTypes.func, }; LabelsStep.defaultProps = { title: 'common.labels', canEdit: true, onBack: undefined, onCopyCard: undefined, }; export default LabelsStep;