feat: Добавлена поддержка предстоящих приемов

This commit is contained in:
Андрей Дувакин 2025-06-08 13:21:46 +05:00
parent 3a22fd05be
commit c609c6471d
10 changed files with 196 additions and 65 deletions

View File

@ -1,5 +1,5 @@
from typing import Sequence, Optional from typing import Sequence, Optional
from sqlalchemy import select, desc from sqlalchemy import select, desc, func
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from datetime import date from datetime import date
@ -27,7 +27,7 @@ class AppointmentsRepository:
return result.scalars().all() return result.scalars().all()
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \ async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
Sequence[Appointment]: Sequence[Appointment]:
stmt = ( stmt = (
select(Appointment) select(Appointment)
.options(joinedload(Appointment.type)) .options(joinedload(Appointment.type))
@ -43,8 +43,22 @@ class AppointmentsRepository:
result = await self.db.execute(stmt) result = await self.db.execute(stmt)
return result.scalars().all() return result.scalars().all()
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[Appointment]:
stmt = (
select(Appointment)
.options(joinedload(Appointment.type))
.options(joinedload(Appointment.patient))
.options(joinedload(Appointment.doctor))
.filter_by(doctor_id=doctor_id)
.filter(Appointment.appointment_datetime >= func.now())
.order_by(Appointment.appointment_datetime)
.limit(5)
)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \ async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
Sequence[Appointment]: Sequence[Appointment]:
stmt = ( stmt = (
select(Appointment) select(Appointment)
.options(joinedload(Appointment.type)) .options(joinedload(Appointment.type))

View File

@ -1,5 +1,5 @@
from typing import Sequence from typing import Sequence
from sqlalchemy import select, desc from sqlalchemy import select, desc, func
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from datetime import date from datetime import date
@ -29,7 +29,7 @@ class ScheduledAppointmentsRepository:
return result.scalars().all() return result.scalars().all()
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \ async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
Sequence[ScheduledAppointment]: Sequence[ScheduledAppointment]:
stmt = ( stmt = (
select(ScheduledAppointment) select(ScheduledAppointment)
.options(joinedload(ScheduledAppointment.type)) .options(joinedload(ScheduledAppointment.type))
@ -45,8 +45,22 @@ class ScheduledAppointmentsRepository:
result = await self.db.execute(stmt) result = await self.db.execute(stmt)
return result.scalars().all() return result.scalars().all()
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[ScheduledAppointment]:
stmt = (
select(ScheduledAppointment)
.options(joinedload(ScheduledAppointment.type))
.options(joinedload(ScheduledAppointment.patient))
.options(joinedload(ScheduledAppointment.doctor))
.filter_by(doctor_id=doctor_id, is_canceled=False)
.filter(ScheduledAppointment.scheduled_datetime >= func.now())
.order_by(ScheduledAppointment.scheduled_datetime)
.limit(5)
)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \ async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
Sequence[ScheduledAppointment]: Sequence[ScheduledAppointment]:
stmt = ( stmt = (
select(ScheduledAppointment) select(ScheduledAppointment)
.options(joinedload(ScheduledAppointment.type)) .options(joinedload(ScheduledAppointment.type))

View File

@ -43,6 +43,21 @@ async def get_all_appointments_by_doctor_id(
return await appointments_service.get_appointments_by_doctor_id(doctor_id, start_date=start_date, end_date=end_date) return await appointments_service.get_appointments_by_doctor_id(doctor_id, start_date=start_date, end_date=end_date)
@router.get(
"/doctor/{doctor_id}/upcoming/",
response_model=list[AppointmentEntity],
summary="Get upcoming appointments for doctor",
description="Returns the next 5 upcoming appointments for doctor",
)
async def get_upcoming_appointments_by_doctor_id(
doctor_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointments_service = AppointmentsService(db)
return await appointments_service.get_upcoming_appointments_by_doctor_id(doctor_id)
@router.get( @router.get(
"/patient/{patient_id}/", "/patient/{patient_id}/",
response_model=list[AppointmentEntity], response_model=list[AppointmentEntity],

View File

@ -45,6 +45,21 @@ async def get_all_scheduled_appointments_by_doctor_id(
end_date=end_date) end_date=end_date)
@router.get(
"/doctor/{doctor_id}/upcoming/",
response_model=list[ScheduledAppointmentEntity],
summary="Get upcoming scheduled appointments for doctor",
description="Returns the next 5 upcoming scheduled appointments for doctor",
)
async def get_upcoming_scheduled_appointments_by_doctor_id(
doctor_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
appointments_service = ScheduledAppointmentsService(db)
return await appointments_service.get_upcoming_scheduled_appointments_by_doctor_id(doctor_id)
@router.get( @router.get(
"/patient/{patient_id}/", "/patient/{patient_id}/",
response_model=ScheduledAppointmentEntity, response_model=ScheduledAppointmentEntity,

View File

@ -39,6 +39,16 @@ class AppointmentsService:
end_date=end_date) end_date=end_date)
return [self.model_to_entity(appointment) for appointment in appointments] return [self.model_to_entity(appointment) for appointment in appointments]
async def get_upcoming_appointments_by_doctor_id(self, doctor_id: int) -> Optional[list[AppointmentEntity]]:
doctor = await self.users_repository.get_by_id(doctor_id)
if not doctor:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='Доктор с таким ID не найден',
)
appointments = await self.appointments_repository.get_upcoming_by_doctor_id(doctor_id)
return [self.model_to_entity(appointment) for appointment in appointments]
async def get_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None, async def get_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
end_date: date | None = None) -> Optional[list[AppointmentEntity]]: end_date: date | None = None) -> Optional[list[AppointmentEntity]]:
patient = await self.patients_repository.get_by_id(patient_id) patient = await self.patients_repository.get_by_id(patient_id)

View File

@ -39,6 +39,17 @@ class ScheduledAppointmentsService:
end_date=end_date) end_date=end_date)
return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments] return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments]
async def get_upcoming_scheduled_appointments_by_doctor_id(self, doctor_id: int) -> Optional[
list[ScheduledAppointmentEntity]]:
doctor = await self.users_repository.get_by_id(doctor_id)
if not doctor:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='Доктор с таким ID не найден',
)
scheduled_appointments = await self.scheduled_appointment_repository.get_upcoming_by_doctor_id(doctor_id)
return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments]
async def get_scheduled_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None, async def get_scheduled_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
end_date: date | None = None) -> Optional[ end_date: date | None = None) -> Optional[
list[ScheduledAppointmentEntity]]: list[ScheduledAppointmentEntity]]:

View File

@ -1,5 +1,5 @@
import { createApi } from "@reduxjs/toolkit/query/react"; import {createApi} from "@reduxjs/toolkit/query/react";
import { baseQueryWithAuth } from "./baseQuery.js"; import {baseQueryWithAuth} from "./baseQuery.js";
export const appointmentsApi = createApi({ export const appointmentsApi = createApi({
reducerPath: 'appointmentsApi', reducerPath: 'appointmentsApi',
@ -7,13 +7,17 @@ export const appointmentsApi = createApi({
tagTypes: ['Appointment'], tagTypes: ['Appointment'],
endpoints: (builder) => ({ endpoints: (builder) => ({
getAppointments: builder.query({ getAppointments: builder.query({
query: ({ doctor_id, start_date, end_date }) => ({ query: ({doctor_id, start_date, end_date}) => ({
url: `/appointments/doctor/${doctor_id}/`, url: `/appointments/doctor/${doctor_id}/`,
params: { start_date, end_date }, params: {start_date, end_date},
}), }),
providesTags: ['Appointment'], providesTags: ['Appointment'],
refetchOnMountOrArgChange: 5, refetchOnMountOrArgChange: 5,
}), }),
getUpcomingAppointments: builder.query({
query: (doctor_id) => `/appointments/doctor/${doctor_id}/upcoming/`,
providesTags: ['Appointment'],
}),
getByPatientId: builder.query({ getByPatientId: builder.query({
query: (id) => `/appointments/patient/${id}/`, query: (id) => `/appointments/patient/${id}/`,
providesTags: ['Appointment'], providesTags: ['Appointment'],
@ -28,7 +32,7 @@ export const appointmentsApi = createApi({
invalidatesTags: ['Appointment'], invalidatesTags: ['Appointment'],
}), }),
updateAppointment: builder.mutation({ updateAppointment: builder.mutation({
query: ({ id, data }) => ({ query: ({id, data}) => ({
url: `/appointments/${id}/`, url: `/appointments/${id}/`,
method: 'PUT', method: 'PUT',
body: data, body: data,
@ -40,6 +44,7 @@ export const appointmentsApi = createApi({
export const { export const {
useGetAppointmentsQuery, useGetAppointmentsQuery,
useGetUpcomingAppointmentsQuery,
useGetByPatientIdQuery, useGetByPatientIdQuery,
useCreateAppointmentMutation, useCreateAppointmentMutation,
useUpdateAppointmentMutation, useUpdateAppointmentMutation,

View File

@ -13,6 +13,10 @@ export const scheduledAppointmentsApi = createApi({
}), }),
providesTags: ['ScheduledAppointment'], providesTags: ['ScheduledAppointment'],
}), }),
getUpcomingScheduledAppointments: builder.query({
query: (doctor_id) => `/scheduled_appointments/doctor/${doctor_id}/upcoming/`,
providesTags: ['ScheduledAppointment'],
}),
createScheduledAppointment: builder.mutation({ createScheduledAppointment: builder.mutation({
query: (data) => ({ query: (data) => ({
url: '/scheduled_appointments/', url: '/scheduled_appointments/',
@ -41,6 +45,7 @@ export const scheduledAppointmentsApi = createApi({
export const { export const {
useGetScheduledAppointmentsQuery, useGetScheduledAppointmentsQuery,
useGetUpcomingScheduledAppointmentsQuery,
useCreateScheduledAppointmentMutation, useCreateScheduledAppointmentMutation,
useUpdateScheduledAppointmentMutation, useUpdateScheduledAppointmentMutation,
useCancelScheduledAppointmentMutation, useCancelScheduledAppointmentMutation,

View File

@ -1,5 +1,5 @@
import {Badge, Button, FloatButton, List, Result, Row, Space, Tag, Typography} from "antd"; import { Badge, Button, FloatButton, List, Result, Row, Space, Tag, Typography } from "antd";
import {Splitter} from "antd"; import { Splitter } from "antd";
import { import {
CalendarOutlined, CalendarOutlined,
MenuFoldOutlined, MenuFoldOutlined,
@ -13,14 +13,15 @@ import dayjs from 'dayjs';
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx"; import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
import AppointmentFormModal from "../../Dummies/AppointmentFormModal/AppointmentFormModal.jsx"; import AppointmentFormModal from "../../Dummies/AppointmentFormModal/AppointmentFormModal.jsx";
import AppointmentViewModal from "../../Dummies/AppointmentViewModal/AppointmentViewModal.jsx"; import AppointmentViewModal from "../../Dummies/AppointmentViewModal/AppointmentViewModal.jsx";
import ScheduledAppointmentFormModal import ScheduledAppointmentFormModal from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx";
from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx"; import ScheduledAppointmentsViewModal from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
import ScheduledAppointmentsViewModal
from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
import AppointmentsListModal from "./Components/AppointmentsListModal/AppointmentsListModal.jsx"; import AppointmentsListModal from "./Components/AppointmentsListModal/AppointmentsListModal.jsx";
const AppointmentsPage = () => { const AppointmentsPage = () => {
const { const {
patients, // Добавляем
appointments, // Добавляем
scheduledAppointments, // Добавляем
isLoading, isLoading,
isError, isError,
collapsed, collapsed,
@ -46,7 +47,6 @@ const AppointmentsPage = () => {
openCreateAppointmentModal, openCreateAppointmentModal,
} = useAppointments(); } = useAppointments();
if (isError) return ( if (isError) return (
<Result <Result
status="error" status="error"
@ -57,30 +57,20 @@ const AppointmentsPage = () => {
return ( return (
<> <>
<Typography.Title level={1}><CalendarOutlined/> Приемы</Typography.Title> <Typography.Title level={1}><CalendarOutlined /> Приемы</Typography.Title>
{isLoading ? ( {isLoading ? (
<LoadingIndicator/> <LoadingIndicator />
) : ( ) : (
<> <>
<Row justify="end" style={{marginBottom: 10, marginRight: "2.4rem"}}> <Row justify="end" style={{ marginBottom: 10, marginRight: "2.4rem" }}>
<Space direction={"vertical"}> <Space direction={"vertical"}>
<Tag color={"blue"} style={{width: "100%"}}> <Tag color={"blue"} style={{ width: "100%" }}>
<Badge status={"processing"} <Badge status={"processing"}
text={ text={<span style={badgeTextStyle}>Запланированный прием</span>} />
<span style={badgeTextStyle}>
Запланированный прием
</span>
}
/>
</Tag> </Tag>
<Tag color={"green"} style={{width: "100%"}}> <Tag color={"green"} style={{ width: "100%" }}>
<Badge status={"success"} <Badge status={"success"}
text={ text={<span style={badgeTextStyle}>Прошедший прием</span>} />
<span style={badgeTextStyle}>
Прошедший прием
</span>
}
/>
</Tag> </Tag>
</Space> </Space>
</Row> </Row>
@ -100,9 +90,10 @@ const AppointmentsPage = () => {
<AppointmentsCalendarTab <AppointmentsCalendarTab
currentMonth={currentMonth} currentMonth={currentMonth}
onMonthChange={handleMonthChange} onMonthChange={handleMonthChange}
appointments={appointments} // Добавляем
scheduledAppointments={scheduledAppointments} // Добавляем
/> />
</Splitter.Panel> </Splitter.Panel>
{showSplitterPanel && ( {showSplitterPanel && (
<Splitter.Panel <Splitter.Panel
style={splitterSiderPanelStyle} style={splitterSiderPanelStyle}
@ -118,8 +109,7 @@ const AppointmentsPage = () => {
dataSource={upcomingEvents.sort((a, b) => dataSource={upcomingEvents.sort((a, b) =>
dayjs(a.appointment_datetime || a.scheduled_datetime).diff( dayjs(a.appointment_datetime || a.scheduled_datetime).diff(
dayjs(b.appointment_datetime || b.scheduled_datetime) dayjs(b.appointment_datetime || b.scheduled_datetime)
) ))}
)}
renderItem={(item) => ( renderItem={(item) => (
<List.Item <List.Item
onClick={() => handleEventClick(item)} onClick={() => handleEventClick(item)}
@ -137,9 +127,9 @@ const AppointmentsPage = () => {
<Space direction="vertical" size={2}> <Space direction="vertical" size={2}>
<Space> <Space>
{item.appointment_datetime ? ( {item.appointment_datetime ? (
<ClockCircleOutlined style={{color: "#52c41a"}}/> <ClockCircleOutlined style={{ color: "#52c41a" }} />
) : ( ) : (
<CalendarOutlined style={{color: "#1890ff"}}/> <CalendarOutlined style={{ color: "#1890ff" }} />
)} )}
<Typography.Text strong> <Typography.Text strong>
{dayjs(item.appointment_datetime || item.scheduled_datetime).format('DD.MM.YYYY HH:mm')} {dayjs(item.appointment_datetime || item.scheduled_datetime).format('DD.MM.YYYY HH:mm')}
@ -173,7 +163,7 @@ const AppointmentsPage = () => {
<Button <Button
type="primary" type="primary"
onClick={handleToggleSider} onClick={handleToggleSider}
icon={collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/>} icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
style={siderButtonStyle} style={siderButtonStyle}
> >
{siderButtonText} {siderButtonText}
@ -183,26 +173,26 @@ const AppointmentsPage = () => {
placement={"left"} placement={"left"}
trigger="hover" trigger="hover"
type="primary" type="primary"
icon={<PlusOutlined/>} icon={<PlusOutlined />}
tooltip="Создать" tooltip="Создать"
> >
<FloatButton <FloatButton
icon={<PlusOutlined/>} icon={<PlusOutlined />}
onClick={openCreateAppointmentModal} onClick={openCreateAppointmentModal}
tooltip="Прием" tooltip="Прием"
/> />
<FloatButton <FloatButton
icon={<CalendarOutlined/>} icon={<CalendarOutlined />}
onClick={openCreateScheduledAppointmentModal} onClick={openCreateScheduledAppointmentModal}
tooltip="Запланированный прием" tooltip="Запланированный прием"
/> />
</FloatButton.Group> </FloatButton.Group>
<AppointmentFormModal/> <AppointmentFormModal />
<AppointmentViewModal/> <AppointmentViewModal />
<ScheduledAppointmentFormModal/> <ScheduledAppointmentFormModal />
<ScheduledAppointmentsViewModal/> <ScheduledAppointmentsViewModal />
<AppointmentsListModal/> <AppointmentsListModal />
</> </>
)} )}
</> </>

View File

@ -4,6 +4,7 @@ import { notification } from "antd";
import { Grid } from "antd"; import { Grid } from "antd";
import { import {
useGetAppointmentsQuery, useGetAppointmentsQuery,
useGetUpcomingAppointmentsQuery,
} from "../../../Api/appointmentsApi.js"; } from "../../../Api/appointmentsApi.js";
import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js"; import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js";
import { import {
@ -14,8 +15,17 @@ import {
setSelectedScheduledAppointment, setSelectedScheduledAppointment,
toggleSider toggleSider
} from "../../../Redux/Slices/appointmentsSlice.js"; } from "../../../Redux/Slices/appointmentsSlice.js";
import { useGetScheduledAppointmentsQuery } from "../../../Api/scheduledAppointmentsApi.js"; import {
useGetScheduledAppointmentsQuery,
useGetUpcomingScheduledAppointmentsQuery,
} from "../../../Api/scheduledAppointmentsApi.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault("Europe/Moscow");
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
@ -25,13 +35,13 @@ const useAppointments = () => {
const { collapsed, siderWidth, hovered, selectedAppointment } = useSelector(state => state.appointmentsUI); const { collapsed, siderWidth, hovered, selectedAppointment } = useSelector(state => state.appointmentsUI);
const screens = useBreakpoint(); const screens = useBreakpoint();
const [currentMonth, setCurrentMonth] = useState(dayjs().startOf('month')); const [currentMonth, setCurrentMonth] = useState(dayjs().tz("Europe/Moscow").startOf('month'));
const startDate = currentMonth.startOf('month').format('YYYY-MM-DD'); const startDate = currentMonth.startOf('month').tz("Europe/Moscow").format('YYYY-MM-DD');
const endDate = currentMonth.endOf('month').format('YYYY-MM-DD'); const endDate = currentMonth.endOf('month').tz("Europe/Moscow").format('YYYY-MM-DD');
const handleMonthChange = (newMonth) => { const handleMonthChange = (newMonth) => {
setCurrentMonth(dayjs(newMonth).startOf('month')); setCurrentMonth(dayjs(newMonth).tz("Europe/Moscow").startOf('month'));
}; };
const { const {
@ -39,7 +49,8 @@ const useAppointments = () => {
isLoading: isLoadingAppointments, isLoading: isLoadingAppointments,
isError: isErrorAppointments, isError: isErrorAppointments,
} = useGetAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, { } = useGetAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
pollingInterval: 20000, pollingInterval: 60000,
skip: !userData.id,
}); });
const { const {
@ -47,7 +58,8 @@ const useAppointments = () => {
isLoading: isLoadingScheduledAppointments, isLoading: isLoadingScheduledAppointments,
isError: isErrorScheduledAppointments, isError: isErrorScheduledAppointments,
} = useGetScheduledAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, { } = useGetScheduledAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
pollingInterval: 20000, pollingInterval: 60000,
skip: !userData.id,
}); });
const { const {
@ -55,7 +67,26 @@ const useAppointments = () => {
isLoading: isLoadingPatients, isLoading: isLoadingPatients,
isError: isErrorPatients, isError: isErrorPatients,
} = useGetAllPatientsQuery(undefined, { } = useGetAllPatientsQuery(undefined, {
pollingInterval: 20000, pollingInterval: 60000,
skip: !userData.id,
});
const {
data: upcomingAppointments = [],
isLoading: isLoadingUpcomingAppointments,
isError: isErrorUpcomingAppointments,
} = useGetUpcomingAppointmentsQuery(userData.id, {
pollingInterval: 60000,
skip: !userData.id,
});
const {
data: upcomingScheduledAppointments = [],
isLoading: isLoadingUpcomingScheduledAppointments,
isError: isErrorUpcomingScheduledAppointments,
} = useGetUpcomingScheduledAppointmentsQuery(userData.id, {
pollingInterval: 60000,
skip: !userData.id,
}); });
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth); const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
@ -123,11 +154,10 @@ const useAppointments = () => {
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]); const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
const upcomingEvents = useMemo(() => const upcomingEvents = useMemo(() =>
[...appointments, ...scheduledAppointments] [...upcomingAppointments, ...upcomingScheduledAppointments]
.filter(app => dayjs(app.appointment_datetime || app.scheduled_datetime).isAfter(dayjs())) .sort((a, b) => dayjs(a.appointment_datetime || a.scheduled_datetime).tz("Europe/Moscow") - dayjs(b.appointment_datetime || b.scheduled_datetime).tz("Europe/Moscow"))
.sort((a, b) => dayjs(a.appointment_datetime || a.scheduled_datetime) - dayjs(b.appointment_datetime || b.scheduled_datetime))
.slice(0, 5), .slice(0, 5),
[appointments, scheduledAppointments] [upcomingAppointments, upcomingScheduledAppointments]
); );
useEffect(() => { useEffect(() => {
@ -156,14 +186,36 @@ const useAppointments = () => {
placement: 'topRight', placement: 'topRight',
}); });
} }
}, [isErrorAppointments, isErrorScheduledAppointments, isErrorPatients]); if (isErrorUpcomingAppointments) {
notification.error({
message: 'Ошибка',
description: 'Ошибка загрузки предстоящих приемов.',
placement: 'topRight',
});
}
if (isErrorUpcomingScheduledAppointments) {
notification.error({
message: 'Ошибка',
description: 'Ошибка загрузки предстоящих запланированных приемов.',
placement: 'topRight',
});
}
}, [
isErrorAppointments,
isErrorScheduledAppointments,
isErrorPatients,
isErrorUpcomingAppointments,
isErrorUpcomingScheduledAppointments
]);
return { return {
patients, patients,
appointments, appointments,
scheduledAppointments, scheduledAppointments,
isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients, isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients ||
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients, isLoadingUpcomingAppointments || isLoadingUpcomingScheduledAppointments,
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients ||
isErrorUpcomingAppointments || isErrorUpcomingScheduledAppointments,
collapsed, collapsed,
siderWidth: localSiderWidth, siderWidth: localSiderWidth,
hovered, hovered,