1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-19 21:29:43 +02:00
planka/client/src/components/LabelsStep/LabelsStep.jsx

198 lines
4.7 KiB
React
Raw Normal View History

2019-08-31 04:07:25 +05:00
import pick from 'lodash/pick';
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
2019-08-31 04:07:25 +05:00
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Button } from 'semantic-ui-react';
import { Input, Popup } from '../../lib/custom-ui';
2019-08-31 04:07:25 +05:00
import { useField, useSteps } from '../../hooks';
2019-08-31 04:07:25 +05:00
import AddStep from './AddStep';
import EditStep from './EditStep';
import Item from './Item';
import styles from './LabelsStep.module.scss';
2019-08-31 04:07:25 +05:00
const StepTypes = {
ADD: 'ADD',
EDIT: 'EDIT',
};
const LabelsStep = React.memo(
2022-11-10 15:28:43 +01:00
({
items,
currentIds,
title,
canEdit,
onSelect,
onDeselect,
onCreate,
onUpdate,
onDelete,
onBack,
}) => {
2019-08-31 04:07:25 +05:00
const [t] = useTranslation();
const [step, openStep, handleBack] = useSteps();
2022-08-23 21:06:50 +02:00
const [search, handleSearchChange] = useField('');
const cleanSearch = useMemo(() => search.trim().toLowerCase(), [search]);
const filteredItems = useMemo(
() =>
items.filter(
(label) =>
2022-08-23 21:06:50 +02:00
(label.name && label.name.toLowerCase().includes(cleanSearch)) ||
label.color.includes(cleanSearch),
),
2022-08-23 21:06:50 +02:00
[items, cleanSearch],
);
const searchField = useRef(null);
2019-08-31 04:07:25 +05:00
const handleAddClick = useCallback(() => {
openStep(StepTypes.ADD);
}, [openStep]);
const handleEdit = useCallback(
2020-03-25 00:15:47 +05:00
(id) => {
2019-08-31 04:07:25 +05:00
openStep(StepTypes.EDIT, {
id,
});
},
[openStep],
);
const handleSelect = useCallback(
2020-03-25 00:15:47 +05:00
(id) => {
2019-08-31 04:07:25 +05:00
onSelect(id);
},
[onSelect],
);
const handleDeselect = useCallback(
2020-03-25 00:15:47 +05:00
(id) => {
2019-08-31 04:07:25 +05:00
onDeselect(id);
},
[onDeselect],
);
const handleUpdate = useCallback(
(id, data) => {
onUpdate(id, data);
},
[onUpdate],
);
const handleDelete = useCallback(
2020-03-25 00:15:47 +05:00
(id) => {
2019-08-31 04:07:25 +05:00
onDelete(id);
},
[onDelete],
);
useEffect(() => {
searchField.current.focus();
}, []);
2019-08-31 04:07:25 +05:00
if (step) {
switch (step.type) {
case StepTypes.ADD:
2022-10-03 13:12:16 +02:00
return (
<AddStep
defaultData={{
name: search,
}}
onCreate={onCreate}
onBack={handleBack}
/>
);
2019-08-31 04:07:25 +05:00
case StepTypes.EDIT: {
2020-03-25 00:15:47 +05:00
const currentItem = items.find((item) => item.id === step.params.id);
2019-08-31 04:07:25 +05:00
if (currentItem) {
return (
<EditStep
defaultData={pick(currentItem, ['name', 'color'])}
2020-03-25 00:15:47 +05:00
onUpdate={(data) => handleUpdate(currentItem.id, data)}
2019-08-31 04:07:25 +05:00
onDelete={() => handleDelete(currentItem.id)}
onBack={handleBack}
/>
);
}
openStep(null);
break;
}
default:
}
}
return (
<>
2022-08-23 21:06:50 +02:00
<Popup.Header onBack={onBack}>
{t(title, {
context: 'title',
})}
</Popup.Header>
2019-08-31 04:07:25 +05:00
<Popup.Content>
<Input
fluid
ref={searchField}
2022-08-23 21:06:50 +02:00
value={search}
placeholder={t('common.searchLabels')}
icon="search"
2022-08-23 21:06:50 +02:00
onChange={handleSearchChange}
/>
{filteredItems.length > 0 && (
<div className={styles.items}>
{filteredItems.map((item) => (
<Item
key={item.id}
name={item.name}
color={item.color}
isPersisted={item.isPersisted}
isActive={currentIds.includes(item.id)}
2022-11-10 15:28:43 +01:00
canEdit={canEdit}
onSelect={() => handleSelect(item.id)}
onDeselect={() => handleDeselect(item.id)}
onEdit={() => handleEdit(item.id)}
/>
))}
</div>
)}
2022-11-10 15:28:43 +01:00
{canEdit && (
<Button
fluid
content={t('action.createNewLabel')}
className={styles.addButton}
onClick={handleAddClick}
/>
)}
2019-08-31 04:07:25 +05:00
</Popup.Content>
</>
);
},
);
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,
2022-11-10 15:28:43 +01:00
canEdit: PropTypes.bool,
2019-08-31 04:07:25 +05:00
onSelect: PropTypes.func.isRequired,
onDeselect: PropTypes.func.isRequired,
onCreate: PropTypes.func.isRequired,
onUpdate: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
onBack: PropTypes.func,
};
LabelsStep.defaultProps = {
title: 'common.labels',
2022-11-10 15:28:43 +01:00
canEdit: true,
2019-08-31 04:07:25 +05:00
onBack: undefined,
};
export default LabelsStep;