сделал заготовку модального окна, а также починил переадресацию при перезагрузке стринцы

This commit is contained in:
Андрей Дувакин 2025-02-10 18:29:49 +05:00
parent cb3860297a
commit 6c2a6e4c00
6 changed files with 197 additions and 6 deletions

View File

@ -13,6 +13,7 @@
"@react-buddy/palette-antd": "^5.3.0", "@react-buddy/palette-antd": "^5.3.0",
"antd": "^5.23.1", "antd": "^5.23.1",
"axios": "^1.7.9", "axios": "^1.7.9",
"moment": "^2.30.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -4006,6 +4007,15 @@
"node": "*" "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": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

View File

@ -15,6 +15,7 @@
"@react-buddy/palette-antd": "^5.3.0", "@react-buddy/palette-antd": "^5.3.0",
"antd": "^5.23.1", "antd": "^5.23.1",
"axios": "^1.7.9", "axios": "^1.7.9",
"moment": "^2.30.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

View File

@ -11,11 +11,11 @@ const AppRouter = () => (
<Route element={<PrivateRoute/>}> <Route element={<PrivateRoute/>}>
<Route element={<MainLayout/>}> <Route element={<MainLayout/>}>
<Route path={"/"} element={<p>1234</p>}/>
<Route path={"/patients"} element={<PatientsPage/>}/> <Route path={"/patients"} element={<PatientsPage/>}/>
<Route path={"*"} element={<Navigate to={"/"}/>}/> <Route path={"/"} element={<p>1234</p>}/>
</Route> </Route>
</Route> </Route>
<Route path={"*"} element={<Navigate to={"/"}/>}/>
</Routes> </Routes>
) )

View File

@ -1,17 +1,20 @@
import {createContext, useState, useContext, useEffect} from "react"; import {createContext, useState, useContext, useEffect} from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import loginUser from "./api/LoginRequest.jsx"; import loginUser from "./api/LoginRequest.jsx";
import {Spin} from "antd";
const AuthContext = createContext(undefined); const AuthContext = createContext(undefined);
export const AuthProvider = ({children}) => { export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => { useEffect(() => {
const token = localStorage.getItem("access_token"); const token = localStorage.getItem("access_token");
if (token) { if (token) {
setUser({token}); setUser({token});
} }
setIsLoading(false);
}, []); }, []);
const login = async (loginData) => { const login = async (loginData) => {
@ -30,6 +33,10 @@ export const AuthProvider = ({children}) => {
setUser(null); setUser(null);
}; };
if (isLoading) {
return <Spin/>;
}
return ( return (
<AuthContext.Provider value={{user, login, logout}}> <AuthContext.Provider value={{user, login, logout}}>
{children} {children}

View File

@ -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 (
<Modal
title={patient ? "Редактировать пациента" : "Добавить пациента"}
open={visible}
onCancel={onCancel}
onOk={handleOk}
okText="Сохранить"
cancelText="Отмена"
centered
maskClosable={false}
bodyStyle={{padding: 24}}
style={{top: 20}}
>
<Form form={form} layout="vertical">
<Form.Item
name="first_name"
label="Имя"
rules={[{required: true, message: "Введите имя"}]}
>
<Input placeholder="Введите имя"/>
</Form.Item>
<Form.Item
name="last_name"
label="Фамилия"
rules={[{required: true, message: "Введите фамилию"}]}
>
<Input placeholder="Введите фамилию"/>
</Form.Item>
<Form.Item
name="patronymic"
label="Отчество"
>
<Input placeholder="Введите отчество (необязательно)"/>
</Form.Item>
<Form.Item
name="birthday"
label="Дата рождения"
rules={[{required: true, message: "Выберите дату рождения"}]}
>
<DatePicker style={{width: "100%"}} format="YYYY-MM-DD"/>
</Form.Item>
<Form.Item
name="address"
label="Адрес"
>
<Input placeholder="Введите адрес"/>
</Form.Item>
<Form.Item
name="email"
label="Email"
rules={[{type: "email", message: "Введите корректный email"}]}
>
<Input placeholder="Введите email"/>
</Form.Item>
<Form.Item
name="phone"
label="Телефон"
>
<Input placeholder="Введите телефон"/>
</Form.Item>
<Form.Item
name="diagnosis"
label="Диагноз"
>
<TextArea rows={3} placeholder="Введите диагноз"/>
</Form.Item>
<Form.Item
name="correction"
label="Коррекция"
>
<TextArea rows={3} placeholder="Введите информацию о коррекции"/>
</Form.Item>
</Form>
</Modal>
);
};
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;

View File

@ -1,9 +1,10 @@
import { useEffect, useState } from "react"; 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 { PlusOutlined } from "@ant-design/icons";
import { useAuth } from "../AuthContext.jsx"; import { useAuth } from "../AuthContext.jsx";
import getAllPatients from "../api/GetAllPatients.jsx"; import getAllPatients from "../api/GetAllPatients.jsx";
import PatientListCard from "../components/PatientListCard.jsx"; import PatientListCard from "../components/PatientListCard.jsx";
import PatientModal from "../components/PatientModal.jsx"; // Подключаем модальное окно
const { Search } = Input; const { Search } = Input;
const { Option } = Select; const { Option } = Select;
@ -18,6 +19,9 @@ const PatientsPage = () => {
const [current, setCurrent] = useState(1); const [current, setCurrent] = useState(1);
const [pageSize, setPageSize] = useState(10); const [pageSize, setPageSize] = useState(10);
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectedPatient, setSelectedPatient] = useState(null);
useEffect(() => { useEffect(() => {
const fetchPatients = async () => { const fetchPatients = async () => {
if (!user || !user.token) return; if (!user || !user.token) return;
@ -45,6 +49,36 @@ const PatientsPage = () => {
: fullNameB.localeCompare(fullNameA); : 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 ( return (
<div style={{ padding: 20 }}> <div style={{ padding: 20 }}>
<Row gutter={[16, 16]} style={{ marginBottom: 20 }}> <Row gutter={[16, 16]} style={{ marginBottom: 20 }}>
@ -71,8 +105,12 @@ const PatientsPage = () => {
grid={{ gutter: 16, column: 1 }} grid={{ gutter: 16, column: 1 }}
dataSource={filteredPatients} dataSource={filteredPatients}
renderItem={(patient) => ( renderItem={(patient) => (
<List.Item> <List.Item
<PatientListCard patient={patient} /> onClick={() => {
handleEditPatient(patient);
}}
>
<PatientListCard patient={patient}/>
</List.Item> </List.Item>
)} )}
pagination={{ pagination={{
@ -90,7 +128,14 @@ const PatientsPage = () => {
<FloatButton <FloatButton
icon={<PlusOutlined />} icon={<PlusOutlined />}
style={{ position: "fixed", bottom: 20, right: 20 }} style={{ position: "fixed", bottom: 20, right: 20 }}
onClick={() => console.log("Добавить пациента")} onClick={handleAddPatient}
/>
<PatientModal
visible={isModalVisible}
onCancel={handleCancel}
onSubmit={handleSubmit}
patient={selectedPatient}
/> />
</div> </div>
); );