проверка работы gitea
This commit is contained in:
parent
c320437b00
commit
0a14842120
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
@ -22,7 +21,6 @@ def get_url():
|
|||||||
async def run_migrations_online():
|
async def run_migrations_online():
|
||||||
connectable = create_async_engine(get_url(), poolclass=pool.NullPool, future=True)
|
connectable = create_async_engine(get_url(), poolclass=pool.NullPool, future=True)
|
||||||
|
|
||||||
|
|
||||||
async with connectable.connect() as connection:
|
async with connectable.connect() as connection:
|
||||||
await connection.run_sync(do_run_migrations)
|
await connection.run_sync(do_run_migrations)
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from pydantic import BaseModel
|
|||||||
class RegisterEntity(BaseModel):
|
class RegisterEntity(BaseModel):
|
||||||
first_name: str
|
first_name: str
|
||||||
last_name: str
|
last_name: str
|
||||||
patronymic: Optional[str]
|
patronymic: Optional[str] = None
|
||||||
role_id: int
|
role_id: int
|
||||||
login: str
|
login: str
|
||||||
password: str
|
password: str
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Column, Integer, VARCHAR
|
from sqlalchemy import Column, VARCHAR
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from app.domain.models.base import BaseModel
|
from app.domain.models.base import BaseModel
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
@ -12,18 +13,18 @@ from app.domain.models import User
|
|||||||
|
|
||||||
class UsersService:
|
class UsersService:
|
||||||
def __init__(self, db: AsyncSession):
|
def __init__(self, db: AsyncSession):
|
||||||
self.user_repository = UsersRepository(db)
|
self.users_repository = UsersRepository(db)
|
||||||
self.role_repository = RolesRepository(db)
|
self.roles_repository = RolesRepository(db)
|
||||||
|
|
||||||
async def register_user(self, register_entity: RegisterEntity) -> UserEntity:
|
async def register_user(self, register_entity: RegisterEntity) -> Optional[UserEntity]:
|
||||||
role = await self.role_repository.get_by_id(register_entity.role_id)
|
role = await self.roles_repository.get_by_id(register_entity.role_id)
|
||||||
if not role:
|
if not role:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
detail='The role with this ID was not found'
|
detail='The role with this ID was not found'
|
||||||
)
|
)
|
||||||
|
|
||||||
user = await self.user_repository.get_by_login(register_entity.login)
|
user = await self.users_repository.get_by_login(register_entity.login)
|
||||||
if user:
|
if user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
@ -45,7 +46,7 @@ class UsersService:
|
|||||||
)
|
)
|
||||||
user_model.set_password(register_entity.password)
|
user_model.set_password(register_entity.password)
|
||||||
|
|
||||||
created_user = await self.user_repository.create(user_model)
|
created_user = await self.users_repository.create(user_model)
|
||||||
|
|
||||||
return UserEntity(
|
return UserEntity(
|
||||||
id=created_user.id,
|
id=created_user.id,
|
||||||
|
|||||||
27
web-app/src/Api/appointmentsApi.js
Normal file
27
web-app/src/Api/appointmentsApi.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
|
||||||
|
import CONFIG from "../Core/сonfig.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const appointmentsApi = createApi({
|
||||||
|
reducerPath: 'appointmentsApi',
|
||||||
|
baseQuery: fetchBaseQuery({
|
||||||
|
baseUrl: CONFIG.BASE_URL,
|
||||||
|
prepareHeaders: (headers) => {
|
||||||
|
const token = localStorage.getItem('access_token');
|
||||||
|
if (token) headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
tagTypes: ['Appointment'],
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
getAppointments: builder.query({
|
||||||
|
query: () => '/appointments/',
|
||||||
|
providesTags: ['Appointment'],
|
||||||
|
refetchOnMountOrArgChange: 5
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
useGetAppointmentsQuery,
|
||||||
|
} = appointmentsApi;
|
||||||
25
web-app/src/Api/scheduledAppointmentsApi.js
Normal file
25
web-app/src/Api/scheduledAppointmentsApi.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
|
||||||
|
import CONFIG from "../Core/сonfig.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const scheduledAppointmentsApi = createApi({
|
||||||
|
reducerPath: 'scheduledAppointmentsApi',
|
||||||
|
baseQuery: fetchBaseQuery({
|
||||||
|
baseUrl: CONFIG.BASE_URL,
|
||||||
|
prepareHeaders: (headers) => {
|
||||||
|
const token = localStorage.getItem('access_token');
|
||||||
|
if (token) headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
tagTypes: ['ScheduledAppointment'],
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
getScheduledAppointments: builder.query({
|
||||||
|
query: () => `/scheduledAppointments`,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
useGetScheduledAppointmentsQuery,
|
||||||
|
} = scheduledAppointmentsApi;
|
||||||
@ -4,12 +4,19 @@ import {AuthProvider} from "../Hooks/AuthContext.jsx";
|
|||||||
import "/src/Styles/app.css";
|
import "/src/Styles/app.css";
|
||||||
import {Provider} from "react-redux";
|
import {Provider} from "react-redux";
|
||||||
import store from "../Redux/store.js";
|
import store from "../Redux/store.js";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import locale from 'antd/locale/ru_RU';
|
||||||
|
import {ConfigProvider} from "antd";
|
||||||
|
|
||||||
|
dayjs.locale('ru');
|
||||||
|
|
||||||
const App = () => (
|
const App = () => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router>
|
<Router>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
|
<ConfigProvider locale={locale}>
|
||||||
<AppRouter/>
|
<AppRouter/>
|
||||||
|
</ConfigProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</Router>
|
</Router>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import {Routes, Route, Navigate} from "react-router-dom";
|
import {Routes, Route, Navigate} from "react-router-dom";
|
||||||
import PrivateRoute from "../Components/PrivateRoute.jsx";
|
import PrivateRoute from "./PrivateRoute.jsx";
|
||||||
import LoginPage from "../Components/Pages/LoginPage.jsx";
|
import LoginPage from "../Components/Pages/LoginPage/LoginPage.jsx";
|
||||||
import MainLayout from "../Components/Layouts/MainLayout.jsx";
|
import MainLayout from "../Components/Layouts/MainLayout.jsx";
|
||||||
import PatientsPage from "../Components/Pages/PatientsPage/PatientsPage.jsx";
|
import PatientsPage from "../Components/Pages/PatientsPage/PatientsPage.jsx";
|
||||||
import HomePage from "../Components/Pages/HomePage.jsx";
|
import HomePage from "../Components/Pages/HomePage.jsx";
|
||||||
import LensesLayout from "../Components/Layouts/LensesLayout.jsx";
|
import LensesSetsPage from "../Components/Pages/LensesSetsPage/LensesSetsPage.jsx";
|
||||||
import IssuesPage from "../Components/Pages/IssuesPage/IssuesPage.jsx";
|
import IssuesPage from "../Components/Pages/IssuesPage/IssuesPage.jsx";
|
||||||
import AppointmentsLayout from "../Components/Layouts/AppointmentsLayout.jsx";
|
import AppointmentsPage from "../Components/Pages/AppointmentsPage/AppointmentsPage.jsx";
|
||||||
|
|
||||||
|
|
||||||
const AppRouter = () => (
|
const AppRouter = () => (
|
||||||
@ -16,9 +16,9 @@ const AppRouter = () => (
|
|||||||
<Route element={<PrivateRoute/>}>
|
<Route element={<PrivateRoute/>}>
|
||||||
<Route element={<MainLayout/>}>
|
<Route element={<MainLayout/>}>
|
||||||
<Route path={"/Patients"} element={<PatientsPage/>}/>
|
<Route path={"/Patients"} element={<PatientsPage/>}/>
|
||||||
<Route path={"/Lenses"} element={<LensesLayout/>}/>
|
<Route path={"/Lenses"} element={<LensesSetsPage/>}/>
|
||||||
<Route path={"/issues"} element={<IssuesPage/>}/>
|
<Route path={"/issues"} element={<IssuesPage/>}/>
|
||||||
<Route path={"/Appointments"} element={<AppointmentsLayout/>}/>
|
<Route path={"/Appointments"} element={<AppointmentsPage/>}/>
|
||||||
<Route path={"/"} element={<HomePage/>}/>
|
<Route path={"/"} element={<HomePage/>}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {Card, Popconfirm, Tooltip} from "antd";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
|
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import LensViewModal from "../Pages/LensesPage/Components/LensViewModal/LensViewModal.jsx";
|
import LensViewModal from "../Pages/LensesSetsPage/Components/LensesTab/Components/LensViewModal/LensViewModal.jsx";
|
||||||
import {LensPropType} from "../../Types/lensPropType.js";
|
import {LensPropType} from "../../Types/lensPropType.js";
|
||||||
|
|
||||||
const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {
|
const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {
|
||||||
|
|||||||
@ -1,166 +0,0 @@
|
|||||||
import {useEffect, useState} from "react";
|
|
||||||
import {Button, Grid, Tabs, Typography} from "antd";
|
|
||||||
import {Splitter} from "antd";
|
|
||||||
import {
|
|
||||||
CalendarOutlined, TableOutlined, MenuFoldOutlined, MenuUnfoldOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import AppointmentsCalendarPage from "../Pages/AppointmentsCalendarPage.jsx";
|
|
||||||
import AppointmentsTablePage from "../Pages/AppointmentsTablePage.jsx";
|
|
||||||
import getAllAppointments from "../../old_api/appointments/getAllAppointments.js";
|
|
||||||
import getAllScheduledAppointments from "../../old_api/scheduled_appointments/getAllScheduledAppointments.js";
|
|
||||||
import {useAuth} from "../../Hooks/AuthContext.jsx";
|
|
||||||
import LoadingIndicator from "../Widgets/LoadingIndicator.jsx";
|
|
||||||
import {cacheInfo, getCachedInfo, getCacheTimestamp} from "../../Utils/cachedInfoUtils.js";
|
|
||||||
|
|
||||||
const {useBreakpoint} = Grid;
|
|
||||||
|
|
||||||
const AppointmentsLayout = () => {
|
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
|
||||||
const [siderWidth, setSiderWidth] = useState(250);
|
|
||||||
const [hovered, setHovered] = useState(false);
|
|
||||||
|
|
||||||
const screens = useBreakpoint();
|
|
||||||
const {api} = useAuth();
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
const [appointments, setAppointments] = useState([]);
|
|
||||||
const [scheduledAppointments, setScheduledAppointments] = useState([]);
|
|
||||||
|
|
||||||
const toggleSider = () => setCollapsed(!collapsed);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadDataWithCache();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const interval = setInterval(loadData, 5000);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const loadData = async () => {
|
|
||||||
await fetchAppointments();
|
|
||||||
await fetchScheduledAppointments();
|
|
||||||
setLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadDataWithCache = async () => {
|
|
||||||
await fetchAppointmentsWithCache();
|
|
||||||
await fetchScheduledAppointmentsWithCache();
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchAppointmentsWithCache = async () => {
|
|
||||||
const cachedData = getCachedInfo("appointmentsData");
|
|
||||||
const cacheTimestamp = getCacheTimestamp("appointmentsData");
|
|
||||||
|
|
||||||
if (cachedData && cacheTimestamp && (Date.now() - cacheTimestamp) < 60 * 1000) {
|
|
||||||
setAppointments(cachedData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchAppointments();
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchAppointments = async () => {
|
|
||||||
const data = await getAllAppointments(api);
|
|
||||||
setAppointments(data);
|
|
||||||
cacheInfo("appointmentsData", data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchScheduledAppointmentsWithCache = async () => {
|
|
||||||
const cachedData = getCachedInfo("scheduledAppointmentsData");
|
|
||||||
const cacheTimestamp = getCacheTimestamp("scheduledAppointmentsData");
|
|
||||||
|
|
||||||
if (cachedData && cacheTimestamp && (Date.now() - cacheTimestamp) < 60 * 1000) {
|
|
||||||
setScheduledAppointments(cachedData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchScheduledAppointments();
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchScheduledAppointments = async () => {
|
|
||||||
const data = await getAllScheduledAppointments(api);
|
|
||||||
setScheduledAppointments(data);
|
|
||||||
cacheInfo("scheduledAppointmentsData", data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const items = [{
|
|
||||||
key: "1",
|
|
||||||
label: "Календарь приемов",
|
|
||||||
children: <AppointmentsCalendarPage appointments={appointments} scheduledAppointments={scheduledAppointments}/>,
|
|
||||||
icon: <CalendarOutlined/>,
|
|
||||||
}, {
|
|
||||||
key: "2",
|
|
||||||
label: "Таблица приемов",
|
|
||||||
children: <AppointmentsTablePage/>,
|
|
||||||
icon: <TableOutlined/>,
|
|
||||||
},];
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (<LoadingIndicator/>)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Splitter
|
|
||||||
style={{flex: 1}}
|
|
||||||
min={200}
|
|
||||||
max={400}
|
|
||||||
initial={siderWidth}
|
|
||||||
onChange={setSiderWidth}
|
|
||||||
>
|
|
||||||
<Splitter.Panel style={{padding: 16}} defaultSize="80%" min="25%" max="90%">
|
|
||||||
<Tabs defaultActiveKey="1" items={items}/>
|
|
||||||
</Splitter.Panel>
|
|
||||||
|
|
||||||
{!collapsed && !screens.xs && (
|
|
||||||
<Splitter.Panel
|
|
||||||
style={{
|
|
||||||
padding: "16px", borderLeft: "1px solid #ddd", overflowY: "auto",
|
|
||||||
}}
|
|
||||||
defaultSize="20%"
|
|
||||||
min="20%"
|
|
||||||
max="75%"
|
|
||||||
>
|
|
||||||
<Typography.Title level={3} style={{marginBottom: 36}}>
|
|
||||||
Предстоящие события
|
|
||||||
</Typography.Title>
|
|
||||||
<p>Здесь будут предстоящие приемы...</p>
|
|
||||||
</Splitter.Panel>
|
|
||||||
)}
|
|
||||||
</Splitter>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
right: 0,
|
|
||||||
top: "50%",
|
|
||||||
transform: "translateY(-50%)",
|
|
||||||
transition: "right 0.3s ease",
|
|
||||||
zIndex: 1000,
|
|
||||||
display: screens.xs ? "none" : "block",
|
|
||||||
}}
|
|
||||||
onMouseEnter={() => setHovered(true)}
|
|
||||||
onMouseLeave={() => setHovered(false)}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={toggleSider}
|
|
||||||
icon={collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/>}
|
|
||||||
style={{
|
|
||||||
width: hovered ? 250 : 50,
|
|
||||||
padding: hovered ? "0 20px" : "0",
|
|
||||||
overflow: "hidden",
|
|
||||||
textAlign: "left",
|
|
||||||
transition: "width 0.3s ease, padding 0.3s ease",
|
|
||||||
borderRadius: "4px 0 0 4px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{hovered ? (collapsed ? "Показать предстоящие события" : "Скрыть предстоящие события") : ""}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AppointmentsLayout;
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
import {Calendar, Grid, ConfigProvider, Badge, Modal, Tag, Tooltip} from "antd";
|
|
||||||
import {useState} from "react";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import 'dayjs/locale/ru';
|
|
||||||
import locale from 'antd/es/locale/ru_RU';
|
|
||||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
|
||||||
import PropTypes, {arrayOf} from "prop-types";
|
|
||||||
import CalendarCell from "../Widgets/CalendarCell.jsx";
|
|
||||||
import {AppointmentPropType} from "../../Types/appointmentPropType.js";
|
|
||||||
import {ScheduledAppointmentPropType} from "../../Types/scheduledAppointmentPropType.js";
|
|
||||||
|
|
||||||
const {useBreakpoint} = Grid;
|
|
||||||
|
|
||||||
dayjs.extend(updateLocale);
|
|
||||||
dayjs.updateLocale('ru', {
|
|
||||||
weekStart: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
const AppointmentsCalendarPage = ({appointments, scheduledAppointments}) => {
|
|
||||||
const screens = useBreakpoint();
|
|
||||||
const [selectedDate, setSelectedDate] = useState(dayjs(new Date()));
|
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
|
||||||
const [selectedAppointments, setSelectedAppointments] = useState([]);
|
|
||||||
const [selectedAppointment, setSelectedAppointment] = useState(null);
|
|
||||||
|
|
||||||
const dateCellRender = (value) => {
|
|
||||||
const date = value.format('YYYY-MM-DD');
|
|
||||||
const appointmentsForDate = appointments.filter(app =>
|
|
||||||
dayjs(app.appointment_datetime).format('YYYY-MM-DD') === date
|
|
||||||
);
|
|
||||||
const scheduledForDate = scheduledAppointments.filter(app =>
|
|
||||||
dayjs(app.scheduled_datetime).format('YYYY-MM-DD') === date
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CalendarCell
|
|
||||||
appointments={appointmentsForDate}
|
|
||||||
scheduledAppointments={scheduledForDate}
|
|
||||||
onCellClick={() => {
|
|
||||||
}}
|
|
||||||
onItemClick={() => {
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSelect = (date) => {
|
|
||||||
setSelectedDate(date);
|
|
||||||
const selectedDateStr = date.format('YYYY-MM-DD');
|
|
||||||
const appointmentsForDate = appointments.filter(app =>
|
|
||||||
dayjs(app.appointment_datetime).format('YYYY-MM-DD') === selectedDateStr
|
|
||||||
);
|
|
||||||
const scheduledForDate = scheduledAppointments.filter(app =>
|
|
||||||
dayjs(app.scheduled_datetime).format('YYYY-MM-DD') === selectedDateStr
|
|
||||||
);
|
|
||||||
setSelectedAppointments([...appointmentsForDate, ...scheduledForDate]);
|
|
||||||
setModalVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConfigProvider locale={locale}>
|
|
||||||
<div style={{padding: 20}}>
|
|
||||||
<Calendar
|
|
||||||
fullscreen={!screens.xs}
|
|
||||||
value={selectedDate}
|
|
||||||
onSelect={onSelect}
|
|
||||||
cellRender={dateCellRender}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ConfigProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
AppointmentsCalendarPage.propTypes = {
|
|
||||||
appointments: PropTypes.arrayOf(AppointmentPropType).isRequired,
|
|
||||||
scheduledAppointments: PropTypes.arrayOf(ScheduledAppointmentPropType).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AppointmentsCalendarPage;
|
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
import {Button, Tabs, Typography} from "antd";
|
||||||
|
import {Splitter} from "antd";
|
||||||
|
import {
|
||||||
|
CalendarOutlined, TableOutlined, MenuFoldOutlined, MenuUnfoldOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import AppointmentsCalendarTab from "./Components/AppointmentCalendarTab/AppointmentsCalendarTab.jsx";
|
||||||
|
import AppointmentsTableTab from "./Components/AppointmentTableTab/AppointmentsTableTab.jsx";
|
||||||
|
import useAppointmentsUI from "./useAppointmentsUI.js";
|
||||||
|
|
||||||
|
|
||||||
|
const AppointmentsPage = () => {
|
||||||
|
const appointmentsPageUI = useAppointmentsUI();
|
||||||
|
|
||||||
|
const items = [{
|
||||||
|
key: "1",
|
||||||
|
label: "Календарь приемов",
|
||||||
|
children: <AppointmentsCalendarTab/>,
|
||||||
|
icon: <CalendarOutlined/>,
|
||||||
|
}, {
|
||||||
|
key: "2",
|
||||||
|
label: "Таблица приемов",
|
||||||
|
children: <AppointmentsTableTab/>,
|
||||||
|
icon: <TableOutlined/>,
|
||||||
|
},];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Splitter
|
||||||
|
style={appointmentsPageUI.splitterStyle}
|
||||||
|
min={200}
|
||||||
|
max={400}
|
||||||
|
initial={appointmentsPageUI.siderWidth}
|
||||||
|
onChange={appointmentsPageUI.setSiderWidth}
|
||||||
|
>
|
||||||
|
<Splitter.Panel
|
||||||
|
style={appointmentsPageUI.splitterContentPanelStyle}
|
||||||
|
defaultSize="80%"
|
||||||
|
min="25%"
|
||||||
|
max="90%"
|
||||||
|
>
|
||||||
|
<Tabs defaultActiveKey="1" items={items}/>
|
||||||
|
</Splitter.Panel>
|
||||||
|
|
||||||
|
{appointmentsPageUI.showSplitterPanel && (
|
||||||
|
<Splitter.Panel
|
||||||
|
style={appointmentsPageUI.splitterSiderPanelStyle}
|
||||||
|
defaultSize="20%"
|
||||||
|
min="20%"
|
||||||
|
max="75%"
|
||||||
|
>
|
||||||
|
<Typography.Title level={3} style={appointmentsPageUI.siderTitleStyle}>
|
||||||
|
Предстоящие события
|
||||||
|
</Typography.Title>
|
||||||
|
<p>Здесь будут предстоящие приемы...</p>
|
||||||
|
</Splitter.Panel>
|
||||||
|
)}
|
||||||
|
</Splitter>
|
||||||
|
<div
|
||||||
|
style={appointmentsPageUI.siderButtonContainerStyle}
|
||||||
|
onMouseEnter={appointmentsPageUI.handleHoverSider}
|
||||||
|
onMouseLeave={appointmentsPageUI.handleLeaveSider}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={appointmentsPageUI.handleToggleSider}
|
||||||
|
icon={appointmentsPageUI.collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/>}
|
||||||
|
style={appointmentsPageUI.siderButtonStyle}
|
||||||
|
>
|
||||||
|
{appointmentsPageUI.siderButtonText}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppointmentsPage;
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import {Calendar} from "antd";
|
||||||
|
import 'dayjs/locale/ru';
|
||||||
|
import CalendarCell from "../../../../Widgets/CalendarCell.jsx";
|
||||||
|
import useAppointments from "../../useAppointments.js";
|
||||||
|
import useAppointmentCalendarUI from "./useAppointmentCalendarUI.js";
|
||||||
|
|
||||||
|
|
||||||
|
const AppointmentsCalendarTab = () => {
|
||||||
|
const appointmentsData = useAppointments();
|
||||||
|
const appointmentsCalendarUI = useAppointmentCalendarUI(appointmentsData.appointments, appointmentsData.scheduledAppointments);
|
||||||
|
|
||||||
|
const dateCellRender = (value) => {
|
||||||
|
const appointmentsForDate = appointmentsCalendarUI.getAppointmentsByListAndDate(appointmentsData.appointments, value);
|
||||||
|
const scheduledForDate = appointmentsCalendarUI.getAppointmentsByListAndDate(appointmentsData.scheduledAppointments, value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CalendarCell
|
||||||
|
appointments={appointmentsForDate}
|
||||||
|
scheduledAppointments={scheduledForDate}
|
||||||
|
onCellClick={() => {
|
||||||
|
}}
|
||||||
|
onItemClick={() => {
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={appointmentsCalendarUI.calendarContainerStyle}>
|
||||||
|
<Calendar
|
||||||
|
fullscreen={appointmentsCalendarUI.fullScreenCalendar}
|
||||||
|
value={appointmentsCalendarUI.selectedDate}
|
||||||
|
onSelect={appointmentsCalendarUI.onSelect}
|
||||||
|
cellRender={dateCellRender}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppointmentsCalendarTab;
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {
|
||||||
|
openModal,
|
||||||
|
setSelectedAppointments,
|
||||||
|
setSelectedDate
|
||||||
|
} from "../../../../../Redux/Slices/appointmentsSlice.js";
|
||||||
|
import {Grid} from "antd";
|
||||||
|
|
||||||
|
const {useBreakpoint} = Grid;
|
||||||
|
|
||||||
|
const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const {
|
||||||
|
modalVisible,
|
||||||
|
selectedAppointments,
|
||||||
|
selectedAppointment,
|
||||||
|
} = useSelector(state => state.appointmentsUI);
|
||||||
|
const selectedDate = dayjs(useSelector(state => state.appointmentsUI.selectedDate));
|
||||||
|
|
||||||
|
|
||||||
|
const screens = useBreakpoint();
|
||||||
|
const fullScreenCalendar = !screens.xs;
|
||||||
|
|
||||||
|
const calendarContainerStyle = {padding: 20};
|
||||||
|
|
||||||
|
const onSelect = (date) => {
|
||||||
|
const selectedDateStr = date.format('YYYY-MM-DD');
|
||||||
|
dispatch(setSelectedDate(selectedDateStr));
|
||||||
|
|
||||||
|
console.log(appointments)
|
||||||
|
const appointmentsForDate = appointments.filter(app =>
|
||||||
|
dayjs(app.appointment_datetime).format('YYYY-MM-DD') === selectedDateStr
|
||||||
|
);
|
||||||
|
console.log(appointmentsForDate)
|
||||||
|
|
||||||
|
const scheduledForDate = scheduledAppointments.filter(app =>
|
||||||
|
dayjs(app.scheduled_datetime).format('YYYY-MM-DD') === selectedDateStr
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(setSelectedAppointments([...appointmentsForDate, ...scheduledForDate]));
|
||||||
|
dispatch(openModal());
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAppointmentsByListAndDate = (list, value) => {
|
||||||
|
const date = value.format('YYYY-MM-DD');
|
||||||
|
return list.filter(app =>
|
||||||
|
dayjs(app.appointment_datetime).format('YYYY-MM-DD') === date
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedDate,
|
||||||
|
fullScreenCalendar,
|
||||||
|
calendarContainerStyle,
|
||||||
|
onSelect,
|
||||||
|
getAppointmentsByListAndDate,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useAppointmentCalendarUI;
|
||||||
@ -1,10 +1,8 @@
|
|||||||
import {useAuth} from "../../Hooks/AuthContext.jsx";
|
import {useAuth} from "../../../../../Hooks/AuthContext.jsx";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import getAllAppointments from "../../old_api/appointments/getAllAppointments.js";
|
|
||||||
import {notification} from "antd";
|
|
||||||
|
|
||||||
|
|
||||||
const AppointmentsTablePage = () => {
|
const AppointmentsTableTab = () => {
|
||||||
const {api} = useAuth();
|
const {api} = useAuth();
|
||||||
|
|
||||||
const [appointments, setAppointments] = useState([]);
|
const [appointments, setAppointments] = useState([]);
|
||||||
@ -23,4 +21,4 @@ const AppointmentsTablePage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AppointmentsTablePage;
|
export default AppointmentsTableTab;
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import {useGetAppointmentsQuery} from "../../../Api/appointmentsApi.js";
|
||||||
|
|
||||||
|
|
||||||
|
const useAppointments = () => {
|
||||||
|
const {
|
||||||
|
data: appointments = [],
|
||||||
|
isLoadingAppointments,
|
||||||
|
isErrorAppointments,
|
||||||
|
} = useGetAppointmentsQuery(undefined, {
|
||||||
|
pollingInterval: 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: scheduledAppointments = [],
|
||||||
|
isLoadingScheduledAppointments,
|
||||||
|
isErrorScheduledAppointments,
|
||||||
|
} = useGetAppointmentsQuery(undefined, {
|
||||||
|
pollingInterval: 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
appointments,
|
||||||
|
scheduledAppointments,
|
||||||
|
isLoading: isLoadingAppointments || isLoadingScheduledAppointments,
|
||||||
|
isError: isErrorAppointments || isErrorScheduledAppointments,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useAppointments;
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {Grid} from "antd";
|
||||||
|
import {setHovered, toggleSider} from "../../../Redux/Slices/appointmentsSlice.js";
|
||||||
|
import {useEffect, useMemo} from "react";
|
||||||
|
|
||||||
|
const {useBreakpoint} = Grid;
|
||||||
|
|
||||||
|
const useAppointmentsUI = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const {
|
||||||
|
collapsed,
|
||||||
|
siderWidth,
|
||||||
|
hovered,
|
||||||
|
} = useSelector(state => state.appointmentsUI);
|
||||||
|
const screens = useBreakpoint();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = "Приемы";
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const splitterStyle = {flex: 1};
|
||||||
|
const splitterContentPanelStyle = {padding: 16};
|
||||||
|
const splitterSiderPanelStyle = {padding: "16px", borderLeft: "1px solid #ddd", overflowY: "auto"};
|
||||||
|
const siderTitleStyle = {marginBottom: 36};
|
||||||
|
const siderButtonContainerStyle = {
|
||||||
|
position: "fixed",
|
||||||
|
right: 0,
|
||||||
|
top: "50%",
|
||||||
|
transform: "translateY(-50%)",
|
||||||
|
transition: "right 0.3s ease",
|
||||||
|
zIndex: 1000,
|
||||||
|
display: screens.xs ? "none" : "block",
|
||||||
|
};
|
||||||
|
const siderButtonStyle = {
|
||||||
|
width: hovered ? 250 : 50,
|
||||||
|
padding: hovered ? "0 20px" : "0",
|
||||||
|
overflow: "hidden",
|
||||||
|
textAlign: "left",
|
||||||
|
transition: "width 0.3s ease, padding 0.3s ease",
|
||||||
|
borderRadius: "4px 0 0 4px",
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleSider = () => dispatch(toggleSider());
|
||||||
|
const handleHoverSider = () => dispatch(setHovered(true));
|
||||||
|
const handleLeaveSider = () => dispatch(setHovered(false));
|
||||||
|
|
||||||
|
const siderButtonText = useMemo(() => hovered ? (collapsed ? "Показать предстоящие события" : "Скрыть предстоящие события") : "", [collapsed, hovered]);
|
||||||
|
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
collapsed,
|
||||||
|
siderWidth,
|
||||||
|
hovered,
|
||||||
|
showSplitterPanel,
|
||||||
|
siderButtonText,
|
||||||
|
splitterStyle,
|
||||||
|
splitterContentPanelStyle,
|
||||||
|
splitterSiderPanelStyle,
|
||||||
|
siderTitleStyle,
|
||||||
|
siderButtonContainerStyle,
|
||||||
|
siderButtonStyle,
|
||||||
|
handleToggleSider,
|
||||||
|
handleHoverSider,
|
||||||
|
handleLeaveSider,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useAppointmentsUI;
|
||||||
@ -2,13 +2,13 @@ import {
|
|||||||
Modal, Input, Button, Typography, Collapse, Steps, Row, Alert, Col, DatePicker, Spin
|
Modal, Input, Button, Typography, Collapse, Steps, Row, Alert, Col, DatePicker, Spin
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import useLensIssueFormModal from "./useLensIssueFormModal.js";
|
import useLensIssueForm from "./useLensIssueForm.js";
|
||||||
import useLensIssueFormModalUI from "./useLensIssueFormModalUI.js";
|
import useLensIssueFormUI from "./useLensIssueFormUI.js";
|
||||||
import {useMemo} from "react";
|
import {useMemo} from "react";
|
||||||
|
|
||||||
const LensIssueFormModal = ({visible, onCancel, onSubmit}) => {
|
const LensIssueFormModal = ({visible, onCancel, onSubmit}) => {
|
||||||
const lensIssueFormModalData = useLensIssueFormModal();
|
const lensIssueFormModalData = useLensIssueForm();
|
||||||
const lensIssueFormModalUI = useLensIssueFormModalUI(visible, onCancel, onSubmit, lensIssueFormModalData.patients, lensIssueFormModalData.lenses);
|
const lensIssueFormModalUI = useLensIssueFormUI(visible, onCancel, onSubmit, lensIssueFormModalData.patients, lensIssueFormModalData.lenses);
|
||||||
|
|
||||||
const patientsItems = lensIssueFormModalUI.filteredPatients.map((patient) => ({
|
const patientsItems = lensIssueFormModalUI.filteredPatients.map((patient) => ({
|
||||||
key: patient.id,
|
key: patient.id,
|
||||||
@ -182,7 +182,7 @@ const LensIssueFormModal = ({visible, onCancel, onSubmit}) => {
|
|||||||
}, {
|
}, {
|
||||||
title: 'Выбор линзы', content: SelectLensStep,
|
title: 'Выбор линзы', content: SelectLensStep,
|
||||||
}, {
|
}, {
|
||||||
title: 'Подтверждение', content: <ConfirmStep/>,
|
title: 'Подтверждение', content: ConfirmStep,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {useGetPatientsQuery} from "../../../../../Api/patientsApi.js";
|
|||||||
import {useGetNotIssuedLensesQuery} from "../../../../../Api/lensesApi.js";
|
import {useGetNotIssuedLensesQuery} from "../../../../../Api/lensesApi.js";
|
||||||
|
|
||||||
|
|
||||||
const useLensIssueFormModal = () => {
|
const useLensIssueForm = () => {
|
||||||
const {data: patients = [], isLoading: isLoadingPatients, isError: isErrorPatients} = useGetPatientsQuery(undefined);
|
const {data: patients = [], isLoading: isLoadingPatients, isError: isErrorPatients} = useGetPatientsQuery(undefined);
|
||||||
const {data: lenses = [], isLoading: isLoadingLenses, isError: isErrorLenses} = useGetNotIssuedLensesQuery(undefined);
|
const {data: lenses = [], isLoading: isLoadingLenses, isError: isErrorLenses} = useGetNotIssuedLensesQuery(undefined);
|
||||||
|
|
||||||
@ -14,4 +14,4 @@ const useLensIssueFormModal = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLensIssueFormModal;
|
export default useLensIssueForm;
|
||||||
@ -4,7 +4,7 @@ import {Grid, notification} from "antd";
|
|||||||
|
|
||||||
const {useBreakpoint} = Grid;
|
const {useBreakpoint} = Grid;
|
||||||
|
|
||||||
const useLensIssueFormModalUI = (visible, onCancel, onSubmit, patients, lenses) => {
|
const useLensIssueFormUI = (visible, onCancel, onSubmit, patients, lenses) => {
|
||||||
const screens = useBreakpoint();
|
const screens = useBreakpoint();
|
||||||
|
|
||||||
const [searchPatientString, setSearchPatientString] = useState("");
|
const [searchPatientString, setSearchPatientString] = useState("");
|
||||||
@ -193,4 +193,4 @@ const useLensIssueFormModalUI = (visible, onCancel, onSubmit, patients, lenses)
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLensIssueFormModalUI;
|
export default useLensIssueFormUI;
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import {Col, Form, InputNumber, Modal, Row, Select} from "antd";
|
import {Col, Form, InputNumber, Modal, Row, Select} from "antd";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {LensPropType} from "../../../../../Types/lensPropType.js";
|
import {LensPropType} from "../../../../../../../Types/lensPropType.js";
|
||||||
import useLensFormModal from "./useLensFormModal.js";
|
import useLensForm from "./useLensForm.js";
|
||||||
import useLensFormModalUI from "./useLensFormModalUI.js";
|
import useLensFormUI from "./useLensFormUI.js";
|
||||||
|
|
||||||
|
|
||||||
const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
|
const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
|
||||||
const lensFormData = useLensFormModal();
|
const lensFormData = useLensForm();
|
||||||
const lensFormUI = useLensFormModalUI(lensFormData.lensTypes, visible, onCancel, onSubmit, lens);
|
const lensFormUI = useLensFormUI(lensFormData.lensTypes, visible, onCancel, onSubmit, lens);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import {useGetLensTypesQuery} from "../../../../../Api/lensTypesApi.js";
|
import {useGetLensTypesQuery} from "../../../../../../../Api/lensTypesApi.js";
|
||||||
|
|
||||||
|
|
||||||
const useLensFormModal = () => {
|
const useLensForm = () => {
|
||||||
const {data: lensTypes = [], isLoading, isError} = useGetLensTypesQuery(undefined);
|
const {data: lensTypes = [], isLoading, isError} = useGetLensTypesQuery(undefined);
|
||||||
|
|
||||||
return {lensTypes, isLoading, isError};
|
return {lensTypes, isLoading, isError};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLensFormModal;
|
export default useLensForm;
|
||||||
@ -2,7 +2,7 @@ import {useEffect} from "react";
|
|||||||
import {Form} from "antd";
|
import {Form} from "antd";
|
||||||
|
|
||||||
|
|
||||||
const useLensFormModalUI = (lensTypes, visible, onCancel, onSubmit, lens) => {
|
const useLensFormUI = (lensTypes, visible, onCancel, onSubmit, lens) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -45,4 +45,4 @@ const useLensFormModalUI = (lensTypes, visible, onCancel, onSubmit, lens) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLensFormModalUI;
|
export default useLensFormUI;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import {Button, Col, Modal, Row, Typography} from "antd";
|
import {Button, Col, Modal, Row, Typography} from "antd";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {LensPropType} from "../../../../../Types/lensPropType.js";
|
import {LensPropType} from "../../../../../../../Types/lensPropType.js";
|
||||||
|
|
||||||
const {Text, Title} = Typography;
|
const {Text, Title} = Typography;
|
||||||
|
|
||||||
@ -22,10 +22,10 @@ import {
|
|||||||
TableOutlined,
|
TableOutlined,
|
||||||
BuildOutlined
|
BuildOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import LensCard from "../../Dummies/LensListCard.jsx";
|
import LensCard from "../../../../Dummies/LensListCard.jsx";
|
||||||
import LensFormModal from "./Components/LensFormModal/LensFormModal.jsx";
|
import LensFormModal from "./Components/LensFormModal/LensFormModal.jsx";
|
||||||
import SelectViewMode from "../../Widgets/SelectViewMode.jsx";
|
import SelectViewMode from "../../../../Widgets/SelectViewMode.jsx";
|
||||||
import LoadingIndicator from "../../Widgets/LoadingIndicator.jsx";
|
import LoadingIndicator from "../../../../Widgets/LoadingIndicator.jsx";
|
||||||
import useLenses from "./useLenses.js";
|
import useLenses from "./useLenses.js";
|
||||||
import useLensesUI from "./useLensesUI.js";
|
import useLensesUI from "./useLensesUI.js";
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ const {Option} = Select;
|
|||||||
const {useBreakpoint} = Grid;
|
const {useBreakpoint} = Grid;
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
|
|
||||||
const LensesPage = () => {
|
const LensesTab = () => {
|
||||||
const lensesData = useLenses();
|
const lensesData = useLenses();
|
||||||
const lensesUI = useLensesUI(lensesData.lenses);
|
const lensesUI = useLensesUI(lensesData.lenses);
|
||||||
|
|
||||||
@ -332,4 +332,4 @@ const LensesPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LensesPage;
|
export default LensesTab;
|
||||||
@ -4,9 +4,9 @@ import {
|
|||||||
useDeleteLensMutation,
|
useDeleteLensMutation,
|
||||||
useGetLensesQuery,
|
useGetLensesQuery,
|
||||||
useUpdateLensMutation
|
useUpdateLensMutation
|
||||||
} from "../../../Api/lensesApi.js";
|
} from "../../../../../Api/lensesApi.js";
|
||||||
import {notification} from "antd";
|
import {notification} from "antd";
|
||||||
import {closeModal} from "../../../Redux/Slices/lensesSlice.js";
|
import {closeModal} from "../../../../../Redux/Slices/lensesSlice.js";
|
||||||
|
|
||||||
|
|
||||||
const useLenses = () => {
|
const useLenses = () => {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useMemo} from "react";
|
import {useEffect, useMemo} from "react";
|
||||||
import {getCachedInfo} from "../../../Utils/cachedInfoUtils.js";
|
import {getCachedInfo} from "../../../../../Utils/cachedInfoUtils.js";
|
||||||
import {
|
import {
|
||||||
closeModal,
|
closeModal,
|
||||||
openModal,
|
openModal,
|
||||||
@ -7,7 +7,7 @@ import {
|
|||||||
setSearchParams,
|
setSearchParams,
|
||||||
setSearchText, setShowAdvancedSearch,
|
setSearchText, setShowAdvancedSearch,
|
||||||
setViewMode
|
setViewMode
|
||||||
} from "../../../Redux/Slices/lensesSlice.js";
|
} from "../../../../../Redux/Slices/lensesSlice.js";
|
||||||
import {useDispatch, useSelector} from "react-redux";
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
|
||||||
|
|
||||||
@ -1,15 +1,15 @@
|
|||||||
import {Modal, Button, Form, Input, Table, InputNumber, Select, Space, Result} from "antd";
|
import {Modal, Button, Form, Input, Table, InputNumber, Select, Space, Result} from "antd";
|
||||||
import {PlusOutlined, DeleteOutlined} from "@ant-design/icons";
|
import {PlusOutlined, DeleteOutlined} from "@ant-design/icons";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {SetPropType} from "../../../../../Types/setPropType.js";
|
import {SetPropType} from "../../../../../../../Types/setPropType.js";
|
||||||
import useSetFormModal from "./useSetFormModal.js";
|
import useSetForm from "./useSetForm.js";
|
||||||
import useSetFormModalUI from "./useSetFormModalUI.js";
|
import useSetFormUI from "./useSetFormUI.js";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
|
const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
|
||||||
const setFormModalData = useSetFormModal(setData);
|
const setFormModalData = useSetForm(setData);
|
||||||
const setFormModalUI = useSetFormModalUI(visible, onCancel, setData, onSubmit, setFormModalData.setContents, setFormModalData.lensTypes);
|
const setFormModalUI = useSetFormUI(visible, onCancel, setData, onSubmit, setFormModalData.setContents, setFormModalData.lensTypes);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import {useGetLensTypesQuery} from "../../../../../Api/lensTypesApi.js";
|
import {useGetLensTypesQuery} from "../../../../../../../Api/lensTypesApi.js";
|
||||||
import {useGetSetContentQuery} from "../../../../../Api/setContentApi.js";
|
import {useGetSetContentQuery} from "../../../../../../../Api/setContentApi.js";
|
||||||
|
|
||||||
|
|
||||||
const useSetFormModal = (setData) => {
|
const useSetForm = (setData) => {
|
||||||
const {data: lensTypes = [], isLoading: isLoadingLensTypes, isError: isErrorLensTypes} =
|
const {data: lensTypes = [], isLoading: isLoadingLensTypes, isError: isErrorLensTypes} =
|
||||||
useGetLensTypesQuery(undefined);
|
useGetLensTypesQuery(undefined);
|
||||||
|
|
||||||
@ -24,4 +24,4 @@ const useSetFormModal = (setData) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useSetFormModal;
|
export default useSetForm;
|
||||||
@ -2,7 +2,7 @@ import {Form, notification} from "antd";
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
|
||||||
const useSetFormModalUI = (visible, onCancel, setData, onSubmit, content, lensTypes) => {
|
const useSetFormUI = (visible, onCancel, setData, onSubmit, content, lensTypes) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [currentContent, setCurrentContent] = useState([]);
|
const [currentContent, setCurrentContent] = useState([]);
|
||||||
|
|
||||||
@ -112,4 +112,4 @@ const useSetFormModalUI = (visible, onCancel, setData, onSubmit, content, lensTy
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useSetFormModalUI;
|
export default useSetFormUI;
|
||||||
@ -1,15 +1,15 @@
|
|||||||
import {FloatButton, Input, List, Result, Row, Typography} from "antd";
|
import {FloatButton, Input, List, Result, Row, Typography} from "antd";
|
||||||
import {PlusOutlined, SwitcherOutlined} from "@ant-design/icons";
|
import {PlusOutlined, SwitcherOutlined} from "@ant-design/icons";
|
||||||
import SetListCard from "../../Dummies/SetListCard.jsx";
|
import SetListCard from "../../../../Dummies/SetListCard.jsx";
|
||||||
import SetFormModal from "./Components/SetFormModal/SetFormModal.jsx";
|
import SetFormModal from "./Components/SetFormModal/SetFormModal.jsx";
|
||||||
import LoadingIndicator from "../../Widgets/LoadingIndicator.jsx";
|
import LoadingIndicator from "../../../../Widgets/LoadingIndicator.jsx";
|
||||||
import useSets from "./useSets.js";
|
import useSets from "./useSets.js";
|
||||||
import useSetsUI from "./useSetsUI.js";
|
import useSetsUI from "./useSetsUI.js";
|
||||||
|
|
||||||
|
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
|
|
||||||
const SetsPage = () => {
|
const SetsTab = () => {
|
||||||
const setsData = useSets();
|
const setsData = useSets();
|
||||||
const setsUI = useSetsUI(setsData.sets);
|
const setsUI = useSetsUI(setsData.sets);
|
||||||
|
|
||||||
@ -79,4 +79,4 @@ const SetsPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SetsPage;
|
export default SetsTab;
|
||||||
@ -5,9 +5,9 @@ import {
|
|||||||
useDeleteSetMutation,
|
useDeleteSetMutation,
|
||||||
useGetSetsQuery,
|
useGetSetsQuery,
|
||||||
useUpdateSetMutation
|
useUpdateSetMutation
|
||||||
} from "../../../Api/setsApi.js";
|
} from "../../../../../Api/setsApi.js";
|
||||||
import {closeModal} from "../../../Redux/Slices/setsSlice.js";
|
import {closeModal} from "../../../../../Redux/Slices/setsSlice.js";
|
||||||
import {useAddSetContentMutation, useUpdateSetContentMutation} from "../../../Api/setContentApi.js";
|
import {useAddSetContentMutation, useUpdateSetContentMutation} from "../../../../../Api/setContentApi.js";
|
||||||
|
|
||||||
|
|
||||||
const useSets = () => {
|
const useSets = () => {
|
||||||
@ -7,7 +7,7 @@ import {
|
|||||||
setCurrentPage,
|
setCurrentPage,
|
||||||
setPageSize,
|
setPageSize,
|
||||||
setSearchText
|
setSearchText
|
||||||
} from "../../../Redux/Slices/setsSlice.js";
|
} from "../../../../../Redux/Slices/setsSlice.js";
|
||||||
|
|
||||||
|
|
||||||
const useSetsUI = (sets) => {
|
const useSetsUI = (sets) => {
|
||||||
@ -1,27 +1,27 @@
|
|||||||
import {
|
import {
|
||||||
Tabs
|
Tabs
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import LensesPage from "../Pages/LensesPage/LensesPage.jsx";
|
import LensesTab from "./Components/LensesTab/LensesTab.jsx";
|
||||||
import {FolderViewOutlined, SwitcherOutlined} from "@ant-design/icons";
|
import {FolderViewOutlined, SwitcherOutlined} from "@ant-design/icons";
|
||||||
import SetsPage from "../Pages/SetsPage/SetsPage.jsx";
|
import SetsTab from "./Components/SetsTab/SetsTab.jsx";
|
||||||
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
key: '1',
|
key: '1',
|
||||||
label: 'Линзы',
|
label: 'Линзы',
|
||||||
children: <LensesPage/>,
|
children: <LensesTab/>,
|
||||||
icon: <FolderViewOutlined/>
|
icon: <FolderViewOutlined/>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: '2',
|
key: '2',
|
||||||
label: 'Наборы линз',
|
label: 'Наборы линз',
|
||||||
children: <SetsPage/>,
|
children: <SetsTab/>,
|
||||||
icon: <SwitcherOutlined/>
|
icon: <SwitcherOutlined/>
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const LensesLayout = () => {
|
const LensesSetsPage = () => {
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultActiveKey="1"
|
defaultActiveKey="1"
|
||||||
@ -30,4 +30,4 @@ const LensesLayout = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LensesLayout;
|
export default LensesSetsPage;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import {Form, Input, Button, Row, Col, Typography} from 'antd';
|
import {Form, Input, Button, Row, Col, Typography} from 'antd';
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import {useAuth} from "../../Hooks/AuthContext.jsx";
|
import {useAuth} from "../../../Hooks/AuthContext.jsx";
|
||||||
import {useNavigate} from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
@ -4,12 +4,12 @@ import locale from "antd/es/date-picker/locale/ru_RU";
|
|||||||
import {MaskedInput} from "antd-mask-input";
|
import {MaskedInput} from "antd-mask-input";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {PatientPropType} from "../../../../../Types/patientPropType.js";
|
import {PatientPropType} from "../../../../../Types/patientPropType.js";
|
||||||
import usePatientFormModalUI from "./usePatientFormModalUI.js";
|
import usePatientFormUI from "./usePatientFormUI.js";
|
||||||
|
|
||||||
const {TextArea} = Input;
|
const {TextArea} = Input;
|
||||||
|
|
||||||
const PatientFormModal = ({visible, onCancel, onSubmit, patient}) => {
|
const PatientFormModal = ({visible, onCancel, onSubmit, patient}) => {
|
||||||
const patientFormModalUI = usePatientFormModalUI(visible, onCancel, onSubmit, patient);
|
const patientFormModalUI = usePatientFormUI(visible, onCancel, onSubmit, patient);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import dayjs from "dayjs";
|
|||||||
import validator from "validator";
|
import validator from "validator";
|
||||||
|
|
||||||
|
|
||||||
const usePatientFormModalUI = (visible, onCancel, onSubmit, patient) => {
|
const usePatientFormUI = (visible, onCancel, onSubmit, patient) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -65,4 +65,4 @@ const usePatientFormModalUI = (visible, onCancel, onSubmit, patient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default usePatientFormModalUI;
|
export default usePatientFormUI;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useRef, useState} from "react";
|
import {useEffect, useRef, useState} from "react";
|
||||||
import {Badge, Col, Tag, Tooltip, Typography} from "antd";
|
import {Badge, Col, Tag, Tooltip} from "antd";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {AppointmentPropType} from "../../Types/appointmentPropType.js";
|
import {AppointmentPropType} from "../../Types/appointmentPropType.js";
|
||||||
@ -38,6 +38,7 @@ const CalendarCell = ({appointments, scheduledAppointments, onCellClick, onItemC
|
|||||||
{appointments.map(app => (
|
{appointments.map(app => (
|
||||||
<Col
|
<Col
|
||||||
key={app.id}
|
key={app.id}
|
||||||
|
style={{overflowX: 'hidden'}}
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={`Прошедший прием: ${dayjs(app.appointment_datetime).format('HH:mm')}`}
|
title={`Прошедший прием: ${dayjs(app.appointment_datetime).format('HH:mm')}`}
|
||||||
@ -48,11 +49,11 @@ const CalendarCell = ({appointments, scheduledAppointments, onCellClick, onItemC
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onItemClick(app);
|
onItemClick(app);
|
||||||
}}
|
}}
|
||||||
style={{margin: '2px 0', cursor: 'pointer'}}
|
style={{margin: '2px 2px 0 0', cursor: 'pointer', width: "95%", minHeight: 30}}
|
||||||
>
|
>
|
||||||
<Badge
|
<Badge
|
||||||
status="success"
|
status="success"
|
||||||
text={dayjs(app.appointment_datetime).format('HH:mm')}
|
text={dayjs(app.scheduled_datetime).format('HH:mm') + ` ${app.patient.last_name} ${app.patient.first_name} `}
|
||||||
/>
|
/>
|
||||||
</Tag>
|
</Tag>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -61,6 +62,7 @@ const CalendarCell = ({appointments, scheduledAppointments, onCellClick, onItemC
|
|||||||
{scheduledAppointments.map(app => (
|
{scheduledAppointments.map(app => (
|
||||||
<Col
|
<Col
|
||||||
key={app.id}
|
key={app.id}
|
||||||
|
style={{overflowX: 'hidden'}}
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={`Запланированный прием: ${dayjs(app.scheduled_datetime).format('HH:mm')}`}
|
title={`Запланированный прием: ${dayjs(app.scheduled_datetime).format('HH:mm')}`}
|
||||||
@ -71,11 +73,11 @@ const CalendarCell = ({appointments, scheduledAppointments, onCellClick, onItemC
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onItemClick(app);
|
onItemClick(app);
|
||||||
}}
|
}}
|
||||||
style={{margin: '2px 0', cursor: 'pointer'}}
|
style={{margin: '2px 2px 0 0', cursor: 'pointer', width: "95%", minHeight: 30}}
|
||||||
>
|
>
|
||||||
<Badge
|
<Badge
|
||||||
status="processing"
|
status="processing"
|
||||||
text={dayjs(app.scheduled_datetime).format('HH:mm')}
|
text={dayjs(app.scheduled_datetime).format('HH:mm') + ` ${app.patient.last_name} ${app.patient.first_name}`}
|
||||||
/>
|
/>
|
||||||
</Tag>
|
</Tag>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
57
web-app/src/Redux/Slices/appointmentsSlice.js
Normal file
57
web-app/src/Redux/Slices/appointmentsSlice.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import {createSlice} from "@reduxjs/toolkit";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
collapsed: true,
|
||||||
|
siderWidth: 250,
|
||||||
|
hovered: false,
|
||||||
|
selectedDate: dayjs().format('YYYY-MM-DD'),
|
||||||
|
modalVisible: false,
|
||||||
|
selectedAppointments: [],
|
||||||
|
selectedAppointment: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const appointmentsSlice = createSlice({
|
||||||
|
name: 'appointmentsUI',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
toggleSider: (state) => {
|
||||||
|
state.collapsed = !state.collapsed;
|
||||||
|
},
|
||||||
|
setSiderWidth: (state, action) => {
|
||||||
|
state.siderWidth = action.payload;
|
||||||
|
},
|
||||||
|
setHovered: (state, action) => {
|
||||||
|
state.hovered = action.payload;
|
||||||
|
},
|
||||||
|
setSelectedDate: (state, action) => {
|
||||||
|
state.selectedDate = action.payload;
|
||||||
|
},
|
||||||
|
openModal: (state) => {
|
||||||
|
state.modalVisible = true;
|
||||||
|
},
|
||||||
|
closeModal: (state) => {
|
||||||
|
state.modalVisible = false;
|
||||||
|
},
|
||||||
|
setSelectedAppointments: (state, action) => {
|
||||||
|
state.selectedAppointments = action.payload;
|
||||||
|
},
|
||||||
|
setSelectedAppointment: (state, action) => {
|
||||||
|
state.selectedAppointment = action.payload;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
toggleSider,
|
||||||
|
setSiderWidth,
|
||||||
|
setHovered,
|
||||||
|
setSelectedDate,
|
||||||
|
openModal,
|
||||||
|
closeModal,
|
||||||
|
setSelectedAppointments,
|
||||||
|
setSelectedAppointment,
|
||||||
|
} = appointmentsSlice.actions;
|
||||||
|
|
||||||
|
export default appointmentsSlice.reducer;
|
||||||
@ -9,6 +9,8 @@ import {setContentApi} from "../Api/setContentApi.js";
|
|||||||
import {lensIssuesApi} from "../Api/lensIssuesApi.js";
|
import {lensIssuesApi} from "../Api/lensIssuesApi.js";
|
||||||
import lensIssuesReducer from "./Slices/lensIssuesSlice.js";
|
import lensIssuesReducer from "./Slices/lensIssuesSlice.js";
|
||||||
import {lensTypesApi} from "../Api/lensTypesApi.js";
|
import {lensTypesApi} from "../Api/lensTypesApi.js";
|
||||||
|
import {appointmentsApi} from "../Api/appointmentsApi.js";
|
||||||
|
import appointmentsReducer from "./Slices/appointmentsSlice.js";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
@ -27,6 +29,9 @@ export const store = configureStore({
|
|||||||
|
|
||||||
[lensIssuesApi.reducerPath]: lensIssuesApi.reducer,
|
[lensIssuesApi.reducerPath]: lensIssuesApi.reducer,
|
||||||
lensIssuesUI: lensIssuesReducer,
|
lensIssuesUI: lensIssuesReducer,
|
||||||
|
|
||||||
|
[appointmentsApi.reducerPath]: appointmentsApi.reducer,
|
||||||
|
appointmentsUI: appointmentsReducer,
|
||||||
},
|
},
|
||||||
middleware: (getDefaultMiddleware) => (
|
middleware: (getDefaultMiddleware) => (
|
||||||
getDefaultMiddleware().concat(
|
getDefaultMiddleware().concat(
|
||||||
@ -36,8 +41,9 @@ export const store = configureStore({
|
|||||||
setContentApi.middleware,
|
setContentApi.middleware,
|
||||||
lensTypesApi.middleware,
|
lensTypesApi.middleware,
|
||||||
lensIssuesApi.middleware,
|
lensIssuesApi.middleware,
|
||||||
|
appointmentsApi.middleware,
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getAllAppointments = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/appointments/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getAllAppointments;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const AddLensIssue = async (api, lens_issue) => {
|
|
||||||
const response = await api.post(`${CONFIG.BASE_URL}/lens_issues/`, lens_issue);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddLensIssue;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const GetAllLensIssues = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/lens_issues/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GetAllLensIssues;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getAllLensTypes = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/lens_types/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getAllLensTypes;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getNotIssuedLenses = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/lenses/not_issued/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getNotIssuedLenses;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getAllPatients = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/patients/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getAllPatients;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getAllScheduledAppointments = async (api) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/scheduled_appointments/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getAllScheduledAppointments;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import CONFIG from "../../Core/сonfig.js";
|
|
||||||
|
|
||||||
const getSetContentBySetId = async (api, set_id) => {
|
|
||||||
const response = await api.get(`${CONFIG.BASE_URL}/set_content/${set_id}/`);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getSetContentBySetId;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user