feat: Добавлена админ-панель и API пользователей
Добавлены компоненты для админ-панели и API для управления пользователями.
This commit is contained in:
parent
49e4e2f3f1
commit
b8b57e451b
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Линза ➕</title>
|
||||
<title>Visus ➕</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/favicons/favicon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/favicon-60x60.png">
|
||||
|
||||
@ -7,6 +7,11 @@ export const usersApi = createApi({
|
||||
baseQuery: baseQueryWithAuth,
|
||||
tagTypes: ['User'],
|
||||
endpoints: (builder) => ({
|
||||
getAllUsers: builder.query({
|
||||
query: () => '/users/',
|
||||
providesTags: ['User'],
|
||||
refetchOnMountOrArgChange: 5,
|
||||
}),
|
||||
getAuthenticatedUserData: builder.query({
|
||||
query: () => '/users/my-data/',
|
||||
providesTags: ['User'],
|
||||
@ -34,4 +39,5 @@ export const {
|
||||
useGetAuthenticatedUserDataQuery,
|
||||
useChangePasswordMutation,
|
||||
useUpdateUserMutation,
|
||||
useGetAllUsersQuery,
|
||||
} = usersApi;
|
||||
@ -1,10 +1,30 @@
|
||||
import { Navigate, Outlet } from "react-router-dom";
|
||||
import { useSelector } from "react-redux";
|
||||
import {useGetAuthenticatedUserDataQuery} from "../Api/usersApi.js";
|
||||
import LoadingIndicator from "../Components/Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||
import {Alert} from "antd";
|
||||
|
||||
const AdminRoute = () => {
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
const {
|
||||
data: user,
|
||||
isLoading: isUserLoading,
|
||||
isError: isUserError,
|
||||
} = useGetAuthenticatedUserDataQuery(undefined, {
|
||||
pollingInterval: 60000,
|
||||
});
|
||||
|
||||
if (!user || user.role.title !== "Администратор") {
|
||||
if (isUserLoading) {
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
if (isUserError) {
|
||||
return <Alert message="Ошибка загрузки данных пользователя" type="error" showIcon />;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
if (!user.role || user.role.title !== "Администратор") {
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import IssuesPage from "../Components/Pages/IssuesPage/IssuesPage.jsx";
|
||||
import AppointmentsPage from "../Components/Pages/AppointmentsPage/AppointmentsPage.jsx";
|
||||
import ProfilePage from "../Components/Pages/ProfilePage/ProfilePage.jsx";
|
||||
import AdminRoute from "./AdminRoute.jsx";
|
||||
import AdminPage from "../Components/Pages/AdminPage/AdminPage.jsx";
|
||||
|
||||
|
||||
const AppRouter = () => (
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||
import {Typography} from "antd";
|
||||
import useAdminPage from "./useAdminPage.js";
|
||||
import {ControlOutlined} from "@ant-design/icons";
|
||||
import useAdminPageUI from "./useAdminPageUI.js";
|
||||
|
||||
|
||||
const AdminPage = () => {
|
||||
const adminPageData = useAdminPage();
|
||||
const adminPageUI = useAdminPageUI();
|
||||
|
||||
|
||||
return (
|
||||
<div style={adminPageUI.containerStyle}>
|
||||
{adminPageData.isLoading ? (
|
||||
<LoadingIndicator/>
|
||||
) : (
|
||||
<>
|
||||
<Typography.Title level={1}>
|
||||
<ControlOutlined/> Панель администратора
|
||||
</Typography.Title>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default AdminPage;
|
||||
21
web-app/src/Components/Pages/AdminPage/useAdminPage.js
Normal file
21
web-app/src/Components/Pages/AdminPage/useAdminPage.js
Normal file
@ -0,0 +1,21 @@
|
||||
import {useGetAllUsersQuery} from "../../../Api/usersApi.js";
|
||||
|
||||
|
||||
const useAdminPage = () => {
|
||||
|
||||
const {
|
||||
data: users = [],
|
||||
isLoading,
|
||||
isError,
|
||||
} = useGetAllUsersQuery(undefined, {
|
||||
pollingInterval: 10000,
|
||||
});
|
||||
|
||||
return {
|
||||
users,
|
||||
isLoading,
|
||||
isError,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAdminPage;
|
||||
16
web-app/src/Components/Pages/AdminPage/useAdminPageUI.js
Normal file
16
web-app/src/Components/Pages/AdminPage/useAdminPageUI.js
Normal file
@ -0,0 +1,16 @@
|
||||
import {Grid} from "antd";
|
||||
|
||||
|
||||
const {useBreakpoint} = Grid;
|
||||
|
||||
const useAdminPageUI = () => {
|
||||
const screens = useBreakpoint();
|
||||
|
||||
const containerStyle = {padding: screens.xs ? 16 : 24};
|
||||
|
||||
return {
|
||||
containerStyle,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAdminPageUI;
|
||||
@ -32,7 +32,6 @@ ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
|
||||
const HomePage = () => {
|
||||
const homePageData = useHomePage();
|
||||
const homePageUI = useHomePageUI(homePageData.appointments, homePageData.scheduledAppointments, homePageData.patients);
|
||||
// const selectedScheduledAppointment = useSelector((state) => state.appointmentsUI.selectedScheduledAppointment);
|
||||
|
||||
if (homePageData.isError) {
|
||||
return (
|
||||
|
||||
@ -4,7 +4,7 @@ import dayjs from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import {useSelector} from "react-redux"; // Import isBetween plugin
|
||||
|
||||
dayjs.extend(isBetween); // Extend dayjs with isBetween
|
||||
dayjs.extend(isBetween);
|
||||
|
||||
const { useBreakpoint } = Grid;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {Button, Card, Col, Form, Input, Modal, Row, Space, Typography, Result} from "antd";
|
||||
import {EditOutlined} from "@ant-design/icons";
|
||||
import {EditOutlined, UserOutlined} from "@ant-design/icons";
|
||||
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||
import useProfilePage from "./useProfilePage.js";
|
||||
import useProfilePageUI from "./useProfilePageUI.js";
|
||||
@ -44,6 +44,9 @@ const ProfilePage = () => {
|
||||
<LoadingIndicator/>
|
||||
) : (
|
||||
<>
|
||||
<Typography.Title level={1}>
|
||||
<UserOutlined/> Главная страница
|
||||
</Typography.Title>
|
||||
<Typography.Title level={1}>Профиль</Typography.Title>
|
||||
<Card style={cardStyle}>
|
||||
<Row gutter={[16, 16]}>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user