visus-plus/web-app/src/layouts/AppointmentsLayout.jsx

183 lines
6.5 KiB
JavaScript

import {useEffect, useState} from "react";
import {Button, Grid, notification, Tabs, Typography} from "antd";
import {Splitter} from "antd";
import {
CalendarOutlined, TableOutlined, MenuFoldOutlined, MenuUnfoldOutlined,
} from "@ant-design/icons";
import AppointmentsCalendarPage from "../pages/appointments_layout/AppointmentsCalendarPage.jsx";
import AppointmentsTablePage from "../pages/appointments_layout/AppointmentsTablePage.jsx";
import getAllAppointments from "../api/appointments/getAllAppointments.jsx";
import getAllScheduledAppointments from "../api/scheduled_appointments/getAllScheduledAppointments.jsx";
import {useAuth} from "../AuthContext.jsx";
import LoadingIndicator from "../components/LoadingIndicator.jsx";
import {cacheInfo, getCachedInfo, getCacheTimestamp} from "../utils/cachedInfoUtils.jsx";
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 () => {
try {
const data = await getAllAppointments(api);
setAppointments(data);
cacheInfo("appointmentsData", data);
} catch (error) {
console.log(error);
notification.error({
message: "Ошибка загрузки данных", description: "Проверьте подключение к сети.", placement: "topRight",
});
}
};
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 () => {
try {
const data = await getAllScheduledAppointments(api);
setScheduledAppointments(data);
cacheInfo("scheduledAppointmentsData", data);
} catch (error) {
console.log(error);
notification.error({
message: "Ошибка загрузки данных", description: "Проверьте подключение к сети.", placement: "topRight",
});
}
};
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;