397 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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}
onUsersCountChange={adjustSspUsersCount}
/>
<ModalEditSsp
open={openModalEdit}
onClose={handleCloseModalEdit}
ssp={sspForEdit}
onEdit={handleUpdateSsp}
/>
<ModalAddSsp
open={openModalAdd}
onClose={handleCloseAddSsp}
onSave={handleSaveNewSsp}
/>
</>
);
};
export default SspsPage;