Created
March 3, 2021 15:03
-
-
Save RuslanSevrukov/b169d34ba5bb58fb9e8076212dccca20 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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