andrei 0c326d815a refactor: Обновление UI компонентов и хуков
Перемещены и рефакторизованы виджеты и хуки для улучшения структуры.
Обновлены стили и тексты в модальных окнах.
2025-06-02 16:31:44 +05:00

179 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {Button, FloatButton, List, Result, Space, Typography} from "antd";
import {Splitter} from "antd";
import {
CalendarOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
PlusOutlined,
ClockCircleOutlined, DatabaseOutlined
} from "@ant-design/icons";
import AppointmentsCalendarTab from "./Components/AppointmentCalendarTab/AppointmentsCalendarTab.jsx";
import useAppointmentsUI from "./useAppointmentsUI.js";
import useAppointments from "./useAppointments.js";
import dayjs from 'dayjs';
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
import AppointmentFormModal from "../../Dummies/AppointmentFormModal/AppointmentFormModal.jsx";
import {useDispatch} from "react-redux";
import {
closeModal,
openModal,
setSelectedAppointment,
setSelectedScheduledAppointment
} from "../../../Redux/Slices/appointmentsSlice.js";
import AppointmentViewModal from "../../Widgets/AppointmentViewModal/AppointmentViewModal.jsx";
import ScheduledAppointmentFormModal from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx";
import ScheduledAppointmentsViewModal
from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
import AppointmentsListModal from "./Components/AppointmentsListModal/AppointmentsListModal.jsx";
const AppointmentsPage = () => {
const appointmentsData = useAppointments();
const appointmentsPageUI = useAppointmentsUI(appointmentsData.appointments, appointmentsData.scheduledAppointments);
const dispatch = useDispatch();
const handleEventClick = (event) => {
if (event.appointment_datetime) {
dispatch(setSelectedAppointment(event));
} else {
dispatch(setSelectedScheduledAppointment(event));
}
};
if (appointmentsData.isError) return (
<Result
status="error"
title="Ошибка"
subTitle="Произошла ошибка в работе страницы"
/>
);
return (
<>
<Typography.Title level={1}><CalendarOutlined/> Приемы</Typography.Title>
{appointmentsData.isLoading ? (
<LoadingIndicator/>
) : (
<>
<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%"
>
<AppointmentsCalendarTab/>
</Splitter.Panel>
{appointmentsPageUI.showSplitterPanel && (
<Splitter.Panel
style={appointmentsPageUI.splitterSiderPanelStyle}
defaultSize="20%"
min="20%"
max="75%"
>
<Typography.Title level={3} style={appointmentsPageUI.siderTitleStyle}>
Предстоящие события
</Typography.Title>
{appointmentsPageUI.upcomingEvents.length ? (
<List
dataSource={appointmentsPageUI.upcomingEvents.sort((a, b) =>
dayjs(a.appointment_datetime || a.scheduled_datetime).diff(
dayjs(b.appointment_datetime || b.scheduled_datetime)
)
)}
renderItem={(item) => (
<List.Item
onClick={() => handleEventClick(item)}
style={{
padding: "12px",
marginBottom: "8px",
borderRadius: "4px",
background: item.appointment_datetime ? "#e6f7ff" : "#f6ffed",
cursor: "pointer",
transition: "background 0.3s",
}}
onMouseEnter={(e) => (e.currentTarget.style.background = item.appointment_datetime ? "#d9efff" : "#efffdb")}
onMouseLeave={(e) => (e.currentTarget.style.background = item.appointment_datetime ? "#e6f7ff" : "#f6ffed")}
>
<Space direction="vertical" size={2}>
<Space>
{item.appointment_datetime ? (
<ClockCircleOutlined style={{color: "#1890ff"}}/>
) : (
<CalendarOutlined style={{color: "#52c41a"}}/>
)}
<Typography.Text strong>
{dayjs(item.appointment_datetime || item.scheduled_datetime).format('DD.MM.YYYY HH:mm')}
</Typography.Text>
</Space>
<Typography.Text>
{item.appointment_datetime ? 'Прием' : 'Запланировано'}
{item.patient ? ` - ${item.patient.last_name} ${item.patient.first_name}` : ''}
</Typography.Text>
<Typography.Text type="secondary">
Тип: {item.type?.title || 'Не указан'}
</Typography.Text>
{dayjs(item.appointment_datetime || item.scheduled_datetime).isSame(dayjs(), 'day') && (
<Typography.Text type="warning">Сегодня</Typography.Text>
)}
</Space>
</List.Item>
)}
/>
) : (
<Typography.Text type="secondary">Нет предстоящих событий</Typography.Text>
)}
</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>
<FloatButton.Group
placement={"left"}
trigger="hover"
type="primary"
icon={<PlusOutlined/>}
tooltip="Создать"
>
<FloatButton
icon={<PlusOutlined/>}
onClick={() => dispatch(openModal())}
tooltip="Прием"
/>
<FloatButton
icon={<CalendarOutlined/>}
onClick={appointmentsPageUI.openCreateScheduledAppointmentModal}
tooltip="Запланированный прием"
/>
</FloatButton.Group>
<AppointmentFormModal/>
<AppointmentViewModal/>
<ScheduledAppointmentFormModal/>
<ScheduledAppointmentsViewModal/>
<AppointmentsListModal/>
</>
)}
</>
);
};
export default AppointmentsPage;