183 lines
6.5 KiB
JavaScript
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;
|