feat: AppointmentsPage: Добавлено отображение напоминаний
This commit is contained in:
parent
59b77a665b
commit
a5fccd0710
@ -2,7 +2,7 @@ from typing import Sequence, Optional
|
|||||||
from sqlalchemy import select, desc, func
|
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, timedelta
|
||||||
|
|
||||||
from app.domain.models import Appointment
|
from app.domain.models import Appointment
|
||||||
|
|
||||||
@ -43,6 +43,35 @@ 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_reminders(self, current_date: date) -> Sequence[Appointment]:
|
||||||
|
stmt = (
|
||||||
|
select(Appointment)
|
||||||
|
.options(joinedload(Appointment.type))
|
||||||
|
.options(joinedload(Appointment.patient))
|
||||||
|
.options(joinedload(Appointment.doctor))
|
||||||
|
.filter(Appointment.days_until_the_next_appointment.is_not(None))
|
||||||
|
)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
appointments = result.scalars().all()
|
||||||
|
|
||||||
|
filtered_appointments = []
|
||||||
|
for appointment in appointments:
|
||||||
|
next_appointment_date = (appointment.appointment_datetime + timedelta(
|
||||||
|
days=appointment.days_until_the_next_appointment)).date()
|
||||||
|
days_until = appointment.days_until_the_next_appointment
|
||||||
|
window_days = (
|
||||||
|
7 if days_until <= 90 else
|
||||||
|
14 if days_until <= 180 else
|
||||||
|
30 if days_until <= 365 else
|
||||||
|
60
|
||||||
|
)
|
||||||
|
window_start = next_appointment_date - timedelta(days=window_days)
|
||||||
|
window_end = next_appointment_date + timedelta(days=window_days)
|
||||||
|
if window_start <= current_date <= window_end:
|
||||||
|
filtered_appointments.append(appointment)
|
||||||
|
|
||||||
|
return filtered_appointments
|
||||||
|
|
||||||
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[Appointment]:
|
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[Appointment]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Appointment)
|
select(Appointment)
|
||||||
|
|||||||
@ -58,6 +58,22 @@ async def get_upcoming_appointments_by_doctor_id(
|
|||||||
return await appointments_service.get_upcoming_appointments_by_doctor_id(doctor_id)
|
return await appointments_service.get_upcoming_appointments_by_doctor_id(doctor_id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/reminders/",
|
||||||
|
response_model=list[AppointmentEntity],
|
||||||
|
summary="Get appointment reminders",
|
||||||
|
description="Returns a list of appointments with upcoming follow-up reminders based on days_until_the_next_appointment",
|
||||||
|
)
|
||||||
|
async def get_appointment_reminders(
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
current_date: date = Query(default_factory=date.today,
|
||||||
|
description="Current date for reminder calculation (YYYY-MM-DD)"),
|
||||||
|
):
|
||||||
|
appointments_service = AppointmentsService(db)
|
||||||
|
return await appointments_service.get_appointment_reminders(current_date)
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/patient/{patient_id}/",
|
"/patient/{patient_id}/",
|
||||||
response_model=list[AppointmentEntity],
|
response_model=list[AppointmentEntity],
|
||||||
|
|||||||
@ -49,6 +49,10 @@ class AppointmentsService:
|
|||||||
appointments = await self.appointments_repository.get_upcoming_by_doctor_id(doctor_id)
|
appointments = await self.appointments_repository.get_upcoming_by_doctor_id(doctor_id)
|
||||||
return [self.model_to_entity(appointment) for appointment in appointments]
|
return [self.model_to_entity(appointment) for appointment in appointments]
|
||||||
|
|
||||||
|
async def get_appointment_reminders(self, current_date: date) -> list[AppointmentEntity]:
|
||||||
|
appointments = await self.appointments_repository.get_reminders(current_date)
|
||||||
|
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)
|
||||||
|
|||||||
@ -31,13 +31,11 @@ export const appointmentsApi = createApi({
|
|||||||
}),
|
}),
|
||||||
invalidatesTags: ['Appointment'],
|
invalidatesTags: ['Appointment'],
|
||||||
}),
|
}),
|
||||||
updateAppointment: builder.mutation({
|
getAppointmentReminders: builder.query({
|
||||||
query: ({id, data}) => ({
|
query: (current_date) => ({
|
||||||
url: `/appointments/${id}/`,
|
url: "/appointments/reminders/",
|
||||||
method: 'PUT',
|
params: { current_date },
|
||||||
body: data,
|
|
||||||
}),
|
}),
|
||||||
invalidatesTags: ['Appointment'],
|
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@ -47,5 +45,5 @@ export const {
|
|||||||
useGetUpcomingAppointmentsQuery,
|
useGetUpcomingAppointmentsQuery,
|
||||||
useGetByPatientIdQuery,
|
useGetByPatientIdQuery,
|
||||||
useCreateAppointmentMutation,
|
useCreateAppointmentMutation,
|
||||||
useUpdateAppointmentMutation,
|
useGetAppointmentRemindersQuery
|
||||||
} = appointmentsApi;
|
} = appointmentsApi;
|
||||||
@ -1,20 +1,23 @@
|
|||||||
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,
|
||||||
MenuUnfoldOutlined,
|
MenuUnfoldOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
ClockCircleOutlined,
|
ClockCircleOutlined,
|
||||||
|
BellOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import AppointmentsCalendar from "./Components/AppointmentCalendar/AppointmentsCalendar.jsx";
|
import AppointmentsCalendar from "./Components/AppointmentCalendar/AppointmentsCalendar.jsx";
|
||||||
import useAppointments from "./useAppointments.js";
|
import useAppointmentsPage from "./useAppointmentsPage.js";
|
||||||
import dayjs from 'dayjs';
|
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 from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx";
|
import ScheduledAppointmentFormModal
|
||||||
import ScheduledAppointmentsViewModal from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
|
from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.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 = () => {
|
||||||
@ -44,7 +47,7 @@ const AppointmentsPage = () => {
|
|||||||
handleMonthChange,
|
handleMonthChange,
|
||||||
handleEventClick,
|
handleEventClick,
|
||||||
openCreateAppointmentModal,
|
openCreateAppointmentModal,
|
||||||
} = useAppointments();
|
} = useAppointmentsPage();
|
||||||
|
|
||||||
if (isError) return (
|
if (isError) return (
|
||||||
<Result
|
<Result
|
||||||
@ -56,20 +59,24 @@ 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={<span style={badgeTextStyle}>Запланированный прием</span>} />
|
text={<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={<span style={badgeTextStyle}>Прошедший прием</span>} />
|
text={<span style={badgeTextStyle}>Прошедший прием</span>}/>
|
||||||
|
</Tag>
|
||||||
|
<Tag color={"yellow"} style={{width: "100%"}}>
|
||||||
|
<Badge status={"warning"}
|
||||||
|
text={<span style={badgeTextStyle}>Напоминание о приеме</span>}/>
|
||||||
</Tag>
|
</Tag>
|
||||||
</Space>
|
</Space>
|
||||||
</Row>
|
</Row>
|
||||||
@ -89,8 +96,8 @@ const AppointmentsPage = () => {
|
|||||||
<AppointmentsCalendar
|
<AppointmentsCalendar
|
||||||
currentMonth={currentMonth}
|
currentMonth={currentMonth}
|
||||||
onMonthChange={handleMonthChange}
|
onMonthChange={handleMonthChange}
|
||||||
appointments={appointments} // Добавляем
|
appointments={appointments}
|
||||||
scheduledAppointments={scheduledAppointments} // Добавляем
|
scheduledAppointments={scheduledAppointments}
|
||||||
/>
|
/>
|
||||||
</Splitter.Panel>
|
</Splitter.Panel>
|
||||||
{showSplitterPanel && (
|
{showSplitterPanel && (
|
||||||
@ -105,10 +112,7 @@ const AppointmentsPage = () => {
|
|||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
{upcomingEvents.length ? (
|
{upcomingEvents.length ? (
|
||||||
<List
|
<List
|
||||||
dataSource={upcomingEvents.sort((a, b) =>
|
dataSource={upcomingEvents}
|
||||||
dayjs(a.appointment_datetime || a.scheduled_datetime).diff(
|
|
||||||
dayjs(b.appointment_datetime || b.scheduled_datetime)
|
|
||||||
))}
|
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item
|
<List.Item
|
||||||
onClick={() => handleEventClick(item)}
|
onClick={() => handleEventClick(item)}
|
||||||
@ -116,32 +120,46 @@ const AppointmentsPage = () => {
|
|||||||
padding: "12px",
|
padding: "12px",
|
||||||
marginBottom: "8px",
|
marginBottom: "8px",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
background: item.appointment_datetime ? "#f6ffed" : "#e6f7ff",
|
background: item.type === "reminder" ? "#fff7e6" :
|
||||||
|
item.appointment_datetime ? "#f6ffed" : "#e6f7ff",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
transition: "background 0.3s",
|
transition: "background 0.3s",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => (e.currentTarget.style.background = item.appointment_datetime ? "#efffdb" : "#d9efff")}
|
onMouseEnter={(e) => (e.currentTarget.style.background =
|
||||||
onMouseLeave={(e) => (e.currentTarget.style.background = item.appointment_datetime ? "#f6ffed" : "#e6f7ff")}
|
item.type === "reminder" ? "#ffecd2" :
|
||||||
|
item.appointment_datetime ? "#efffdb" : "#d9efff")}
|
||||||
|
onMouseLeave={(e) => (e.currentTarget.style.background =
|
||||||
|
item.type === "reminder" ? "#fff7e6" :
|
||||||
|
item.appointment_datetime ? "#f6ffed" : "#e6f7ff")}
|
||||||
>
|
>
|
||||||
<Space direction="vertical" size={2}>
|
<Space direction="vertical" size={2}>
|
||||||
<Space>
|
<Space>
|
||||||
{item.appointment_datetime ? (
|
{item.type === "reminder" ? (
|
||||||
<ClockCircleOutlined style={{ color: "#52c41a" }} />
|
<BellOutlined style={{color: "#fa8c16"}}/>
|
||||||
|
) : item.appointment_datetime ? (
|
||||||
|
<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.type === "reminder" ? item.reminder_datetime :
|
||||||
|
(item.appointment_datetime || item.scheduled_datetime))
|
||||||
|
.format('DD.MM.YYYY HH:mm')}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Space>
|
</Space>
|
||||||
<Typography.Text>
|
<Typography.Text>
|
||||||
{item.appointment_datetime ? 'Прием' : 'Запланировано'}
|
{item.type === "reminder" ? "Напоминание" :
|
||||||
|
item.appointment_datetime ? "Прием" : "Запланировано"}
|
||||||
{item.patient ? ` - ${item.patient.last_name} ${item.patient.first_name}` : ''}
|
{item.patient ? ` - ${item.patient.last_name} ${item.patient.first_name}` : ''}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
|
{item.type !== "reminder" && (
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
Тип: {item.type?.title || 'Не указан'}
|
Тип: {item.type === "reminder" ? item.type.title : item.type?.title || 'Не указан'}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
{dayjs(item.appointment_datetime || item.scheduled_datetime).isSame(dayjs(), 'day') && (
|
)}
|
||||||
|
{dayjs(item.type === "reminder" ? item.reminder_datetime :
|
||||||
|
(item.appointment_datetime || item.scheduled_datetime))
|
||||||
|
.isSame(dayjs(), 'day') && (
|
||||||
<Typography.Text type="warning">Сегодня</Typography.Text>
|
<Typography.Text type="warning">Сегодня</Typography.Text>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
@ -162,7 +180,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}
|
||||||
@ -172,26 +190,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/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {useDispatch, useSelector} from "react-redux";
|
|||||||
import {notification} from "antd";
|
import {notification} from "antd";
|
||||||
import {Grid} from "antd";
|
import {Grid} from "antd";
|
||||||
import {
|
import {
|
||||||
|
useGetAppointmentRemindersQuery,
|
||||||
useGetAppointmentsQuery,
|
useGetAppointmentsQuery,
|
||||||
useGetUpcomingAppointmentsQuery,
|
useGetUpcomingAppointmentsQuery,
|
||||||
} from "../../../Api/appointmentsApi.js";
|
} from "../../../Api/appointmentsApi.js";
|
||||||
@ -28,7 +29,7 @@ dayjs.extend(timezone);
|
|||||||
|
|
||||||
const {useBreakpoint} = Grid;
|
const {useBreakpoint} = Grid;
|
||||||
|
|
||||||
const useAppointments = () => {
|
const useAppointmentsPage = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const {userData} = useSelector(state => state.auth);
|
const {userData} = useSelector(state => state.auth);
|
||||||
const {collapsed, siderWidth, hovered, selectedAppointment} = useSelector(state => state.appointmentsUI);
|
const {collapsed, siderWidth, hovered, selectedAppointment} = useSelector(state => state.appointmentsUI);
|
||||||
@ -88,6 +89,15 @@ const useAppointments = () => {
|
|||||||
skip: !userData.id,
|
skip: !userData.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: reminders = [],
|
||||||
|
isLoading: isLoadingReminders,
|
||||||
|
isError: isErrorReminders,
|
||||||
|
} = useGetAppointmentRemindersQuery(new Date().toISOString().split("T")[0], {
|
||||||
|
skip: !userData,
|
||||||
|
pollingInterval: 60000,
|
||||||
|
});
|
||||||
|
|
||||||
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
|
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
|
||||||
|
|
||||||
const splitterStyle = {flex: 1};
|
const splitterStyle = {flex: 1};
|
||||||
@ -133,7 +143,9 @@ const useAppointments = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleEventClick = (event) => {
|
const handleEventClick = (event) => {
|
||||||
if (event.appointment_datetime) {
|
if (event.type === "reminder") {
|
||||||
|
dispatch(setSelectedAppointment(event));
|
||||||
|
} else if (event.appointment_datetime) {
|
||||||
dispatch(setSelectedAppointment(event));
|
dispatch(setSelectedAppointment(event));
|
||||||
} else {
|
} else {
|
||||||
dispatch(setSelectedScheduledAppointment(event));
|
dispatch(setSelectedScheduledAppointment(event));
|
||||||
@ -150,14 +162,34 @@ const useAppointments = () => {
|
|||||||
hovered ? (collapsed ? "Показать предстоящие события" : "Скрыть предстоящие события") : "",
|
hovered ? (collapsed ? "Показать предстоящие события" : "Скрыть предстоящие события") : "",
|
||||||
[collapsed, hovered]
|
[collapsed, hovered]
|
||||||
);
|
);
|
||||||
|
|
||||||
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
|
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
|
||||||
|
|
||||||
const upcomingEvents = useMemo(() =>
|
const upcomingEvents = useMemo(() => {
|
||||||
[...upcomingAppointments, ...upcomingScheduledAppointments]
|
const remindersWithType = reminders.map(reminder => ({
|
||||||
.sort((a, b) => dayjs(a.appointment_datetime || a.scheduled_datetime) - dayjs(b.appointment_datetime || b.scheduled_datetime))
|
...reminder,
|
||||||
.slice(0, 5),
|
type: "reminder",
|
||||||
[upcomingAppointments, upcomingScheduledAppointments]
|
reminder_datetime: dayjs(reminder.appointment_datetime).add(reminder.days_until_the_next_appointment, 'day').toISOString(),
|
||||||
);
|
}));
|
||||||
|
const appointmentsWithType = upcomingAppointments.map(appointment => ({
|
||||||
|
...appointment,
|
||||||
|
type: "appointment",
|
||||||
|
}));
|
||||||
|
const scheduledAppointmentsWithType = upcomingScheduledAppointments.map(scheduled => ({
|
||||||
|
...scheduled,
|
||||||
|
type: "scheduledAppointment",
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [
|
||||||
|
...appointmentsWithType,
|
||||||
|
...scheduledAppointmentsWithType,
|
||||||
|
...remindersWithType
|
||||||
|
].sort((a, b) => {
|
||||||
|
const dateA = a.type === "reminder" ? a.reminder_datetime : (a.appointment_datetime || a.scheduled_datetime);
|
||||||
|
const dateB = b.type === "reminder" ? b.reminder_datetime : (b.appointment_datetime || b.scheduled_datetime);
|
||||||
|
return dayjs(dateA).diff(dayjs(dateB));
|
||||||
|
}).slice(0, 5);
|
||||||
|
}, [upcomingAppointments, upcomingScheduledAppointments, reminders]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = "Приемы";
|
document.title = "Приемы";
|
||||||
@ -199,18 +231,27 @@ const useAppointments = () => {
|
|||||||
placement: 'topRight',
|
placement: 'topRight',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (isErrorReminders) {
|
||||||
|
notification.error({
|
||||||
|
message: 'Ошибка',
|
||||||
|
description: 'Ошибка загрузки напоминаний.',
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
}, [
|
}, [
|
||||||
isErrorAppointments,
|
isErrorAppointments,
|
||||||
isErrorScheduledAppointments,
|
isErrorScheduledAppointments,
|
||||||
isErrorPatients,
|
isErrorPatients,
|
||||||
isErrorUpcomingAppointments,
|
isErrorUpcomingAppointments,
|
||||||
isErrorUpcomingScheduledAppointments
|
isErrorUpcomingScheduledAppointments,
|
||||||
|
isErrorReminders
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
patients,
|
patients,
|
||||||
appointments,
|
appointments,
|
||||||
scheduledAppointments,
|
scheduledAppointments,
|
||||||
|
reminders,
|
||||||
isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients ||
|
isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients ||
|
||||||
isLoadingUpcomingAppointments || isLoadingUpcomingScheduledAppointments,
|
isLoadingUpcomingAppointments || isLoadingUpcomingScheduledAppointments,
|
||||||
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients ||
|
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients ||
|
||||||
@ -242,4 +283,4 @@ const useAppointments = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useAppointments;
|
export default useAppointmentsPage;
|
||||||
Loading…
x
Reference in New Issue
Block a user