Skip to content

Instantly share code, notes, and snippets.

@RuslanSevrukov
Created March 3, 2021 15:03
Show Gist options
  • Save RuslanSevrukov/b169d34ba5bb58fb9e8076212dccca20 to your computer and use it in GitHub Desktop.
Save RuslanSevrukov/b169d34ba5bb58fb9e8076212dccca20 to your computer and use it in GitHub Desktop.
import React, {
useEffect,
memo,
useCallback,
useState,
useMemo,
} from ‘react’;
import { useDispatch, useSelector } from ‘react-redux’;
import ReactTooltip from ‘react-tooltip’;
import { debounce } from ‘lodash’;
import {
getUsersRequest,
updateRoleForSelectionRequest,
updateRoleRequest,
} from ‘../../actions/adminRequest’;
import TableUsers from ‘./TableUsers’;
import Kpi from ‘./Kpi’;
import SelectRole from ‘./SelectRole’;
import ConfirmationModal from ‘../modals/StandartModal’;
import CopyboardText from ‘./CopyboardText’;
import SearchAdminInput from ‘./SearchAdminInput’;
import { getKeysFromObject, roundIndicator } from ‘../../service/helpers’;
import CustomCheckbox from ‘../formElements/CustomCheckbox’;
// temporary
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
function Users() {
const dispatch = useDispatch();
const users = useSelector(({ admin: { users } }) => users);
const pageCount = useSelector(({ admin: { pageCount } }) => pageCount);
const currentUser = useSelector(({ auth: { currentUser } }) => currentUser);
// searching by useEffect through request
const [search, setSearch] = useState(‘’);
useEffect(() => {
ReactTooltip.rebuild();
});
const handleSearching = useCallback((value) => {
setSearch(value);
}, []);
const handler = useCallback(debounce(handleSearching, 400), [handleSearching]);
const handleChangeInput = useCallback(({ target: { value } }) => {
handler(value);
}, [handler]);
const updateRole = useCallback((data) => {
dispatch(updateRoleRequest(data));
}, [dispatch]);
const updateRoleForSelection = useCallback((data) => {
dispatch(updateRoleForSelectionRequest(data));
}, [dispatch]);
const [selection, setSelection] = useState({});
useEffect(() => {
const emptyUsers = {};
users.forEach(({ email }) => { emptyUsers[email] = null; });
if (users[0] && selection[users[0].email] === undefined) {
setSelection({ ...selection, ...emptyUsers });
}
}, [selection, users]);
const [isShowModalUser, setShowModalUser] = useState(false);
const closeModalUser = useCallback(() => setShowModalUser(false), []);
const openModalUser = useCallback(() => setShowModalUser(true), []);
const [isShowModalSelection, setShowModalSelection] = useState(false);
const closeModalSelection = useCallback(() => setShowModalSelection(false), []);
const openModalSelection = useCallback(() => setShowModalSelection(true), []);
const [dataToUpdate, setDataToUpdate] = useState({});
const [roleForAll, setRoleForAll] = useState({});
const resetSelectAll = useCallback(() => {
const resetedSelection = {};
getKeysFromObject(selection).forEach((email) => {
resetedSelection[email] = false;
});
setSelection(resetedSelection);
}, [selection]);
const handleUpdatingRole = useCallback((data) => {
if (data.label !== data.prevLabel) {
openModalUser();
setDataToUpdate(data);
}
}, [openModalUser]);
const handleUpdatingRoleForSelection = useCallback((data) => {
const selectedUsers = getKeysFromObject(selection).map(email => selection[email]).filter(Boolean);
const prevLabel = selectedUsers[0].role.name;
if (data.label !== prevLabel) {
openModalSelection();
setDataToUpdate({ ...data, prevLabel });
}
}, [openModalSelection, selection]);
const confirmUpdatingRole = useCallback(() => {
const {
id,
roleId,
} = dataToUpdate;
updateRole({ id, roleId });
closeModalUser();
}, [closeModalUser, dataToUpdate, updateRole]);
const confirmUpdatingRoleForSelection = useCallback(() => {
const {
value: roleId,
} = dataToUpdate;
const userIds = getKeysFromObject(selection)
.map(email => selection[email] && selection[email].id)
.filter(Boolean);
updateRoleForSelection({ userIds, roleId });
closeModalSelection();
setRoleForAll(currentUser.roles.find(({ value: id }) => Number(id) === Number(roleId)));
}, [closeModalSelection, currentUser, dataToUpdate, selection, updateRoleForSelection]);
const allUsersCheckedForPage = useMemo(() => users
.map(({ email }) => selection[email])
.filter(Boolean).length === users.length, [selection, users]);
const selectAllUsersOnPage = useCallback(() => {
const obj = {};
const pageSelection = users.map(({ email }) => selection[email]).filter(Boolean);
if (pageSelection.length === users.length) {
users.forEach((user) => { obj[user.email] = null; });
} else {
users.forEach((user) => { obj[user.email] = user; });
}
setSelection({ ...selection, ...obj });
}, [selection, users]);
const selectAllButton = useCallback(() => (
<div className=“custom-checkbox custom-checkbox_multiple”>
<input
type=“checkbox”
id=“select-all-users”
checked={allUsersCheckedForPage}
readOnly
/>
<label
htmlFor=“select-all-users”
onClick={selectAllUsersOnPage}
className=“custom-checkbox__label”
/>
</div>
), [allUsersCheckedForPage, selectAllUsersOnPage]);
const checkedRoles = useMemo(() => Array.from(new Set(Object.values(selection).map(u => u && u.role.name).filter(Boolean))), [selection]);
const changeRoleForAllUsers = useCallback(() => (
<div>
<SelectRole
value={roleForAll}
options={currentUser.roles}
onChange={r => handleUpdatingRoleForSelection(r)}
defaultPlaceholder=“SELECT TEAM”
disabled={checkedRoles.length !== 1}
showAttention={false}
/>
</div>
), [checkedRoles.length, currentUser.roles, handleUpdatingRoleForSelection, roleForAll]);
useEffect(() => {
setRoleForAll({});
}, [checkedRoles]); // clear select for selection
const handleKpi = useCallback((data = ‘’) => {
if (!data) {
return null;
}
const [value, target] = data.split(‘:’);
return (
<div className=“kpi-tooltip-container”>
<div className=“kpi-tooltip-container__row”>
<span>Current:</span>
<span>{`${roundIndicator(value)}%`}</span>
</div>
<div className=“kpi-tooltip-container__row”>
<span>Target:</span>
<span>{`${roundIndicator(target)}%`}</span>
</div>
</div>
);
}, []);
const columns = React.useMemo(
() => [
{
Header: ' ’,
id: ‘selection’,
Cell: ({ row }) => (
<div>
<CustomCheckbox
onChange={() => { setSelection({ ...selection, [row.original.email]: selection[row.original.email] ? null : row.original }); }}
value={row.original.email}
checked={!!selection[row.original.email]}
id={`user_${row.original.id}`}
/>
</div>
),
},
{
Header: ‘ID’,
accessor: ‘id’,
},
{
Header: ‘Email’,
accessor: ‘email’,
Cell: props => (
<CopyboardText text={props.value} />
),
},
{
Header: ‘Telegram’,
accessor: ‘telegramNick’,
Cell: props => (
<CopyboardText text={props.value} />
),
},
{
Header: ‘Name’,
accessor: ‘name’,
Cell: props => (
<CopyboardText text={props.value} />
),
},
{
Header: ‘KPI’,
accessor: ‘kpi’,
Cell: () => {
const value = getRandomArbitrary(-500, 500);
const target = 13;
return (
// TODO replace with kpi from api
<div
data-tip={`${value}:${target}`}
data-for=“kpiTooltip”
>
<Kpi
value={value}
/>
</div>
);
},
},
{
Header: ‘Team’,
accessor: ‘role’,
Cell: ({ value: { name: label, id: value }, row: { original: { id } } }) => (
<SelectRole
value={{ label, value }}
onChange={({ label: newLabel, value: roleId }) => handleUpdatingRole({
id,
roleId,
prevLabel: label,
label: newLabel,
})}
options={currentUser.roles}
/>
),
},
],
[currentUser.roles, handleUpdatingRole, selection],
);
const fetchData = React.useCallback((params) => {
dispatch(getUsersRequest(params));
}, [dispatch]);
const closeModal = useCallback(() => {
if (isShowModalUser) {
closeModalUser();
}
if (isShowModalSelection) {
closeModalSelection();
}
}, [closeModalSelection, closeModalUser, isShowModalSelection, isShowModalUser]);
const confirmUpdatingRoles = useCallback(() => {
if (isShowModalUser) {
confirmUpdatingRole();
}
if (isShowModalSelection) {
confirmUpdatingRoleForSelection();
}
}, [confirmUpdatingRole, confirmUpdatingRoleForSelection, isShowModalSelection, isShowModalUser]);
return (
<div className=“users-container”>
<div className=“users-block”>
<SearchAdminInput
onChange={handleChangeInput}
className=“users-block__search”
placeholder=“Search by ID, email, telegram, name, team, analytics ”
/>
<TableUsers
columns={columns}
data={users}
fetchData={fetchData}
pageCount={pageCount}
selection={selection}
search={search}
selectAllButton={selectAllButton} // component
resetSelectAll={resetSelectAll}
changeRoleForAllUsers={changeRoleForAllUsers}
/>
<ConfirmationModal
show={isShowModalUser || isShowModalSelection}
handleClose={closeModal}
>
<div className=“confirmation-modal__container”>
<div className=“confirmation-modal__header”>
{`Изменение команды ${isShowModalUser ? ‘пользователя’ : ‘пользователей‘}`}
</div>
<div className=“confirmation-modal__action-info”>
<span>{dataToUpdate.prevLabel}</span>
<img className=“confirmation-modal__action-arrow” src=“/images/arrow-long-left-grey.svg” alt=“arrow” />
<span>{dataToUpdate.label}</span>
</div>
<div className=“confirmation-modal__help”>
<span>
{`${isShowModalUser ? ‘Пользователь будет зачислен ’ : ‘Пользователи будут зачислены ‘} в ${dataToUpdate.label}.`}
</span>
Тут можно написать какой-то поясняющий, но короткий текст.
</div>
<div className=“confirmation-modal__buttons”>
<button className=“button button_blue button_big” onClick={confirmUpdatingRoles}>
{`${isShowModalUser ? ‘перевести юзера’ : ‘перевести юзеров’}`}
</button>
<button className=“button confirmation-modal__button-cancel” onClick={closeModal}>отмена</button>
</div>
</div>
</ConfirmationModal>
</div>
<ReactTooltip
id=“kpiTooltip”
type=“info”
className=“kpi-tooltip”
data-event=“mousein click”
data-event-off=“mouseout click”
delayHide={500}
delayUpdate={500}
delayShow={500}
getContent={handleKpi}
place=“bottom”
/>
</div>
);
}
export default memo(Users);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment