feat: Добавлена админ-панель и API пользователей
Добавлены компоненты для админ-панели и API для управления пользователями.
This commit is contained in:
parent
49e4e2f3f1
commit
b8b57e451b
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<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="57x57" href="/favicons/favicon-57x57.png">
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/favicon-60x60.png">
|
<link rel="apple-touch-icon" sizes="60x60" href="/favicons/favicon-60x60.png">
|
||||||
|
|||||||
@ -7,6 +7,11 @@ export const usersApi = createApi({
|
|||||||
baseQuery: baseQueryWithAuth,
|
baseQuery: baseQueryWithAuth,
|
||||||
tagTypes: ['User'],
|
tagTypes: ['User'],
|
||||||
endpoints: (builder) => ({
|
endpoints: (builder) => ({
|
||||||
|
getAllUsers: builder.query({
|
||||||
|
query: () => '/users/',
|
||||||
|
providesTags: ['User'],
|
||||||
|
refetchOnMountOrArgChange: 5,
|
||||||
|
}),
|
||||||
getAuthenticatedUserData: builder.query({
|
getAuthenticatedUserData: builder.query({
|
||||||
query: () => '/users/my-data/',
|
query: () => '/users/my-data/',
|
||||||
providesTags: ['User'],
|
providesTags: ['User'],
|
||||||
@ -34,4 +39,5 @@ export const {
|
|||||||
useGetAuthenticatedUserDataQuery,
|
useGetAuthenticatedUserDataQuery,
|
||||||
useChangePasswordMutation,
|
useChangePasswordMutation,
|
||||||
useUpdateUserMutation,
|
useUpdateUserMutation,
|
||||||
|
useGetAllUsersQuery,
|
||||||
} = usersApi;
|
} = usersApi;
|
||||||
@ -1,10 +1,30 @@
|
|||||||
import { Navigate, Outlet } from "react-router-dom";
|
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 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="/" />;
|
return <Navigate to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import IssuesPage from "../Components/Pages/IssuesPage/IssuesPage.jsx";
|
|||||||
import AppointmentsPage from "../Components/Pages/AppointmentsPage/AppointmentsPage.jsx";
|
import AppointmentsPage from "../Components/Pages/AppointmentsPage/AppointmentsPage.jsx";
|
||||||
import ProfilePage from "../Components/Pages/ProfilePage/ProfilePage.jsx";
|
import ProfilePage from "../Components/Pages/ProfilePage/ProfilePage.jsx";
|
||||||
import AdminRoute from "./AdminRoute.jsx";
|
import AdminRoute from "./AdminRoute.jsx";
|
||||||
|
import AdminPage from "../Components/Pages/AdminPage/AdminPage.jsx";
|
||||||
|
|
||||||
|
|
||||||
const AppRouter = () => (
|
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 HomePage = () => {
|
||||||
const homePageData = useHomePage();
|
const homePageData = useHomePage();
|
||||||
const homePageUI = useHomePageUI(homePageData.appointments, homePageData.scheduledAppointments, homePageData.patients);
|
const homePageUI = useHomePageUI(homePageData.appointments, homePageData.scheduledAppointments, homePageData.patients);
|
||||||
// const selectedScheduledAppointment = useSelector((state) => state.appointmentsUI.selectedScheduledAppointment);
|
|
||||||
|
|
||||||
if (homePageData.isError) {
|
if (homePageData.isError) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import dayjs from "dayjs";
|
|||||||
import isBetween from "dayjs/plugin/isBetween";
|
import isBetween from "dayjs/plugin/isBetween";
|
||||||
import {useSelector} from "react-redux"; // Import isBetween plugin
|
import {useSelector} from "react-redux"; // Import isBetween plugin
|
||||||
|
|
||||||
dayjs.extend(isBetween); // Extend dayjs with isBetween
|
dayjs.extend(isBetween);
|
||||||
|
|
||||||
const { useBreakpoint } = Grid;
|
const { useBreakpoint } = Grid;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Button, Card, Col, Form, Input, Modal, Row, Space, Typography, Result} from "antd";
|
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 LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||||
import useProfilePage from "./useProfilePage.js";
|
import useProfilePage from "./useProfilePage.js";
|
||||||
import useProfilePageUI from "./useProfilePageUI.js";
|
import useProfilePageUI from "./useProfilePageUI.js";
|
||||||
@ -44,6 +44,9 @@ const ProfilePage = () => {
|
|||||||
<LoadingIndicator/>
|
<LoadingIndicator/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<Typography.Title level={1}>
|
||||||
|
<UserOutlined/> Главная страница
|
||||||
|
</Typography.Title>
|
||||||
<Typography.Title level={1}>Профиль</Typography.Title>
|
<Typography.Title level={1}>Профиль</Typography.Title>
|
||||||
<Card style={cardStyle}>
|
<Card style={cardStyle}>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user