refactor: appointments UI

Перемещены и переименованы компоненты Appointments.
This commit is contained in:
Андрей Дувакин 2025-06-29 09:49:26 +05:00
parent c3d77738a7
commit 04242d63f1
7 changed files with 126 additions and 76 deletions

View File

@ -33,10 +33,8 @@ const MainLayout = () => {
}
menuItems.push(
mainLayoutData.getItem("Мой профиль", "profile", <UserOutlined/>, [
mainLayoutData.getItem("Перейти в профиль", "/profile", <UserOutlined/>),
mainLayoutData.getItem("Выйти", "logout", <LogoutOutlined/>)
])
mainLayoutData.getItem("Перейти в профиль", "/profile", <UserOutlined/>),
mainLayoutData.getItem("Выйти", "logout", <LogoutOutlined/>)
);
if (mainLayoutData.isUserError) {
@ -45,48 +43,101 @@ const MainLayout = () => {
return (
<Layout style={{minHeight: "100vh"}}>
<Sider
collapsible={!mainLayoutData.screens.xs}
collapsed={mainLayoutData.collapsed}
onCollapse={mainLayoutData.setCollapsed}
style={{height: "100vh", position: "fixed", left: 0, overflow: "auto"}}
>
<div style={{display: "flex", justifyContent: "center", padding: 16}}>
<img
src="/logo_rounded.png"
alt="Логотип"
style={{width: mainLayoutData.collapsed ? 40 : 80, transition: "width 0.2s"}}
/>
</div>
<Menu
theme="dark"
selectedKeys={[location.pathname]}
mode="inline"
items={menuItems}
onClick={mainLayoutData.handleMenuClick}
/>
</Sider>
{mainLayoutData.screens.xs ? (
<>
<Content style={{
margin: "0 8px",
padding: 24,
flex: 1,
overflow: "auto",
background: "#fff",
borderRadius: 8,
marginTop: "8px"
}}>
{mainLayoutData.isUserLoading ? (
<LoadingIndicator/>
) : (
<Outlet/>
)}
</Content>
<Layout.Header style={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
display: "flex",
alignItems: "center",
padding: "0 16px",
background: "#001529",
zIndex: 1000
}}>
<div style={{display: "flex", alignItems: "center", paddingRight: 16}}>
<img
src="/logo_rounded.png"
alt="Логотип"
style={{width: 40}}
/>
</div>
<Menu
theme="dark"
mode="horizontal"
selectedKeys={[mainLayoutData.location.pathname]}
items={menuItems}
onClick={mainLayoutData.handleMenuClick}
style={{flex: 1, minWidth: 0}}
/>
</Layout.Header>
<Footer style={{textAlign: "center", padding: "12px 0", marginBottom: 48}}>
Visus+ © {new Date().getFullYear()}
</Footer>
</>
) : (
<>
<Sider
collapsible={!mainLayoutData.screens.xs}
collapsed={mainLayoutData.collapsed}
onCollapse={mainLayoutData.setCollapsed}
style={{height: "100vh", position: "fixed", left: 0, overflow: "auto"}}
>
<div style={{display: "flex", justifyContent: "center", padding: 16}}>
<img
src="/logo_rounded.png"
alt="Логотип"
style={{width: mainLayoutData.collapsed ? 40 : 80, transition: "width 0.2s"}}
/>
</div>
<Menu
theme="dark"
selectedKeys={[location.pathname]}
mode="inline"
items={menuItems}
onClick={mainLayoutData.handleMenuClick}
/>
</Sider>
<Layout
style={{marginLeft: mainLayoutData.collapsed ? 80 : 200, transition: "margin-left 0.2s"}}
>
<Content style={{
margin: "0 16px",
padding: 24,
minHeight: "100vh",
overflow: "auto",
background: "#fff",
borderRadius: 8,
marginTop: "15px"
}}>
{mainLayoutData.isUserLoading ? (
<LoadingIndicator/>
) : (
<Outlet/>
)}
</Content>
<Footer style={{textAlign: "center"}}>Visus+ © {new Date().getFullYear()}</Footer>
</Layout>
</>
)}
<Layout
style={{marginLeft: mainLayoutData.collapsed ? 80 : 200, transition: "margin-left 0.2s"}}
>
<Content style={{
margin: "0 16px",
padding: 24,
minHeight: "100vh",
overflow: "auto",
background: "#fff",
borderRadius: 8,
marginTop: "15px"
}}>
{mainLayoutData.isUserLoading ? (
<LoadingIndicator/>
) : (
<Outlet/>
)}
</Content>
<Footer style={{textAlign: "center"}}>Visus+ © {new Date().getFullYear()}</Footer>
</Layout>
</Layout>
);
};

