367 lines
12 KiB
JavaScript
367 lines
12 KiB
JavaScript
import { useState, useEffect } from 'react';
|
||
import { PageContainer } from '../../StyledForPage';
|
||
import { HeaderSwitch } from '../../../components/HeaderMenu/HeaderSwitch';
|
||
import { SwitchUserSsp } from '../../../components/AdminPanel/SwitchUserSsp';
|
||
import { ROLES_ID_RUSSIAN_NAME_ARRAY, ROLES_NAME_ID } from '../../../constants';
|
||
import { useAuth } from '../../../app/context/AuthProvider';
|
||
import { Box, TextField, Autocomplete, FormLabel } from '@mui/material';
|
||
import SearchComponent from '../../../components/common/SearchComponent';
|
||
import { toast } from 'react-toastify';
|
||
import { SspApi } from '../../../api/ssp';
|
||
import { UsersApi } from '../../../api/users';
|
||
import UserTable from './UserTable/UserTable';
|
||
import { ROLES_ID_RUSSIAN_NAME } from '../../../constants';
|
||
import { ModalEditUserSsp } from './ModalEditUserSsp';
|
||
import { ModalAddUsers } from './ModalAddUsers';
|
||
import UsersActionBar from './UsersActionBar';
|
||
import { PrimaryButton } from '../../../components/common/Buttons/Buttons';
|
||
import { WhitePlus } from '../../../components/common/icons/icons';
|
||
|
||
const UsersPage = () => {
|
||
const { user } = useAuth();
|
||
const [deps, setDeps] = useState([]);
|
||
const [roles, setRoles] = useState([]);
|
||
const [dep, setDep] = useState(null);
|
||
const [role, setRole] = useState(null);
|
||
const [users, setUsers] = useState([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [filterString, setFilterString] = useState('');
|
||
const [editableUser, setEditableUser] = useState(null);
|
||
const [selectedUsersId, setSelectedUsersId] = useState(new Set());
|
||
const [openEditUsers, setOpenEditUserSsp] = useState(false);
|
||
const [openModalAddUsers, setOpenModalAddUser] = useState(false);
|
||
|
||
const loadUsers = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const data = await UsersApi.getAll();
|
||
if (!data.success) {
|
||
toast.error('Ошибка получения пользователей ' + data.message);
|
||
return;
|
||
}
|
||
setUsers(data.result.sort((a, b) => a.id - b.id));
|
||
} catch {
|
||
toast.error('Ошибка получения пользователей');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
setRoles(ROLES_ID_RUSSIAN_NAME_ARRAY);
|
||
|
||
SspApi.getAll().then((data) => {
|
||
if (!data.success) {
|
||
toast.error(
|
||
'Ошибка получения ССП/Региональные филиалы ' + data.message,
|
||
);
|
||
return;
|
||
}
|
||
const activeDeps = data.result.filter((v) => v.is_active);
|
||
setDeps(activeDeps);
|
||
});
|
||
|
||
loadUsers();
|
||
}, []);
|
||
|
||
const handleEditUserSsp = (user) => {
|
||
setEditableUser(user);
|
||
setOpenEditUserSsp(true);
|
||
};
|
||
|
||
const handleSaveEditableUser = async (user, depsData = null) => {
|
||
try {
|
||
if (depsData !== null) {
|
||
if (depsData.delete.length > 0) {
|
||
try {
|
||
const deleteResult = await SspApi.deleteManySsps(user.id, {
|
||
user_id: user.id,
|
||
ssp_ids: depsData.delete,
|
||
});
|
||
|
||
if (deleteResult.success) {
|
||
toast.success('Подразделение у пользователя удалено');
|
||
} else {
|
||
toast.error('Ошибка удаления подразделения у пользователя');
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
toast.error('Ошибка удаления подразделения у пользователя');
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (depsData.update.length > 0) {
|
||
try {
|
||
const updateResult = await SspApi.putManySsps(user.id, {
|
||
ssp_ids: depsData.update,
|
||
});
|
||
|
||
if (updateResult.success) {
|
||
toast.success('Подразделение у пользователя добавлено');
|
||
} else {
|
||
toast.error('Ошибка добавления подразделения у пользователя');
|
||
}
|
||
} catch (error) {
|
||
toast.error('Ошибка добавления подразделения у пользователя');
|
||
}
|
||
}
|
||
}
|
||
const data = await UsersApi.update(user.id, { ...user, load_orgs: true });
|
||
|
||
if (!data.success) {
|
||
toast.error('Не удалось обновить данные', data.message);
|
||
return;
|
||
}
|
||
|
||
const updatedUser = data.result;
|
||
if (updatedUser?.id) {
|
||
setUsers((prev) =>
|
||
prev
|
||
.map((u) => (u.id === updatedUser.id ? updatedUser : u))
|
||
.sort((a, b) => a.id - b.id),
|
||
);
|
||
}
|
||
} catch (error) {
|
||
toast.error(error?.detail || 'Не удалось обновить данные');
|
||
}
|
||
};
|
||
|
||
const handleUserAdded = (newUser) => {
|
||
if (!newUser?.id) return;
|
||
setUsers((prev) => {
|
||
if (prev.some((u) => u.id === newUser.id)) return prev;
|
||
return [...prev, newUser].sort((a, b) => a.id - b.id);
|
||
});
|
||
};
|
||
|
||
const handleOpenModalAddUsers = () => {
|
||
setOpenModalAddUser(true);
|
||
};
|
||
|
||
const handleCloseModalAddUsers = () => {
|
||
setOpenModalAddUser(false);
|
||
};
|
||
|
||
const handleSelectedUser = (users) => {
|
||
setSelectedUsersId(users);
|
||
};
|
||
|
||
const handleDeleteSelectedUsers = () => {
|
||
for (const userId of selectedUsersId) {
|
||
handleDeleteUser(userId);
|
||
}
|
||
};
|
||
|
||
const handleDeleteUser = (userId) => {
|
||
UsersApi.delete(userId)
|
||
.then((data) => {
|
||
if (data.success) {
|
||
setUsers((prev) => prev.filter((u) => u.id != userId));
|
||
} else {
|
||
toast.error('Ошибка удаления пользователя ' + data.message);
|
||
}
|
||
})
|
||
.catch(() => {
|
||
toast.error('Ошибка удаления пользователя ');
|
||
});
|
||
};
|
||
|
||
const handleUsersChange = (changeData) => {
|
||
const { sspId, roleId } = changeData;
|
||
const selectedUsers = users.filter((u) => selectedUsersId.has(u.id));
|
||
for (const user of selectedUsers) {
|
||
let depsData;
|
||
if (roleId) {
|
||
user.role_id = roleId;
|
||
}
|
||
if (sspId) {
|
||
depsData = {
|
||
update: [sspId],
|
||
delete:
|
||
user.role_id === ROLES_NAME_ID.executor_rf &&
|
||
user.org_units?.[0]?.id !== undefined
|
||
? [user.org_units[0].id]
|
||
: [],
|
||
};
|
||
user.ssp_id = sspId;
|
||
}
|
||
handleSaveEditableUser(user, depsData);
|
||
}
|
||
};
|
||
|
||
const handleUnselectUsers = () => {
|
||
setSelectedUsersId(new Set());
|
||
};
|
||
|
||
if (!user || user.role_id != ROLES_NAME_ID.admin) return;
|
||
|
||
return (
|
||
<>
|
||
<PageContainer>
|
||
<HeaderSwitch />
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||
<SwitchUserSsp />
|
||
<Box sx={{ display: 'flex', gap: '1rem', alignItems: 'end' }}>
|
||
<PrimaryButton
|
||
onClick={handleOpenModalAddUsers}
|
||
sx={{ marginLeft: '2rem', maxWidth: 'max-content' }}
|
||
startIcon={<WhitePlus />}
|
||
>
|
||
Добавить
|
||
</PrimaryButton>
|
||
</Box>
|
||
</Box>
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||
<Box sx={{ display: 'flex', gap: '1rem', alignItems: 'end' }}>
|
||
<SearchComponent
|
||
placeholder="Поиск по пользователям..."
|
||
onChange={setFilterString}
|
||
height="2.5rem"
|
||
/>
|
||
<Box
|
||
sx={{ display: 'flex', flexDirection: 'column', gap: '0.125rem' }}
|
||
>
|
||
<FormLabel
|
||
sx={{
|
||
fontWeight: '400',
|
||
fontSize: '0.75rem',
|
||
color: '#4a5565',
|
||
margin: '0',
|
||
}}
|
||
>
|
||
Роли
|
||
</FormLabel>
|
||
<Autocomplete
|
||
size="small"
|
||
options={roles}
|
||
noOptionsText="Не найдено"
|
||
getOptionLabel={(option) =>
|
||
ROLES_ID_RUSSIAN_NAME[option.id] || option.name || ''
|
||
}
|
||
value={role ? roles.find((f) => f.id === role.id) : null}
|
||
onChange={(event, newValue) => {
|
||
setRole(
|
||
newValue ? roles.find((f) => f.id === newValue.id) : null,
|
||
);
|
||
}}
|
||
sx={{ height: '2.5rem', minWidth: '20.25rem' }}
|
||
renderInput={(params) => (
|
||
<TextField
|
||
{...params}
|
||
placeholder="Все"
|
||
sx={{
|
||
height: '2.5rem',
|
||
width: '20.25rem',
|
||
'& .MuiOutlinedInput-root': {
|
||
height: '2.5rem',
|
||
'& fieldset': {
|
||
borderRadius: '0.5rem',
|
||
borderColor: 'rgba(0,0,0,0.1)',
|
||
},
|
||
},
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
</Box>
|
||
<Box
|
||
sx={{ display: 'flex', flexDirection: 'column', gap: '0.125rem' }}
|
||
>
|
||
<FormLabel
|
||
sx={{
|
||
fontWeight: '400',
|
||
fontSize: '0.75rem',
|
||
color: '#4a5565',
|
||
margin: '0',
|
||
}}
|
||
>
|
||
ССП/Региональные филиалы
|
||
</FormLabel>
|
||
<Autocomplete
|
||
size="small"
|
||
options={[{ id: null, title: 'Без ССП' }, ...deps]}
|
||
noOptionsText="Не найдено"
|
||
getOptionLabel={(option) => option.title || option.name || ''}
|
||
value={
|
||
dep
|
||
? dep.id === null
|
||
? { id: null, title: 'Без ССП' }
|
||
: deps.find((f) => f.id === dep.id)
|
||
: null
|
||
}
|
||
onChange={(event, newValue) => {
|
||
setDep(
|
||
newValue
|
||
? newValue.id === null
|
||
? { id: null, title: 'Без ССП' }
|
||
: deps.find((f) => f.id === newValue.id)
|
||
: null,
|
||
);
|
||
}}
|
||
sx={{ height: '2.5rem', minWidth: '11.25rem' }}
|
||
renderInput={(params) => (
|
||
<TextField
|
||
{...params}
|
||
placeholder="Все"
|
||
sx={{
|
||
height: '2.5rem',
|
||
width: '11.25rem',
|
||
'& .MuiOutlinedInput-root': {
|
||
height: '2.5rem',
|
||
'& fieldset': {
|
||
borderRadius: '0.5rem',
|
||
borderColor: 'rgba(0,0,0,0.1)',
|
||
},
|
||
},
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
</Box>
|
||
</Box>
|
||
{selectedUsersId.size > 0 && (
|
||
<UsersActionBar
|
||
countUser={selectedUsersId.size}
|
||
onDelete={handleDeleteSelectedUsers}
|
||
onSave={handleUsersChange}
|
||
onClose={handleUnselectUsers}
|
||
sspOptions={deps}
|
||
/>
|
||
)}
|
||
</Box>
|
||
|
||
<UserTable
|
||
data={users}
|
||
loading={loading}
|
||
filterString={filterString}
|
||
ssp={dep !== null ? dep : null}
|
||
roleId={role !== null ? role.id : ''}
|
||
onEditSsp={handleEditUserSsp}
|
||
onEdit={handleSaveEditableUser}
|
||
onDelete={handleDeleteUser}
|
||
onRoleChange={handleSaveEditableUser}
|
||
onSelectedUsers={handleSelectedUser}
|
||
selectedUsersId={selectedUsersId}
|
||
/>
|
||
</PageContainer>
|
||
<ModalEditUserSsp
|
||
open={openEditUsers}
|
||
onClose={() => {
|
||
setOpenEditUserSsp(false);
|
||
}}
|
||
user={editableUser}
|
||
deps={deps}
|
||
onEdit={handleSaveEditableUser}
|
||
/>
|
||
<ModalAddUsers
|
||
open={openModalAddUsers}
|
||
onClose={handleCloseModalAddUsers}
|
||
sspOptions={deps}
|
||
onAddUser={handleUserAdded}
|
||
/>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default UsersPage; |