diff --git a/web-app/package-lock.json b/web-app/package-lock.json
index 51033b0..ea09e61 100644
--- a/web-app/package-lock.json
+++ b/web-app/package-lock.json
@@ -13,6 +13,7 @@
"@react-buddy/palette-antd": "^5.3.0",
"antd": "^5.23.1",
"axios": "^1.7.9",
+ "moment": "^2.30.1",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -4006,6 +4007,15 @@
"node": "*"
}
},
+ "node_modules/moment": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+ "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
diff --git a/web-app/package.json b/web-app/package.json
index 5e8226e..3182af2 100644
--- a/web-app/package.json
+++ b/web-app/package.json
@@ -15,6 +15,7 @@
"@react-buddy/palette-antd": "^5.3.0",
"antd": "^5.23.1",
"axios": "^1.7.9",
+ "moment": "^2.30.1",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/web-app/src/AppRouter.jsx b/web-app/src/AppRouter.jsx
index 7c17da1..b4f1df0 100644
--- a/web-app/src/AppRouter.jsx
+++ b/web-app/src/AppRouter.jsx
@@ -11,11 +11,11 @@ const AppRouter = () => (
}>
}>
- 1234
}/>
}/>
- }/>
+ 1234}/>
+ }/>
)
diff --git a/web-app/src/AuthContext.jsx b/web-app/src/AuthContext.jsx
index 59af6e8..2647cbb 100644
--- a/web-app/src/AuthContext.jsx
+++ b/web-app/src/AuthContext.jsx
@@ -1,17 +1,20 @@
import {createContext, useState, useContext, useEffect} from "react";
import PropTypes from "prop-types";
import loginUser from "./api/LoginRequest.jsx";
+import {Spin} from "antd";
const AuthContext = createContext(undefined);
export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const token = localStorage.getItem("access_token");
if (token) {
setUser({token});
}
+ setIsLoading(false);
}, []);
const login = async (loginData) => {
@@ -30,6 +33,10 @@ export const AuthProvider = ({children}) => {
setUser(null);
};
+ if (isLoading) {
+ return ;
+ }
+
return (
{children}
diff --git a/web-app/src/components/PatientModal.jsx b/web-app/src/components/PatientModal.jsx
new file mode 100644
index 0000000..0e6fabf
--- /dev/null
+++ b/web-app/src/components/PatientModal.jsx
@@ -0,0 +1,128 @@
+import {useEffect} from "react";
+import {Modal, Form, Input, DatePicker} from "antd";
+import moment from "moment";
+import PropTypes from "prop-types";
+
+const {TextArea} = Input;
+
+const PatientModal = ({visible, onCancel, onSubmit, patient}) => {
+ const [form] = Form.useForm();
+
+ useEffect(() => {
+ if (patient) {
+ form.setFieldsValue({
+ ...patient,
+ birthday: patient.birthday ? moment(patient.birthday) : null,
+ });
+ } else {
+ form.resetFields();
+ }
+ }, [patient, form]);
+
+ const handleOk = async () => {
+ try {
+ const values = await form.validateFields();
+ if (values.birthday) {
+ values.birthday = values.birthday.format("YYYY-MM-DD");
+ }
+ onSubmit(values);
+ } catch (errorInfo) {
+ console.log("Validation Failed:", errorInfo);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+PatientModal.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,
+ }),
+};
+
+export default PatientModal;
diff --git a/web-app/src/pages/PatientsPage.jsx b/web-app/src/pages/PatientsPage.jsx
index 9496f51..a1be1f1 100644
--- a/web-app/src/pages/PatientsPage.jsx
+++ b/web-app/src/pages/PatientsPage.jsx
@@ -1,9 +1,10 @@
import { useEffect, useState } from "react";
-import { Input, Select, List, FloatButton, Row, Col } from "antd";
+import { Input, Select, List, FloatButton, Row, Col, message } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import { useAuth } from "../AuthContext.jsx";
import getAllPatients from "../api/GetAllPatients.jsx";
import PatientListCard from "../components/PatientListCard.jsx";
+import PatientModal from "../components/PatientModal.jsx"; // Подключаем модальное окно
const { Search } = Input;
const { Option } = Select;
@@ -18,6 +19,9 @@ const PatientsPage = () => {
const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(10);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [selectedPatient, setSelectedPatient] = useState(null);
+
useEffect(() => {
const fetchPatients = async () => {
if (!user || !user.token) return;
@@ -45,6 +49,36 @@ const PatientsPage = () => {
: fullNameB.localeCompare(fullNameA);
});
+ const handleAddPatient = () => {
+ setSelectedPatient(null);
+ setIsModalVisible(true);
+ };
+
+ const handleEditPatient = (patient) => {
+ setSelectedPatient(patient);
+ setIsModalVisible(true);
+ };
+
+ const handleCancel = () => {
+ setIsModalVisible(false);
+ };
+
+ const handleSubmit = (newPatient) => {
+ if (selectedPatient) {
+ setPatients((prevPatients) =>
+ prevPatients.map((p) =>
+ p.id === selectedPatient.id ? { ...p, ...newPatient } : p
+ )
+ );
+ message.success("Пациент успешно обновлен!");
+ } else {
+ setPatients((prevPatients) => [...prevPatients, { id: Date.now(), ...newPatient }]);
+ message.success("Пациент успешно добавлен!");
+ }
+
+ setIsModalVisible(false);
+ };
+
return (
@@ -71,8 +105,12 @@ const PatientsPage = () => {
grid={{ gutter: 16, column: 1 }}
dataSource={filteredPatients}
renderItem={(patient) => (
-
-
+ {
+ handleEditPatient(patient);
+ }}
+ >
+
)}
pagination={{
@@ -90,7 +128,14 @@ const PatientsPage = () => {
}
style={{ position: "fixed", bottom: 20, right: 20 }}
- onClick={() => console.log("Добавить пациента")}
+ onClick={handleAddPatient}
+ />
+
+
);