View File

@ -7,7 +7,7 @@ import {
PlusOutlined,
ClockCircleOutlined,
} from "@ant-design/icons";
import AppointmentsCalendarTab from "./Components/AppointmentCalendarTab/AppointmentsCalendarTab.jsx";
import AppointmentsCalendar from "./Components/AppointmentCalendar/AppointmentsCalendar.jsx";
import useAppointments from "./useAppointments.js";
import dayjs from 'dayjs';
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
@ -87,7 +87,7 @@ const AppointmentsPage = () => {
min="25%"
max="90%"
>
<AppointmentsCalendarTab
<AppointmentsCalendar
currentMonth={currentMonth}
onMonthChange={handleMonthChange}
appointments={appointments} // Добавляем

View File

@ -1,13 +1,13 @@
import {Calendar} from "antd";
import "dayjs/locale/ru";
import CalendarCell from "../CalendarCell/CalendarCell.jsx";
import useAppointmentCalendarUI from "./useAppointmentCalendarUI.js";
import useAppointmentCalendar from "./useAppointmentCalendar.js";
import AppointmentsListModal from "../AppointmentsListModal/AppointmentsListModal.jsx";
import dayjs from "dayjs";
import PropTypes from "prop-types";
const AppointmentsCalendarTab = ({currentMonth, onMonthChange, appointments, scheduledAppointments}) => {
const appointmentsCalendarUI = useAppointmentCalendarUI(appointments, scheduledAppointments);
const AppointmentsCalendar = ({currentMonth, onMonthChange, appointments, scheduledAppointments}) => {
const appointmentsCalendarUI = useAppointmentCalendar(appointments, scheduledAppointments);
const dateCellRender = (value) => {
const appointmentsForDate = appointmentsCalendarUI.getAppointmentsByListAndDate(
@ -39,12 +39,11 @@ const AppointmentsCalendarTab = ({currentMonth, onMonthChange, appointments, sch
<div style={appointmentsCalendarUI.calendarContainerStyle}>
<Calendar
fullscreen={appointmentsCalendarUI.fullScreenCalendar}
value={currentMonth} // Используем currentMonth вместо selectedDate
onSelect={appointmentsCalendarUI.onSelect}
value={currentMonth}
onPanelChange={(value, mode) => {
appointmentsCalendarUI.onPanelChange(value, mode);
if (mode === "month") {
onMonthChange(value); // Вызываем onMonthChange при смене месяца
onMonthChange(value);
}
}}
cellRender={dateCellRender}
@ -54,11 +53,11 @@ const AppointmentsCalendarTab = ({currentMonth, onMonthChange, appointments, sch
);
};
AppointmentsCalendarTab.propTypes = {
AppointmentsCalendar.propTypes = {
currentMonth: PropTypes.object.isRequired,
onMonthChange: PropTypes.func.isRequired,
appointments: PropTypes.array.isRequired,
scheduledAppointments: PropTypes.array.isRequired,
};
export default AppointmentsCalendarTab;
export default AppointmentsCalendar;

View File

@ -17,7 +17,7 @@ dayjs.tz.setDefault("Europe/Moscow");
const { useBreakpoint } = Grid;
const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
const useAppointmentCalendar = (appointments, scheduledAppointments) => {
const dispatch = useDispatch();
const selectedDate = dayjs.tz(useSelector((state) => state.appointmentsUI.selectedDate), "Europe/Moscow");
@ -75,4 +75,4 @@ const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
};
};
export default useAppointmentCalendarUI;
export default useAppointmentCalendar;

View File

@ -2,7 +2,7 @@ import {Badge, Col, Tag, Tooltip} from "antd";
import PropTypes from "prop-types";
import {AppointmentPropType} from "../../../../../Types/appointmentPropType.js";
import {ScheduledAppointmentPropType} from "../../../../../Types/scheduledAppointmentPropType.js";
import useCalendarCellUI from "./useCalendarCellUI.js";
import useCalendarCell from "./useCalendarCell.js";
const CalendarCell = ({allAppointments, onCellClick, onItemClick}) => {
const {
@ -18,7 +18,7 @@ const CalendarCell = ({allAppointments, onCellClick, onItemClick}) => {
getBadgeText,
getTagColor,
getBadgeStatus,
} = useCalendarCellUI();
} = useCalendarCell();
return (
<div

View File

@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from "react";
import dayjs from "dayjs";
const useCalendarCellUI = () => {
const useCalendarCell = () => {
const containerRef = useRef(null);
const [isCompressed, setIsCompressed] = useState(false);
const COMPRESSION_THRESHOLD = 70;
@ -53,7 +53,7 @@ const useCalendarCellUI = () => {
const compressedCountStyle = {
position: "absolute",
top: 2,
bottom: 12,
right: 2,
fontSize: 10,
fontWeight: "bold",
@ -108,4 +108,4 @@ const useCalendarCellUI = () => {
};
};
export default useCalendarCellUI;
export default useCalendarCell;

View File

@ -1,12 +1,12 @@
import { useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { notification } from "antd";
import { Grid } from "antd";
import {useEffect, useMemo, useState} from "react";
import {useDispatch, useSelector} from "react-redux";
import {notification} from "antd";
import {Grid} from "antd";
import {
useGetAppointmentsQuery,
useGetUpcomingAppointmentsQuery,
} from "../../../Api/appointmentsApi.js";
import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js";
import {useGetAllPatientsQuery} from "../../../Api/patientsApi.js";
import {
openModal,
openScheduledModal,
@ -26,12 +26,12 @@ import timezone from "dayjs/plugin/timezone";
dayjs.extend(utc);
dayjs.extend(timezone);
const { useBreakpoint } = Grid;
const {useBreakpoint} = Grid;
const useAppointments = () => {
const dispatch = useDispatch();
const { userData } = useSelector(state => state.auth);
const { collapsed, siderWidth, hovered, selectedAppointment } = useSelector(state => state.appointmentsUI);
const {userData} = useSelector(state => state.auth);
const {collapsed, siderWidth, hovered, selectedAppointment} = useSelector(state => state.appointmentsUI);
const screens = useBreakpoint();
const [currentMonth, setCurrentMonth] = useState(dayjs().startOf('month'));
@ -47,7 +47,7 @@ const useAppointments = () => {
data: appointments = [],
isLoading: isLoadingAppointments,
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: 60000,
skip: !userData.id,
});
@ -56,7 +56,7 @@ const useAppointments = () => {
data: scheduledAppointments = [],
isLoading: isLoadingScheduledAppointments,
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: 60000,
skip: !userData.id,
});
@ -90,10 +90,10 @@ const useAppointments = () => {
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
const splitterStyle = { flex: 1 };
const splitterContentPanelStyle = { padding: 16 };
const splitterSiderPanelStyle = { padding: "16px", borderLeft: "1px solid #ddd", overflowY: "auto" };
const siderTitleStyle = { marginBottom: 36 };
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,