ref: Creating popups with hook, fix translation keys passing
This commit is contained in:
+145
@@ -0,0 +1,145 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Input, Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import { useField, useSteps } from '../../../hooks';
|
||||
import UserItem from './UserItem';
|
||||
|
||||
import styles from './AddStep.module.scss';
|
||||
|
||||
const StepTypes = {
|
||||
SELECT_PERMISSIONS: 'SELECT_PERMISSIONS',
|
||||
};
|
||||
|
||||
const AddStep = React.memo(
|
||||
({ users, currentUserIds, permissionsSelectStep, title, onCreate, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
const [step, openStep, handleBack] = useSteps();
|
||||
const [search, handleSearchChange] = useField('');
|
||||
const cleanSearch = useMemo(() => search.trim().toLowerCase(), [search]);
|
||||
|
||||
const filteredUsers = useMemo(
|
||||
() =>
|
||||
users.filter(
|
||||
(user) =>
|
||||
user.email.includes(cleanSearch) ||
|
||||
user.name.toLowerCase().includes(cleanSearch) ||
|
||||
(user.username && user.username.includes(cleanSearch)),
|
||||
),
|
||||
[users, cleanSearch],
|
||||
);
|
||||
|
||||
const searchField = useRef(null);
|
||||
|
||||
const handleUserSelect = useCallback(
|
||||
(id) => {
|
||||
if (permissionsSelectStep) {
|
||||
openStep(StepTypes.SELECT_PERMISSIONS, {
|
||||
userId: id,
|
||||
});
|
||||
} else {
|
||||
onCreate({
|
||||
userId: id,
|
||||
});
|
||||
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[permissionsSelectStep, onCreate, onClose, openStep],
|
||||
);
|
||||
|
||||
const handleRoleSelect = useCallback(
|
||||
(data) => {
|
||||
onCreate({
|
||||
userId: step.params.userId,
|
||||
...data,
|
||||
});
|
||||
},
|
||||
[onCreate, step],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
searchField.current.focus({
|
||||
preventScroll: true,
|
||||
});
|
||||
}, []);
|
||||
|
||||
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}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
openStep(null);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header>
|
||||
{t(title, {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<Input
|
||||
fluid
|
||||
ref={searchField}
|
||||
value={search}
|
||||
placeholder={t('common.searchUsers')}
|
||||
icon="search"
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
{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',
|
||||
};
|
||||
|
||||
export default AddStep;
|
||||
@@ -0,0 +1,21 @@
|
||||
:global(#app) {
|
||||
.users {
|
||||
margin-top: 8px;
|
||||
max-height: 60vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import User from '../../User';
|
||||
|
||||
import styles from './UserItem.module.scss';
|
||||
|
||||
const UserItem = React.memo(({ name, avatarUrl, isActive, onSelect }) => (
|
||||
<button type="button" disabled={isActive} className={styles.menuItem} onClick={onSelect}>
|
||||
<span className={styles.user}>
|
||||
<User name={name} avatarUrl={avatarUrl} />
|
||||
</span>
|
||||
<div className={classNames(styles.menuItemText, isActive && styles.menuItemTextActive)}>
|
||||
{name}
|
||||
</div>
|
||||
</button>
|
||||
));
|
||||
|
||||
UserItem.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
avatarUrl: PropTypes.string,
|
||||
isActive: PropTypes.bool.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
UserItem.defaultProps = {
|
||||
avatarUrl: undefined,
|
||||
};
|
||||
|
||||
export default UserItem;
|
||||
@@ -0,0 +1,47 @@
|
||||
:global(#app) {
|
||||
.menuItem {
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 0.28571429rem;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
overflow: hidden;
|
||||
padding: 4px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.menuItemText {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
position: relative;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.menuItemTextActive:before {
|
||||
bottom: 2px;
|
||||
color: #798d99;
|
||||
content: "Г";
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
line-height: 36px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
text-align: center;
|
||||
transform: rotate(-135deg);
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
padding-right: 8px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import AddStep from './AddStep';
|
||||
|
||||
export default AddStep;
|
||||
Reference in New Issue
Block a user