diff --git a/api/app/application/scheduled_appointments_repository.py b/api/app/application/scheduled_appointments_repository.py
index 9bebcc8..6692e84 100644
--- a/api/app/application/scheduled_appointments_repository.py
+++ b/api/app/application/scheduled_appointments_repository.py
@@ -17,7 +17,7 @@ class ScheduledAppointmentsRepository:
.options(joinedload(ScheduledAppointment.type))
.options(joinedload(ScheduledAppointment.patient))
.options(joinedload(ScheduledAppointment.doctor))
- .order_by(desc(ScheduledAppointment.appointment_datetime))
+ .order_by(desc(ScheduledAppointment.scheduled_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
@@ -29,7 +29,7 @@ class ScheduledAppointmentsRepository:
.options(joinedload(ScheduledAppointment.patient))
.options(joinedload(ScheduledAppointment.doctor))
.filter(ScheduledAppointment.doctor_id == doctor_id)
- .order_by(desc(ScheduledAppointment.appointment_datetime))
+ .order_by(desc(ScheduledAppointment.scheduled_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
@@ -41,7 +41,7 @@ class ScheduledAppointmentsRepository:
.options(joinedload(ScheduledAppointment.patient))
.options(joinedload(ScheduledAppointment.doctor))
.filter(ScheduledAppointment.patient_id == patient_id)
- .order_by(desc(ScheduledAppointment.appointment_datetime))
+ .order_by(desc(ScheduledAppointment.scheduled_datetime))
)
result = await self.db.execute(stmt)
return result.scalars().all()
diff --git a/web-app/src/components/PrivateRoute.jsx b/web-app/src/components/PrivateRoute.jsx
index f6e6b84..c63bd7c 100644
--- a/web-app/src/components/PrivateRoute.jsx
+++ b/web-app/src/components/PrivateRoute.jsx
@@ -12,4 +12,4 @@ const PrivateRoute = () => {
};
-export default PrivateRoute;
+export default PrivateRoute;
\ No newline at end of file
diff --git a/web-app/src/components/SelectViewMode.jsx b/web-app/src/components/SelectViewMode.jsx
index cc48c28..7ce9659 100644
--- a/web-app/src/components/SelectViewMode.jsx
+++ b/web-app/src/components/SelectViewMode.jsx
@@ -2,6 +2,7 @@ import {BuildOutlined, TableOutlined} from "@ant-design/icons";
import {Select, Tooltip} from "antd";
import PropTypes from "prop-types";
import {cacheInfo} from "../utils/cachedInfoUtils.jsx";
+import {ViewModPropType} from "../types/viewModPropType.jsx";
const {Option} = Select;
@@ -35,11 +36,7 @@ SelectViewMode.propTypes = {
setViewMode: PropTypes.func.isRequired,
localStorageKey: PropTypes.string.isRequired,
toolTipText: PropTypes.string.isRequired,
- viewModes: PropTypes.arrayOf(PropTypes.shape({
- value: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- icon: PropTypes.element,
- })).isRequired,
+ viewModes: PropTypes.arrayOf(ViewModPropType).isRequired,
};
export default SelectViewMode;
\ No newline at end of file
diff --git a/web-app/src/components/appointments/AppointmentCellViewModal.jsx b/web-app/src/components/appointments/AppointmentCellViewModal.jsx
new file mode 100644
index 0000000..65892cb
--- /dev/null
+++ b/web-app/src/components/appointments/AppointmentCellViewModal.jsx
@@ -0,0 +1,7 @@
+
+
+
+
+const AppointmentCellViewModal = ({appointment}) => {
+
+};
\ No newline at end of file
diff --git a/web-app/src/components/appointments/CalendarCell.jsx b/web-app/src/components/appointments/CalendarCell.jsx
new file mode 100644
index 0000000..591360c
--- /dev/null
+++ b/web-app/src/components/appointments/CalendarCell.jsx
@@ -0,0 +1,109 @@
+import {useEffect, useRef, useState} from "react";
+import {Badge, Col, Tag, Tooltip, Typography} from "antd";
+import dayjs from "dayjs";
+import PropTypes from "prop-types";
+import {AppointmentPropType} from "../../types/appointmentPropType.jsx";
+import {ScheduledAppointmentPropType} from "../../types/scheduledAppointmentPropType.jsx";
+
+
+const CalendarCell = ({appointments, scheduledAppointments, onCellClick, onItemClick}) => {
+ const containerRef = useRef(null);
+ const [isCompressed, setIsCompressed] = useState(false);
+ const COMPRESSION_THRESHOLD = 70;
+
+ useEffect(() => {
+ if (!containerRef.current) return;
+
+ const observer = new ResizeObserver((entries) => {
+ const width = entries[0].contentRect.width;
+ setIsCompressed(width < COMPRESSION_THRESHOLD);
+ });
+
+ observer.observe(containerRef.current);
+ return () => observer.disconnect();
+ }, []);
+
+ return (
+
+ {!isCompressed && (
+
+ {appointments.map(app => (
+
+
+ {
+ e.stopPropagation();
+ onItemClick(app);
+ }}
+ style={{margin: '2px 0', cursor: 'pointer'}}
+ >
+
+
+
+
+ ))}
+ {scheduledAppointments.map(app => (
+
+
+ {
+ e.stopPropagation();
+ onItemClick(app);
+ }}
+ style={{margin: '2px 0', cursor: 'pointer'}}
+ >
+
+
+
+
+ ))}
+
+ )}
+ {isCompressed && (
+
+ {appointments.length + scheduledAppointments.length > 0 && `+${appointments.length + scheduledAppointments.length}`}
+
+ )}
+
+ );
+};
+
+CalendarCell.propTypes = {
+ appointments: PropTypes.arrayOf(AppointmentPropType).isRequired,
+ scheduledAppointments: PropTypes.arrayOf(ScheduledAppointmentPropType).isRequired,
+ onCellClick: PropTypes.func.isRequired,
+ onItemClick: PropTypes.func.isRequired,
+};
+
+export default CalendarCell;
\ No newline at end of file
diff --git a/web-app/src/components/lens_issues/LensIssueFormModal.jsx b/web-app/src/components/lens_issues/LensIssueFormModal.jsx
index 6b7abd1..93a20cf 100644
--- a/web-app/src/components/lens_issues/LensIssueFormModal.jsx
+++ b/web-app/src/components/lens_issues/LensIssueFormModal.jsx
@@ -36,27 +36,13 @@ const LensIssueFormModal = ({visible, onCancel, onSubmit}) => {
}, [visible]);
const fetchPatients = async () => {
- try {
- const data = await getAllPatients(api);
- setPatients(data);
- } catch (error) {
- console.error(error);
- notification.error({
- message: "Ошибка загрузки пациентов", description: "Проверьте подключение к сети.",
- });
- }
+ const data = await getAllPatients(api);
+ setPatients(data);
};
const fetchLenses = async () => {
- try {
- const data = await getNotIssuedLenses(api);
- setLenses(data);
- } catch (error) {
- console.error(error);
- notification.error({
- message: "Ошибка загрузки линз", description: "Проверьте подключение к сети.",
- });
- }
+ const data = await getNotIssuedLenses(api);
+ setLenses(data);
};
const handleOk = async () => {
@@ -324,7 +310,9 @@ const LensIssueFormModal = ({visible, onCancel, onSubmit}) => {
};
LensIssueFormModal.propTypes = {
- visible: PropTypes.bool.isRequired, onCancel: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
+ visible: PropTypes.bool.isRequired,
+ onCancel: PropTypes.func.isRequired,
+ onSubmit: PropTypes.func.isRequired,
};
export default LensIssueFormModal;
diff --git a/web-app/src/components/lens_issues/LensIssueViewModal.jsx b/web-app/src/components/lens_issues/LensIssueViewModal.jsx
index 85f7362..5d9612c 100644
--- a/web-app/src/components/lens_issues/LensIssueViewModal.jsx
+++ b/web-app/src/components/lens_issues/LensIssueViewModal.jsx
@@ -1,5 +1,6 @@
import {Collapse, Modal} from "antd";
import PropTypes from "prop-types";
+import {LensIssuePropType} from "../../types/lensIssuePropType.jsx";
const LensIssueViewModal = ({visible, onCancel, lensIssue}) => {
@@ -69,39 +70,9 @@ const LensIssueViewModal = ({visible, onCancel, lensIssue}) => {
};
LensIssueViewModal.propTypes = {
- visible: PropTypes.bool,
- onCancel: PropTypes.func,
- lensIssue: PropTypes.shape({
- issue_date: PropTypes.string,
- patient: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- patronymic: PropTypes.string,
- birthday: PropTypes.string,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }),
- doctor: PropTypes.shape({
- last_name: PropTypes.string,
- first_name: PropTypes.string,
- login: PropTypes.string,
- }),
- lens: PropTypes.shape({
- id: PropTypes.number.isRequired,
- tor: PropTypes.number.isRequired,
- diameter: PropTypes.number.isRequired,
- esa: PropTypes.number.isRequired,
- fvc: PropTypes.number.isRequired,
- preset_refraction: PropTypes.number.isRequired,
- periphery_toricity: PropTypes.number.isRequired,
- side: PropTypes.string.isRequired,
- issued: PropTypes.bool.isRequired,
- trial: PropTypes.number.isRequired,
- }),
- }),
+ visible: PropTypes.bool.isRequired,
+ onCancel: PropTypes.func.isRequired,
+ lensIssue: LensIssuePropType.isRequired,
};
export default LensIssueViewModal;
\ No newline at end of file
diff --git a/web-app/src/components/lenses/LensFormModal.jsx b/web-app/src/components/lenses/LensFormModal.jsx
index 4d0dbdb..6762d04 100644
--- a/web-app/src/components/lenses/LensFormModal.jsx
+++ b/web-app/src/components/lenses/LensFormModal.jsx
@@ -3,6 +3,7 @@ import {useEffect, useState} from "react";
import PropTypes from "prop-types";
import getAllLensTypes from "../../api/lens_types/getAllLensTypes.jsx";
import {useAuth} from "../../AuthContext.jsx";
+import {LensPropType} from "../../types/lensPropType.jsx";
const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
@@ -26,17 +27,8 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
}, [visible, lens]);
const fetchLensTypes = async () => {
- try {
- const data = await getAllLensTypes(api);
- setLensTypes(data);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки типов линз",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ const data = await getAllLensTypes(api);
+ setLensTypes(data);
};
const handleOk = async () => {
@@ -199,18 +191,7 @@ LensFormModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
- lens: PropTypes.shape({
- tor: PropTypes.number.isRequired,
- trial: PropTypes.number.isRequired,
- esa: PropTypes.number.isRequired,
- fvc: PropTypes.number.isRequired,
- preset_refraction: PropTypes.number.isRequired,
- diameter: PropTypes.number.isRequired,
- periphery_toricity: PropTypes.number.isRequired,
- side: PropTypes.string.isRequired,
- issued: PropTypes.bool.isRequired,
- type_id: PropTypes.number.isRequired,
- }),
+ lens: LensPropType.isRequired,
}
export default LensFormModal;
\ No newline at end of file
diff --git a/web-app/src/components/lenses/LensListCard.jsx b/web-app/src/components/lenses/LensListCard.jsx
index 3b6fccb..cefce5c 100644
--- a/web-app/src/components/lenses/LensListCard.jsx
+++ b/web-app/src/components/lenses/LensListCard.jsx
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
import {useState} from "react";
import LensViewModal from "./LensViewModal.jsx";
+import {LensPropType} from "../../types/lensPropType.jsx";
const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {
const [showModalInfo, setShowModalInfo] = useState(false);
@@ -61,18 +62,7 @@ const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {
};
LensListCard.propTypes = {
- lens: PropTypes.shape({
- id: PropTypes.number.isRequired,
- tor: PropTypes.number.isRequired,
- trial: PropTypes.number,
- esa: PropTypes.number,
- fvc: PropTypes.number,
- preset_refraction: PropTypes.number.isRequired,
- diameter: PropTypes.number.isRequired,
- periphery_toricity: PropTypes.number.isRequired,
- side: PropTypes.string.isRequired,
- issued: PropTypes.bool.isRequired,
- }).isRequired,
+ lens: LensPropType.isRequired,
handleEditLens: PropTypes.func.isRequired,
handleDeleteLens: PropTypes.func.isRequired,
};
diff --git a/web-app/src/components/lenses/LensViewModal.jsx b/web-app/src/components/lenses/LensViewModal.jsx
index 394c9c1..54e6ad3 100644
--- a/web-app/src/components/lenses/LensViewModal.jsx
+++ b/web-app/src/components/lenses/LensViewModal.jsx
@@ -1,5 +1,6 @@
import {Button, Col, Modal, Row, Typography} from "antd";
import PropTypes from "prop-types";
+import {LensPropType} from "../../types/lensPropType.jsx";
const {Text, Title} = Typography;
@@ -72,17 +73,7 @@ const LensViewModal = ({visible, onCancel, lens}) => {
LensViewModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
- lens: PropTypes.shape({
- tor: PropTypes.number.isRequired,
- diameter: PropTypes.number.isRequired,
- esa: PropTypes.number.isRequired,
- fvc: PropTypes.number.isRequired,
- preset_refraction: PropTypes.number.isRequired,
- periphery_toricity: PropTypes.number.isRequired,
- side: PropTypes.string.isRequired,
- issued: PropTypes.bool.isRequired,
- trial: PropTypes.number.isRequired,
- }),
+ lens: LensPropType.isRequired,
};
export default LensViewModal;
diff --git a/web-app/src/components/patients/PatientFormModal.jsx b/web-app/src/components/patients/PatientFormModal.jsx
index 6aad3c5..ce7c0c0 100644
--- a/web-app/src/components/patients/PatientFormModal.jsx
+++ b/web-app/src/components/patients/PatientFormModal.jsx
@@ -5,6 +5,7 @@ import locale from "antd/es/date-picker/locale/ru_RU";
import validator from "validator";
import {MaskedInput} from "antd-mask-input";
import dayjs from "dayjs";
+import {PatientPropType} from "../../types/patientPropType.jsx";
const {TextArea} = Input;
@@ -141,17 +142,7 @@ PatientFormModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
- patient: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- patronymic: PropTypes.string,
- birthday: PropTypes.string,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }),
+ patient: PatientPropType.isRequired,
};
export default PatientFormModal;
diff --git a/web-app/src/components/patients/PatientListCard.jsx b/web-app/src/components/patients/PatientListCard.jsx
index 60f4ff8..cb8a3a7 100644
--- a/web-app/src/components/patients/PatientListCard.jsx
+++ b/web-app/src/components/patients/PatientListCard.jsx
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
import {useState} from "react";
import PatientViewModal from "./PatientViewModal.jsx";
+import {PatientPropType} from "../../types/patientPropType.jsx";
const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
const [showModalInfo, setShowModalInfo] = useState(false);
@@ -73,20 +74,9 @@ const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
};
PatientListCard.propTypes = {
- patient: PropTypes.shape({
- id: PropTypes.number.isRequired,
- last_name: PropTypes.string.isRequired,
- first_name: PropTypes.string.isRequired,
- patronymic: PropTypes.string,
- birthday: PropTypes.string.isRequired,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }).isRequired,
+ patient: PatientPropType.isRequired,
handleEditPatient: PropTypes.func.isRequired,
handleDeletePatient: PropTypes.func.isRequired,
};
-export default PatientListCard;
+export default PatientListCard;
\ No newline at end of file
diff --git a/web-app/src/components/patients/PatientViewModal.jsx b/web-app/src/components/patients/PatientViewModal.jsx
index 328e007..8262fcf 100644
--- a/web-app/src/components/patients/PatientViewModal.jsx
+++ b/web-app/src/components/patients/PatientViewModal.jsx
@@ -1,5 +1,6 @@
import {Button, Col, Modal, Row, Typography, Divider} from "antd";
import PropTypes from "prop-types";
+import {PatientPropType} from "../../types/patientPropType.jsx";
const { Text, Title } = Typography;
@@ -72,17 +73,7 @@ const PatientViewModal = ({ visible, onCancel, patient }) => {
PatientViewModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
- patient: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- patronymic: PropTypes.string,
- birthday: PropTypes.string,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }),
+ patient: PatientPropType.isRequired,
};
export default PatientViewModal;
diff --git a/web-app/src/components/sets/SetFormModal.jsx b/web-app/src/components/sets/SetFormModal.jsx
index 38805f6..f1eda0e 100644
--- a/web-app/src/components/sets/SetFormModal.jsx
+++ b/web-app/src/components/sets/SetFormModal.jsx
@@ -6,6 +6,7 @@ import getAllLensTypes from "../../api/lens_types/getAllLensTypes.jsx";
import {useAuth} from "../../AuthContext.jsx";
import PropTypes from "prop-types";
import getSetContentBySetId from "../../api/set_content/getSetContentBySetId.jsx";
+import {SetPropType} from "../../types/setPropType.jsx";
const {Option} = Select;
@@ -32,31 +33,13 @@ const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
const fetchSetContents = async () => {
if (!setData) return;
- try {
- const data = await getSetContentBySetId(api, setData.id);
- setContent(data);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки контента",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ const data = await getSetContentBySetId(api, setData.id);
+ setContent(data);
};
const fetchLensTypes = async () => {
- try {
- const data = await getAllLensTypes(api);
- setLensTypes(data);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки типов линз",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ const data = await getAllLensTypes(api);
+ setLensTypes(data);
};
const addContentItem = () => {
@@ -272,10 +255,7 @@ SetFormModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
- setData: PropTypes.shape({
- id: PropTypes.number,
- title: PropTypes.string,
- }),
+ setData: SetPropType.isRequired,
}
-export default SetFormModal;
+export default SetFormModal;
\ No newline at end of file
diff --git a/web-app/src/components/sets/SetListCard.jsx b/web-app/src/components/sets/SetListCard.jsx
index c84614a..7b16af6 100644
--- a/web-app/src/components/sets/SetListCard.jsx
+++ b/web-app/src/components/sets/SetListCard.jsx
@@ -1,6 +1,7 @@
import PropTypes from "prop-types";
import {Card, Modal, Popconfirm, Tooltip} from "antd";
import {DeleteOutlined, EditOutlined, PlusOutlined} from "@ant-design/icons";
+import {SetPropType} from "../../types/setPropType.jsx";
const SetListCard = ({set, handleEditSet, handleDeleteSet, handleAppendSet}) => {
const deleteSet = () => {
@@ -59,10 +60,7 @@ const SetListCard = ({set, handleEditSet, handleDeleteSet, handleAppendSet}) =>
};
SetListCard.propTypes = {
- set: PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- }).isRequired,
+ set: SetPropType.isRequired,
handleEditSet: PropTypes.func.isRequired,
handleAppendSet: PropTypes.func.isRequired,
handleDeleteSet: PropTypes.func.isRequired,
diff --git a/web-app/src/layouts/AppointmentsLayout.jsx b/web-app/src/layouts/AppointmentsLayout.jsx
index 425fab3..a8534b6 100644
--- a/web-app/src/layouts/AppointmentsLayout.jsx
+++ b/web-app/src/layouts/AppointmentsLayout.jsx
@@ -1,5 +1,5 @@
import {useEffect, useState} from "react";
-import {Button, Grid, notification, Tabs, Typography} from "antd";
+import {Button, Grid, Tabs, Typography} from "antd";
import {Splitter} from "antd";
import {
CalendarOutlined, TableOutlined, MenuFoldOutlined, MenuUnfoldOutlined,
@@ -62,17 +62,9 @@ const AppointmentsLayout = () => {
};
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 data = await getAllAppointments(api);
+ setAppointments(data);
+ cacheInfo("appointmentsData", data);
};
const fetchScheduledAppointmentsWithCache = async () => {
@@ -88,17 +80,9 @@ const AppointmentsLayout = () => {
};
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 data = await getAllScheduledAppointments(api);
+ setScheduledAppointments(data);
+ cacheInfo("scheduledAppointmentsData", data);
};
const items = [{
@@ -179,4 +163,4 @@ const AppointmentsLayout = () => {
);
};
-export default AppointmentsLayout;
+export default AppointmentsLayout;
\ No newline at end of file
diff --git a/web-app/src/layouts/MainLayout.jsx b/web-app/src/layouts/MainLayout.jsx
index d3e09c9..9362f95 100644
--- a/web-app/src/layouts/MainLayout.jsx
+++ b/web-app/src/layouts/MainLayout.jsx
@@ -92,4 +92,4 @@ const MainLayout = () => {
);
};
-export default MainLayout;
+export default MainLayout;
\ No newline at end of file
diff --git a/web-app/src/pages/IssuesPage.jsx b/web-app/src/pages/IssuesPage.jsx
index 22ff090..0c965f1 100644
--- a/web-app/src/pages/IssuesPage.jsx
+++ b/web-app/src/pages/IssuesPage.jsx
@@ -92,39 +92,20 @@ const IssuesPage = () => {
};
const handleSubmitFormModal = async (issue_date, patient_id, lens_id) => {
- try {
- await addLensIssue(api, {issue_date, patient_id, lens_id});
- setIsModalVisible(false);
- notification.success({
- message: "Линза выдана",
- description: "Линза успешно выдана пациенту.",
- placement: "topRight",
- });
- await fetchLensIssues();
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка добавления",
- description: "Не удалось выдать линзу пациенту.",
- placement: "topRight",
- });
- }
+ setIsModalVisible(false);
+ await addLensIssue(api, {issue_date, patient_id, lens_id});
+ notification.success({
+ message: "Линза выдана",
+ description: "Линза успешно выдана пациенту.",
+ placement: "topRight",
+ });
+ await fetchLensIssues();
};
const fetchLensIssues = async () => {
- try {
- const data = await getAllLensIssues(api);
- setLensIssues(data);
- setLoading(false);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки данных",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- setLoading(false);
- }
+ const data = await getAllLensIssues(api);
+ setLensIssues(data);
+ setLoading(false);
};
const handleSearch = (e) => {
diff --git a/web-app/src/pages/PatientsPage.jsx b/web-app/src/pages/PatientsPage.jsx
index 10ab986..b61345b 100644
--- a/web-app/src/pages/PatientsPage.jsx
+++ b/web-app/src/pages/PatientsPage.jsx
@@ -75,20 +75,10 @@ const PatientsPage = () => {
};
const fetchPatients = async () => {
- try {
- const data = await getAllPatients(api);
- setPatients(data);
-
- cacheInfo("patientsData", data);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки данных",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- })
- }
+ const data = await getAllPatients(api);
+ setPatients(data);
+ cacheInfo("patientsData", data);
setLoading(false);
};
@@ -124,22 +114,13 @@ const PatientsPage = () => {
};
const handleDeletePatient = async (patient_id) => {
- try {
- await deletePatient(api, patient_id);
- await fetchPatients();
- notification.success({
- message: "Пациент удалён",
- description: "Пациент успешно удалён из базы.",
- placement: "topRight",
- });
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка удаления",
- description: "Не удалось удалить пациента.",
- placement: "topRight",
- });
- }
+ await deletePatient(api, patient_id);
+ await fetchPatients();
+ notification.success({
+ message: "Пациент удалён",
+ description: "Пациент успешно удалён из базы.",
+ placement: "topRight",
+ });
};
const handleCancel = () => {
@@ -147,24 +128,14 @@ const PatientsPage = () => {
};
const handleModalPatientSubmit = async (newPatient) => {
- try {
- if (selectedPatient) {
- await editPatient(newPatient);
- } else {
- await addNewPatient(newPatient);
- }
- setIsModalVisible(false);
- await fetchPatients();
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка",
- description: error.response?.status === 401
- ? "Ошибка авторизации: пользователь не найден или токен недействителен"
- : "Не удалось сохранить данные пациента.",
- placement: "topRight",
- });
+ setIsModalVisible(false);
+
+ if (selectedPatient) {
+ await editPatient(newPatient);
+ } else {
+ await addNewPatient(newPatient);
}
+ await fetchPatients();
};
const editPatient = async (patient) => {
@@ -330,6 +301,7 @@ const PatientsPage = () => {
allowClear
/>
+
{viewMode === "tile" && (
{
);
};
-export default PatientsPage;
+export default PatientsPage;
\ No newline at end of file
diff --git a/web-app/src/pages/appointments_layout/AppointmentsCalendarPage.jsx b/web-app/src/pages/appointments_layout/AppointmentsCalendarPage.jsx
index df0fe3e..26ca66c 100644
--- a/web-app/src/pages/appointments_layout/AppointmentsCalendarPage.jsx
+++ b/web-app/src/pages/appointments_layout/AppointmentsCalendarPage.jsx
@@ -1,10 +1,13 @@
-import {Calendar, Grid, ConfigProvider, Badge, Modal} from "antd";
+import {Calendar, Grid, ConfigProvider, Badge, Modal, Tag, Tooltip} from "antd";
import {useState} from "react";
import dayjs from "dayjs";
import 'dayjs/locale/ru';
import locale from 'antd/es/locale/ru_RU';
import updateLocale from 'dayjs/plugin/updateLocale';
-import PropTypes from "prop-types";
+import PropTypes, {arrayOf} from "prop-types";
+import CalendarCell from "../../components/appointments/CalendarCell.jsx";
+import {AppointmentPropType} from "../../types/appointmentPropType.jsx";
+import {ScheduledAppointmentPropType} from "../../types/scheduledAppointmentPropType.jsx";
const {useBreakpoint} = Grid;
@@ -18,6 +21,7 @@ const AppointmentsCalendarPage = ({appointments, scheduledAppointments}) => {
const [selectedDate, setSelectedDate] = useState(dayjs(new Date()));
const [modalVisible, setModalVisible] = useState(false);
const [selectedAppointments, setSelectedAppointments] = useState([]);
+ const [selectedAppointment, setSelectedAppointment] = useState(null);
const dateCellRender = (value) => {
const date = value.format('YYYY-MM-DD');
@@ -29,19 +33,14 @@ const AppointmentsCalendarPage = ({appointments, scheduledAppointments}) => {
);
return (
-
- {appointmentsForDate.map(app => (
- -
-
-
- ))}
- {scheduledForDate.map(app => (
- -
-
-
- ))}
-
+ {
+ }}
+ onItemClick={() => {
+ }}
+ />
);
};
@@ -67,83 +66,15 @@ const AppointmentsCalendarPage = ({appointments, scheduledAppointments}) => {
onSelect={onSelect}
cellRender={dateCellRender}
/>
- setModalVisible(false)}
- footer={null}
- >
- {selectedAppointments.map(app => (
-
-
{app.appointment_datetime ? 'Прием' : 'Запланировано'}: {dayjs(app.appointment_datetime || app.scheduled_datetime).format('HH:mm')}
-
Пациент: {app.patient?.name || 'Не указан'}
-
Врач: {app.doctor?.name || 'Не указан'}
-
Тип: {app.type?.name || 'Не указан'}
- {app.results &&
Результаты: {app.results}
}
-
-
- ))}
-
+
);
};
AppointmentsCalendarPage.propTypes = {
- appointments: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.number.isRequired,
- results: PropTypes.string,
- days_until_the_next_appointment: PropTypes.number,
- appointment_datetime: PropTypes.string.isRequired,
- patient: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- patronymic: PropTypes.string,
- birthday: PropTypes.string,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }),
- doctor: PropTypes.shape({
- last_name: PropTypes.string,
- first_name: PropTypes.string,
- login: PropTypes.string,
- }),
- type: PropTypes.shape({
- title: PropTypes.string,
- })
- })
- ),
- scheduledAppointments: PropTypes.arrayOf(
- PropTypes.shape(
- {
- id: PropTypes.number.isRequired,
- scheduled_datetime: PropTypes.string.isRequired,
- patient: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- patronymic: PropTypes.string,
- birthday: PropTypes.string,
- address: PropTypes.string,
- email: PropTypes.string,
- phone: PropTypes.string,
- diagnosis: PropTypes.string,
- correction: PropTypes.string,
- }),
- doctor: PropTypes.shape({
- last_name: PropTypes.string,
- first_name: PropTypes.string,
- login: PropTypes.string,
- }),
- type: PropTypes.shape({
- title: PropTypes.string,
- }),
- }
- )
- )
+ appointments: PropTypes.arrayOf(AppointmentPropType).isRequired,
+ scheduledAppointments: PropTypes.arrayOf(ScheduledAppointmentPropType).isRequired,
};
-export default AppointmentsCalendarPage;
+export default AppointmentsCalendarPage;
\ No newline at end of file
diff --git a/web-app/src/pages/lenses_layout/LensesPage.jsx b/web-app/src/pages/lenses_layout/LensesPage.jsx
index bcec68d..337b1e7 100644
--- a/web-app/src/pages/lenses_layout/LensesPage.jsx
+++ b/web-app/src/pages/lenses_layout/LensesPage.jsx
@@ -92,19 +92,9 @@ const LensesPage = () => {
};
const fetchLenses = async () => {
- try {
- const data = await getAllLenses(api);
- setLenses(data);
- setLoading(false);
- } catch (error) {
- console.error("Ошибка загрузки линз:", error);
- notification.error({
- message: "Ошибка загрузки линз",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- })
- setLoading(false);
- }
+ const data = await getAllLenses(api);
+ setLenses(data);
+ setLoading(false);
};
const fetchViewModeFromCache = () => {
@@ -147,51 +137,33 @@ const LensesPage = () => {
};
const handleDeleteLens = async (lensId) => {
- try {
- await deleteLens(api, lensId);
- await fetchLenses(api);
- notification.success({
- message: "Линза удалена",
- description: "Линза успешно удалена.",
- placement: "topRight",
- })
- } catch (error) {
- console.error("Ошибка удаления линзы:", error);
- notification.error({
- message: "Ошибка удаления линзы",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ await deleteLens(api, lensId);
+ await fetchLenses(api);
+ notification.success({
+ message: "Линза удалена",
+ description: "Линза успешно удалена.",
+ placement: "topRight",
+ })
};
const handleModalSubmit = async (lensData) => {
- try {
- if (selectedLens) {
- await updateLens(api, selectedLens.id, lensData);
- notification.success({
- message: "Линза обновлена",
- description: "Линза успешно обновлена.",
- placement: "topRight",
- });
- } else {
- await addLens(api, lensData);
- notification.success({
- message: "Линза добавлена",
- description: "Линза успешно добавлена.",
- placement: "topRight",
- });
- }
- setIsModalVisible(false);
- await fetchLenses();
- } catch (error) {
- console.error("Ошибка сохранения линзы:", error);
- notification.error({
- message: "Ошибка сохранения линзы",
- description: "Проверьте подключение к сети.",
+ setIsModalVisible(false);
+ if (selectedLens) {
+ await updateLens(api, selectedLens.id, lensData);
+ notification.success({
+ message: "Линза обновлена",
+ description: "Линза успешно обновлена.",
+ placement: "topRight",
+ });
+ } else {
+ await addLens(api, lensData);
+ notification.success({
+ message: "Линза добавлена",
+ description: "Линза успешно добавлена.",
placement: "topRight",
});
}
+ await fetchLenses();
};
const toggleAdvancedSearch = () => {
diff --git a/web-app/src/pages/lenses_layout/SetLensesPage.jsx b/web-app/src/pages/lenses_layout/SetLensesPage.jsx
index f569d3a..fbf5692 100644
--- a/web-app/src/pages/lenses_layout/SetLensesPage.jsx
+++ b/web-app/src/pages/lenses_layout/SetLensesPage.jsx
@@ -53,23 +53,10 @@ const SetLensesPage = () => {
};
const fetchSets = async () => {
- try {
- const data = await getAllSets(api);
- setSets(data);
-
- cacheInfo("setsData", data);
- } catch (error) {
- console.log(error);
- notification.error({
- message: "Ошибка загрузки данных",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- })
- }
-
- if (loading) {
- setLoading(false);
- }
+ const data = await getAllSets(api);
+ setSets(data);
+ setLoading(false);
+ cacheInfo("setsData", data);
};
const filteredSets = sets.filter(set => set.title.toLowerCase().includes(searchText.toLowerCase()));
@@ -82,102 +69,57 @@ const SetLensesPage = () => {
const handleEditSet = (set) => {
setSelectedSet(set);
setIsModalVisible(true);
- }
+ };
const handleDeleteSet = async (set_id) => {
- try {
- await deleteSet(api, set_id);
- notification.success({
- message: "Набор удален",
- description: "Набор успешно удален.",
- placement: "topRight",
- });
- await fetchSets();
- } catch (error) {
- console.error("Ошибка удаления набора:", error);
- notification.error({
- message: "Ошибка удаления набора",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
- }
+ await deleteSet(api, set_id);
+ notification.success({
+ message: "Набор удален",
+ description: "Набор успешно удален.",
+ placement: "topRight",
+ });
+ await fetchSets();
+ };
const handleCancel = () => {
setIsModalVisible(false);
};
const handleAppendSet = async (set) => {
- try {
- await appendLensesFromSet(api, set.id);
- notification.success({
- message: "Линзы добавлены",
- description: "Линзы успешно добавлены.",
- placement: "topRight",
- });
- } catch (error) {
- console.error("Ошибка добавления линз:", error);
- notification.error({
- message: "Ошибка добавления линз",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ await appendLensesFromSet(api, set.id);
+ notification.success({
+ message: "Линзы добавлены",
+ description: "Линзы успешно добавлены.",
+ placement: "topRight",
+ });
};
const handleModalSetSubmit = async (set, content = []) => {
- try {
- let refreshed_set;
+ setIsModalVisible(false);
- if (selectedSet) {
- refreshed_set = await editCurrentSet(set);
- } else {
- refreshed_set = await addNewSet(set);
- }
+ let refreshed_set;
- if (refreshed_set && selectedSet) {
- await updateContent(content, refreshed_set.id);
- } else if (refreshed_set && !selectedSet) {
- await setContent(content, refreshed_set.id);
- }
-
- setIsModalVisible(false);
- await fetchSets();
- } catch (error) {
- console.error("Ошибка сохранения набора:", error);
- notification.error({
- message: "Ошибка сохранения набора",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
+ if (selectedSet) {
+ refreshed_set = await editCurrentSet(set);
+ } else {
+ refreshed_set = await addNewSet(set);
}
+
+ if (refreshed_set && selectedSet) {
+ await updateContent(content, refreshed_set.id);
+ } else if (refreshed_set && !selectedSet) {
+ await setContent(content, refreshed_set.id);
+ }
+
+ await fetchSets();
};
const setContent = async (content, set_id) => {
- try {
- console.log(content);
- await addSetContent(api, content, set_id);
- } catch (error) {
- console.error("Ошибка сохранения набора:", error);
- notification.error({
- message: "Ошибка сохранения набора",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ await addSetContent(api, content, set_id);
};
const updateContent = async (content, set_id) => {
- try {
- await updateSetContent(api, content, set_id);
- } catch (error) {
- console.error("Ошибка сохранения набора:", error);
- notification.error({
- message: "Ошибка сохранения набора",
- description: "Проверьте подключение к сети.",
- placement: "topRight",
- });
- }
+ await updateSetContent(api, content, set_id);
};
const editCurrentSet = async (set) => {
diff --git a/web-app/src/types/appointmentPropType.jsx b/web-app/src/types/appointmentPropType.jsx
new file mode 100644
index 0000000..39002cf
--- /dev/null
+++ b/web-app/src/types/appointmentPropType.jsx
@@ -0,0 +1,17 @@
+import PropTypes from "prop-types";
+import {PatientPropType} from "./patientPropType.jsx";
+import {UserPropType} from "./userPropType.jsx";
+import {AppointmentTypePropType} from "./appointmentTypePropType.jsx";
+
+export const AppointmentPropType = PropTypes.shape({
+ id: PropTypes.number,
+ results: PropTypes.string,
+ days_until_the_next_appointment: PropTypes.number,
+ appointment_datetime: PropTypes.string.isRequired,
+ patient_id: PropTypes.number.isRequired,
+ doctor_id: PropTypes.number.isRequired,
+ type_id: PropTypes.number.isRequired,
+ patient: PatientPropType,
+ doctor: UserPropType,
+ type: AppointmentTypePropType,
+});
\ No newline at end of file
diff --git a/web-app/src/types/appointmentTypePropType.jsx b/web-app/src/types/appointmentTypePropType.jsx
new file mode 100644
index 0000000..d81c5c9
--- /dev/null
+++ b/web-app/src/types/appointmentTypePropType.jsx
@@ -0,0 +1,6 @@
+import PropTypes from "prop-types";
+
+export const AppointmentTypePropType = PropTypes.shape({
+ id: PropTypes.number,
+ title: PropTypes.string.isRequired,
+})
\ No newline at end of file
diff --git a/web-app/src/types/lensIssuePropType.jsx b/web-app/src/types/lensIssuePropType.jsx
new file mode 100644
index 0000000..0ee25d2
--- /dev/null
+++ b/web-app/src/types/lensIssuePropType.jsx
@@ -0,0 +1,15 @@
+import PropTypes from "prop-types";
+import {PatientPropType} from "./patientPropType.jsx";
+import {UserPropType} from "./userPropType.jsx";
+import {LensPropType} from "./lensPropType.jsx";
+
+export const LensIssuePropType = PropTypes.shape({
+ id: PropTypes.number,
+ issue_date: PropTypes.string.isRequired,
+ patient_id: PropTypes.number.isRequired,
+ doctor_id: PropTypes.number,
+ lens_id: PropTypes.number.isRequired,
+ patient: PatientPropType,
+ doctor: UserPropType,
+ lens: LensPropType,
+});
\ No newline at end of file
diff --git a/web-app/src/types/lensPropType.jsx b/web-app/src/types/lensPropType.jsx
new file mode 100644
index 0000000..5f8ae1c
--- /dev/null
+++ b/web-app/src/types/lensPropType.jsx
@@ -0,0 +1,15 @@
+import PropTypes from "prop-types";
+
+export const LensPropType = PropTypes.shape({
+ id: PropTypes.number,
+ tor: PropTypes.number.isRequired,
+ trial: PropTypes.number.isRequired,
+ esa: PropTypes.number.isRequired,
+ fvc: PropTypes.number.isRequired,
+ preset_refraction: PropTypes.number.isRequired,
+ diameter: PropTypes.number.isRequired,
+ periphery_toricity: PropTypes.number.isRequired,
+ side: PropTypes.string.isRequired,
+ issued: PropTypes.bool.isRequired,
+ type_id: PropTypes.number.isRequired,
+});
\ No newline at end of file
diff --git a/web-app/src/types/lensTypePropType.jsx b/web-app/src/types/lensTypePropType.jsx
new file mode 100644
index 0000000..0ef7c94
--- /dev/null
+++ b/web-app/src/types/lensTypePropType.jsx
@@ -0,0 +1,6 @@
+import PropTypes from "prop-types";
+
+export const LensTypePropType = PropTypes.shape({
+ id: PropTypes.number,
+ title: PropTypes.string.isRequired,
+});
\ No newline at end of file
diff --git a/web-app/src/types/patientPropType.jsx b/web-app/src/types/patientPropType.jsx
new file mode 100644
index 0000000..a998460
--- /dev/null
+++ b/web-app/src/types/patientPropType.jsx
@@ -0,0 +1,14 @@
+import PropTypes from "prop-types";
+
+export const PatientPropType = PropTypes.shape({
+ id: PropTypes.number,
+ first_name: PropTypes.string.isRequired,
+ last_name: PropTypes.string.isRequired,
+ patronymic: PropTypes.string,
+ birthday: PropTypes.string.isRequired,
+ address: PropTypes.string,
+ email: PropTypes.string,
+ phone: PropTypes.string,
+ diagnosis: PropTypes.string,
+ correction: PropTypes.string,
+});
\ No newline at end of file
diff --git a/web-app/src/types/scheduledAppointmentPropType.jsx b/web-app/src/types/scheduledAppointmentPropType.jsx
new file mode 100644
index 0000000..8546500
--- /dev/null
+++ b/web-app/src/types/scheduledAppointmentPropType.jsx
@@ -0,0 +1,15 @@
+import PropTypes from "prop-types";
+import {PatientPropType} from "./patientPropType.jsx";
+import {UserPropType} from "./userPropType.jsx";
+import {AppointmentTypePropType} from "./appointmentTypePropType.jsx";
+
+export const ScheduledAppointmentPropType = PropTypes.shape({
+ id: PropTypes.number,
+ scheduled_datetime: PropTypes.string.isRequired,
+ patient_id: PropTypes.number.isRequired,
+ doctor_id: PropTypes.number.isRequired,
+ type_id: PropTypes.number.isRequired,
+ patient: PatientPropType,
+ doctor: UserPropType,
+ type: AppointmentTypePropType,
+})
\ No newline at end of file
diff --git a/web-app/src/types/setContentPropType.jsx b/web-app/src/types/setContentPropType.jsx
new file mode 100644
index 0000000..cf63433
--- /dev/null
+++ b/web-app/src/types/setContentPropType.jsx
@@ -0,0 +1,15 @@
+import PropTypes from "prop-types";
+
+export const SetContentPropType = PropTypes.shape({
+ id: PropTypes.number,
+ tor: PropTypes.number.isRequired,
+ trial: PropTypes.number.isRequired,
+ esa: PropTypes.number.isRequired,
+ fvc: PropTypes.number.isRequired,
+ preset_refraction: PropTypes.number.isRequired,
+ diameter: PropTypes.number.isRequired,
+ side: PropTypes.string.isRequired,
+ count: PropTypes.number.isRequired,
+ type_id: PropTypes.number.isRequired,
+ set_id: PropTypes.number,
+});
\ No newline at end of file
diff --git a/web-app/src/types/setPropType.jsx b/web-app/src/types/setPropType.jsx
new file mode 100644
index 0000000..d98249b
--- /dev/null
+++ b/web-app/src/types/setPropType.jsx
@@ -0,0 +1,6 @@
+import PropTypes from "prop-types";
+
+export const SetPropType = PropTypes.shape({
+ id: PropTypes.number,
+ title: PropTypes.string.isRequired,
+});
\ No newline at end of file
diff --git a/web-app/src/types/userPropType.jsx b/web-app/src/types/userPropType.jsx
new file mode 100644
index 0000000..1bcf853
--- /dev/null
+++ b/web-app/src/types/userPropType.jsx
@@ -0,0 +1,10 @@
+import PropTypes from "prop-types";
+
+export const UserPropType = PropTypes.shape({
+ id: PropTypes.number,
+ first_name: PropTypes.string.isRequired,
+ last_name: PropTypes.string.isRequired,
+ patronymic: PropTypes.string,
+ login: PropTypes.string.isRequired,
+ role_id: PropTypes.number.isRequired,
+});
\ No newline at end of file
diff --git a/web-app/src/types/viewModPropType.jsx b/web-app/src/types/viewModPropType.jsx
new file mode 100644
index 0000000..23843fc
--- /dev/null
+++ b/web-app/src/types/viewModPropType.jsx
@@ -0,0 +1,7 @@
+import PropTypes from "prop-types";
+
+export const ViewModPropType = PropTypes.shape({
+ value: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ icon: PropTypes.element,
+});
\ No newline at end of file