397 lines
12 KiB
JavaScript
397 lines
12 KiB
JavaScript
import { useState, useEffect, useCallback } from 'react';
|
||
import { PageContainer } from '../../StyledForPage';
|
||
import { HeaderSwitch } from '../../../components/HeaderMenu/HeaderSwitch';
|
||
import { SwitchUserSsp } from '../../../components/AdminPanel/SwitchUserSsp';
|
||
import { ROLES_NAME_ID } from '../../../constants';
|
||
import { useAuth } from '../../../app/context/AuthProvider';
|
||
import {
|
||
Box,
|
||
TextField,
|
||
Autocomplete,
|
||
FormLabel,
|
||
Button,
|
||
FormControlLabel,
|
||
Switch,
|
||
} 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 SspTable from './SspTable';
|
||
import { ModalAddSsp } from './ModalAddSsp';
|
||
import { ModalChangeUsersInSsp } from './ModalChangeUsersInSsp';
|
||
import { ModalEditSsp } from './ModalEditSsp';
|
||
import { PrimaryButton } from '../../../components/common/Buttons/Buttons';
|
||
import { WhitePlus } from '../../../components/common/icons/icons';
|
||
|
||
const SspsPage = () => {
|
||
const { user } = useAuth();
|
||
const [ssps, setSsps] = useState([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [sspForChangeUsers, setSspForChangeUsers] = useState(null);
|
||
const [needUpdateCountUsers, setNeedUpdateCountUsers] = useState(false);
|
||
const [filterString, setFilterString] = useState('');
|
||
const [filterType, setFilterType] = useState(null);
|
||
const [filterStatus, setFilterStatus] = useState(0);
|
||
|
||
const [openModalUsersinSspChange, setOpenModalUsersinSspChange] =
|
||
useState(false);
|
||
const [openModalEdit, setOpenModalEdit] = useState(false);
|
||
const [sspForEdit, setSspForEdit] = useState(null);
|
||
const [openModalAdd, setOpenModalAdd] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const loadSsps = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const data = await SspApi.getAll({ load_users_count: true });
|
||
if (!data.success) {
|
||
toast.error(
|
||
'Ошибка получения ССП/Региональные филиалы ' + data.message,
|
||
);
|
||
return;
|
||
}
|
||
setSsps(data.result.sort((a, b) => a.id - b.id));
|
||
} catch {
|
||
toast.error('Ошибка получения ССП/Региональные филиалы ');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
loadSsps();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (openModalUsersinSspChange && openModalAdd) return;
|
||
setTimeout(() => {
|
||
setNeedUpdateCountUsers(true);
|
||
}, 500);
|
||
}, [openModalUsersinSspChange, openModalAdd]);
|
||
|
||
const handleOpenModalUsersInSspChange = useCallback(
|
||
(sspId) => {
|
||
setOpenModalUsersinSspChange(true);
|
||
setSspForChangeUsers(ssps.find((ssp) => ssp.id == sspId));
|
||
},
|
||
[ssps],
|
||
);
|
||
|
||
const handleCloseModalUsersInSspChange = () => {
|
||
setOpenModalUsersinSspChange(false);
|
||
setSspForChangeUsers(null);
|
||
};
|
||
|
||
const handleChangeStatus = (ssp) =>
|
||
SspApi.deleteSsp(ssp.id)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error(
|
||
'Не удалось отправить в архив ' + (data.message || ''),
|
||
);
|
||
throw new Error(data.message || 'archive_failed');
|
||
}
|
||
toast.success('ССП/РФ перенесены в архив');
|
||
setSsps((prev) =>
|
||
prev
|
||
.map((s) =>
|
||
s.id === ssp.id ? { ...s, is_active: false } : s,
|
||
)
|
||
.sort((a, b) => a.id - b.id),
|
||
);
|
||
})
|
||
.catch((error) => {
|
||
if (error?.response) {
|
||
const msg =
|
||
error.response.data?.message || error.response.data?.detail;
|
||
toast.error(msg || 'Не удалось отправить в архив');
|
||
}
|
||
throw error;
|
||
});
|
||
|
||
const updateUser = (user) => {
|
||
UsersApi.update(user.id, user)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error('Ошибка обновления пользователя ' + data.message);
|
||
}
|
||
})
|
||
.catch(() => {
|
||
toast.error('Ошибка обновления пользователя ');
|
||
});
|
||
};
|
||
|
||
const adjustSspUsersCount = (sspId, delta) => {
|
||
if (!delta) return;
|
||
setSsps((prev) =>
|
||
prev.map((s) =>
|
||
s.id === sspId
|
||
? { ...s, users_count: (s.users_count ?? 0) + delta }
|
||
: s,
|
||
),
|
||
);
|
||
};
|
||
|
||
const updateUserManySsp = (user, sspIds) =>
|
||
SspApi.putManySsps(user.id, sspIds)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error(data?.message || 'Ошибка добавления пользователя');
|
||
return false;
|
||
}
|
||
return true;
|
||
})
|
||
.catch((error) => {
|
||
const msg =
|
||
error?.response?.data?.message ||
|
||
error?.response?.data?.detail;
|
||
toast.error(msg || 'Ошибка добавления пользователя');
|
||
return false;
|
||
});
|
||
|
||
const deleteUserManySsp = (user, sspIds) =>
|
||
SspApi.deleteManySsps(user.id, sspIds)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error('Ошибка обновления пользователя ' + data.message);
|
||
return false;
|
||
}
|
||
return true;
|
||
})
|
||
.catch(() => {
|
||
toast.error('Ошибка обновления пользователя ');
|
||
return false;
|
||
});
|
||
|
||
const handleUpdateUsers = async (ssp, usersDataForUpdate) => {
|
||
let added = 0;
|
||
let removed = 0;
|
||
|
||
for (const user of usersDataForUpdate.update) {
|
||
if (await updateUserManySsp(user, { ssp_ids: [ssp.id] })) {
|
||
added += 1;
|
||
}
|
||
}
|
||
for (const user of usersDataForUpdate.delete) {
|
||
if (await deleteUserManySsp(user, { ssp_ids: [ssp.id] })) {
|
||
removed += 1;
|
||
}
|
||
}
|
||
|
||
adjustSspUsersCount(ssp.id, added - removed);
|
||
};
|
||
|
||
const handleEditSsp = (ssp) => {
|
||
setOpenModalEdit(true);
|
||
setSspForEdit(ssp);
|
||
};
|
||
|
||
const handleUpdateSsp = (ssp) => {
|
||
SspApi.updateSsp(ssp.id, ssp)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error('Не удалось обновить данные ' + data.message);
|
||
return;
|
||
}
|
||
setSsps((prev) => {
|
||
const newSsps = [...prev.filter((s) => s.id !== ssp.id), ssp].sort(
|
||
(a, b) => a.id - b.id,
|
||
);
|
||
return newSsps;
|
||
});
|
||
})
|
||
.catch(() => {
|
||
toast.error('Не удалось обновить данные ');
|
||
});
|
||
};
|
||
|
||
const handleCloseModalEdit = () => {
|
||
setOpenModalEdit(false);
|
||
setSspForEdit(null);
|
||
};
|
||
|
||
const handleAddSsp = () => {
|
||
setOpenModalAdd(true);
|
||
};
|
||
|
||
const handleCloseAddSsp = () => {
|
||
setOpenModalAdd(false);
|
||
};
|
||
|
||
const handleSaveNewSsp = (ssp, usersData) => {
|
||
SspApi.createSsp(ssp)
|
||
.then((data) => {
|
||
if (!data.success) {
|
||
toast.error('Не удалось создать ССП/Рег. филиал ' + data.message);
|
||
return;
|
||
}
|
||
const newSsp = { ...data.result, users_count: data.result.users_count ?? 0 };
|
||
setSsps((prev) => [...prev, newSsp].sort((a, b) => a.id - b.id));
|
||
handleUpdateUsers(newSsp, usersData);
|
||
})
|
||
.catch(() => {
|
||
toast.error('Не удалось создать ССП/Рег. филиал ');
|
||
});
|
||
};
|
||
|
||
if (!user || user.role_id != ROLES_NAME_ID.admin) return;
|
||
return (
|
||
<>
|
||
<PageContainer>
|
||
<HeaderSwitch></HeaderSwitch>
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||
<SwitchUserSsp></SwitchUserSsp>
|
||
<Box sx={{ display: 'flex', gap: '1rem', alignItems: 'end' }}>
|
||
<PrimaryButton onClick={handleAddSsp} startIcon={<WhitePlus />}>
|
||
Добавить
|
||
</PrimaryButton>
|
||
</Box>
|
||
</Box>
|
||
<Box sx={{ display: 'flex', gap: '1rem', alignItems: 'end' }}>
|
||
<SearchComponent
|
||
placeholder="Поиск по ССП/Рег. филиалам..."
|
||
onChange={setFilterString}
|
||
sx={{ maxWidth: '300px' }}
|
||
/>
|
||
<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: 1, text: 'ССП' },
|
||
{ id: 0, text: 'Рег. филиал' },
|
||
]}
|
||
noOptionsText="Не найдено"
|
||
getOptionLabel={(option) => option.text}
|
||
value={filterType}
|
||
onChange={(event, newValue) => {
|
||
setFilterType(newValue);
|
||
}}
|
||
sx={{ height: '2rem', minWidth: '20.25rem' }}
|
||
renderInput={(params) => (
|
||
<TextField
|
||
{...params}
|
||
placeholder="Все"
|
||
sx={{
|
||
height: '2rem',
|
||
width: '20.25rem',
|
||
'& .MuiOutlinedInput-root': {
|
||
height: '2rem',
|
||
'& fieldset': {
|
||
borderRadius: '0.5rem',
|
||
borderColor: 'rgba(0,0,0,0.1)',
|
||
},
|
||
},
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
</Box>
|
||
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
height: '2rem',
|
||
gap: '1rem',
|
||
}}
|
||
>
|
||
<FormControlLabel
|
||
control={
|
||
<Switch
|
||
checked={!!filterStatus}
|
||
onChange={(e) => setFilterStatus(e.target.checked)}
|
||
size="small"
|
||
sx={{
|
||
height: 'max-content',
|
||
width: 'max-content',
|
||
'& .MuiSwitch-switchBase': {
|
||
padding: '0.375rem',
|
||
'&.Mui-checked': {
|
||
transform: 'translateX(.65rem)',
|
||
color: 'white',
|
||
'& + .MuiSwitch-track': {
|
||
backgroundColor: '#258141',
|
||
opacity: 1,
|
||
},
|
||
'& .MuiSwitch-thumb': {
|
||
width: '0.75rem',
|
||
height: '0.75rem',
|
||
},
|
||
},
|
||
'& .MuiSwitch-thumb': {
|
||
width: '0.75rem',
|
||
height: '0.75rem',
|
||
boxShadow: 'none',
|
||
},
|
||
},
|
||
'& .MuiSwitch-track': {
|
||
backgroundColor: '#ccc',
|
||
opacity: 1,
|
||
borderRadius: '0.75rem',
|
||
height: '1rem',
|
||
width: '1.75rem',
|
||
},
|
||
padding: '0.225rem',
|
||
}}
|
||
/>
|
||
}
|
||
sx={{ margin: 0 }}
|
||
/>
|
||
<FormLabel
|
||
sx={{
|
||
fontWeight: '400',
|
||
fontSize: '0.75rem',
|
||
color: '#4a5565',
|
||
margin: '0',
|
||
}}
|
||
>
|
||
Показать архивные
|
||
</FormLabel>
|
||
</Box>
|
||
</Box>
|
||
<SspTable
|
||
data={ssps}
|
||
loading={loading}
|
||
onUsersInSspChange={handleOpenModalUsersInSspChange}
|
||
onStatusChange={handleChangeStatus}
|
||
onEdit={handleEditSsp}
|
||
filterString={filterString}
|
||
filterStatus={filterStatus}
|
||
filterType={filterType}
|
||
/>
|
||
</PageContainer>
|
||
<ModalChangeUsersInSsp
|
||
open={openModalUsersinSspChange}
|
||
onClose={handleCloseModalUsersInSspChange}
|
||
ssp={sspForChangeUsers}
|
||
onEdit={handleUpdateUsers}
|
||
/>
|
||
<ModalEditSsp
|
||
open={openModalEdit}
|
||
onClose={handleCloseModalEdit}
|
||
ssp={sspForEdit}
|
||
onEdit={handleUpdateSsp}
|
||
/>
|
||
<ModalAddSsp
|
||
open={openModalAdd}
|
||
onClose={handleCloseAddSsp}
|
||
onSave={handleSaveNewSsp}
|
||
/>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default SspsPage;
|