mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 13:19:44 +02:00
parent
281cb4a71b
commit
f9e0147f33
61 changed files with 1063 additions and 191 deletions
|
@ -4,89 +4,141 @@ import { useTranslation } from 'react-i18next';
|
|||
import { withPopup } from '../../../lib/popup';
|
||||
import { Input, Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import { useField } from '../../../hooks';
|
||||
import { useField, useSteps } from '../../../hooks';
|
||||
import UserItem from './UserItem';
|
||||
|
||||
import styles from './AddPopup.module.scss';
|
||||
|
||||
const AddStep = React.memo(({ users, currentUserIds, title, onCreate, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
const [searchValue, handleSearchFieldChange] = useField('');
|
||||
const search = useMemo(() => searchValue.trim().toLowerCase(), [searchValue]);
|
||||
const StepTypes = {
|
||||
SELECT_PERMISSIONS: 'SELECT_PERMISSIONS',
|
||||
};
|
||||
|
||||
const filteredUsers = useMemo(
|
||||
() =>
|
||||
users.filter(
|
||||
(user) =>
|
||||
user.email.includes(search) ||
|
||||
user.name.toLowerCase().includes(search) ||
|
||||
(user.username && user.username.includes(search)),
|
||||
),
|
||||
[users, search],
|
||||
);
|
||||
const AddStep = React.memo(
|
||||
({ users, currentUserIds, permissionsSelectStep, title, onCreate, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
const [step, openStep, handleBack] = useSteps();
|
||||
const [searchValue, handleSearchFieldChange] = useField('');
|
||||
const search = useMemo(() => searchValue.trim().toLowerCase(), [searchValue]);
|
||||
|
||||
const searchField = useRef(null);
|
||||
const filteredUsers = useMemo(
|
||||
() =>
|
||||
users.filter(
|
||||
(user) =>
|
||||
user.email.includes(search) ||
|
||||
user.name.toLowerCase().includes(search) ||
|
||||
(user.username && user.username.includes(search)),
|
||||
),
|
||||
[users, search],
|
||||
);
|
||||
|
||||
const handleUserSelect = useCallback(
|
||||
(id) => {
|
||||
onCreate({
|
||||
userId: id,
|
||||
});
|
||||
const searchField = useRef(null);
|
||||
|
||||
onClose();
|
||||
},
|
||||
[onCreate, onClose],
|
||||
);
|
||||
const handleUserSelect = useCallback(
|
||||
(id) => {
|
||||
if (permissionsSelectStep) {
|
||||
openStep(StepTypes.SELECT_PERMISSIONS, {
|
||||
userId: id,
|
||||
});
|
||||
} else {
|
||||
onCreate({
|
||||
userId: id,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
searchField.current.focus();
|
||||
}, []);
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[permissionsSelectStep, onCreate, onClose, openStep],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header>
|
||||
{t(title, {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<Input
|
||||
fluid
|
||||
ref={searchField}
|
||||
value={searchValue}
|
||||
placeholder={t('common.searchUsers')}
|
||||
icon="search"
|
||||
onChange={handleSearchFieldChange}
|
||||
/>
|
||||
{filteredUsers.length > 0 && (
|
||||
<div className={styles.users}>
|
||||
{filteredUsers.map((user) => (
|
||||
<UserItem
|
||||
key={user.id}
|
||||
name={user.name}
|
||||
avatarUrl={user.avatarUrl}
|
||||
isActive={currentUserIds.includes(user.id)}
|
||||
onSelect={() => handleUserSelect(user.id)}
|
||||
const handleRoleSelect = useCallback(
|
||||
(data) => {
|
||||
onCreate({
|
||||
userId: step.params.userId,
|
||||
...data,
|
||||
});
|
||||
|
||||
onClose();
|
||||
},
|
||||
[onCreate, onClose, step],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
searchField.current.focus();
|
||||
}, []);
|
||||
|
||||
if (step) {
|
||||
switch (step.type) {
|
||||
case StepTypes.SELECT_PERMISSIONS: {
|
||||
const currentUser = users.find((user) => user.id === step.params.userId);
|
||||
|
||||
if (currentUser) {
|
||||
const PermissionsSelectStep = permissionsSelectStep;
|
||||
|
||||
return (
|
||||
<PermissionsSelectStep
|
||||
buttonContent="action.addMember"
|
||||
onSelect={handleRoleSelect}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Popup.Content>
|
||||
</>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
openStep(null);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header>
|
||||
{t(title, {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<Input
|
||||
fluid
|
||||
ref={searchField}
|
||||
value={searchValue}
|
||||
placeholder={t('common.searchUsers')}
|
||||
icon="search"
|
||||
onChange={handleSearchFieldChange}
|
||||
/>
|
||||
{filteredUsers.length > 0 && (
|
||||
<div className={styles.users}>
|
||||
{filteredUsers.map((user) => (
|
||||
<UserItem
|
||||
key={user.id}
|
||||
name={user.name}
|
||||
avatarUrl={user.avatarUrl}
|
||||
isActive={currentUserIds.includes(user.id)}
|
||||
onSelect={() => handleUserSelect(user.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Popup.Content>
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
AddStep.propTypes = {
|
||||
/* eslint-disable react/forbid-prop-types */
|
||||
users: PropTypes.array.isRequired,
|
||||
currentUserIds: PropTypes.array.isRequired,
|
||||
/* eslint-disable react/forbid-prop-types */
|
||||
permissionsSelectStep: PropTypes.elementType,
|
||||
title: PropTypes.string,
|
||||
onCreate: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
AddStep.defaultProps = {
|
||||
permissionsSelectStep: undefined,
|
||||
title: 'common.addMember',
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue