diff --git a/web-app/src/api/lenses/UpdateLens.jsx b/web-app/src/api/lenses/UpdateLens.jsx index ddf7cc7..2980ee6 100644 --- a/web-app/src/api/lenses/UpdateLens.jsx +++ b/web-app/src/api/lenses/UpdateLens.jsx @@ -3,7 +3,6 @@ import CONFIG from "../../core/Config.jsx"; const updateLens = async (token, lensId, lensData) => { - console.log(lensId, lensData); try { const response = await axios.put(`${CONFIG.BASE_URL}/lenses/${lensId}/`, lensData, { headers: { diff --git a/web-app/src/components/SelectViewMode.jsx b/web-app/src/components/SelectViewMode.jsx new file mode 100644 index 0000000..7e83f5a --- /dev/null +++ b/web-app/src/components/SelectViewMode.jsx @@ -0,0 +1,40 @@ +import {BuildOutlined, TableOutlined} from "@ant-design/icons"; +import {Select, Tooltip} from "antd"; +import PropTypes from "prop-types"; + +const {Option} = Select; + +const SelectViewMode = ({viewMode, setViewMode, localStorageKey, toolTipText}) => { + return ( + + + + + ) +}; + +SelectViewMode.propTypes = { + viewMode: PropTypes.string.isRequired, + setViewMode: PropTypes.func.isRequired, + localStorageKey: PropTypes.string.isRequired, +}; + +export default SelectViewMode; \ 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 new file mode 100644 index 0000000..4205539 --- /dev/null +++ b/web-app/src/components/lens_issues/LensIssueFormModal.jsx @@ -0,0 +1,193 @@ +import {useEffect, useState} from "react"; +import {Modal, Form, Input, Select, Collapse, Button, notification, List} from "antd"; +import PropTypes from "prop-types"; +import getAllPatients from "../../api/patients/GetAllPatients.jsx"; +import getAllLenses from "../../api/lenses/GetAllLenses.jsx"; +import {useAuth} from "../../AuthContext.jsx"; + +const {Option} = Select; +const {Panel} = Collapse; + +const LensIssueFormModal = ({visible, onCancel, onSubmit}) => { + const {user} = useAuth(); + + const [form] = Form.useForm(); + const [patients, setPatients] = useState([]); + const [lenses, setLenses] = useState([]); + const [selectedPatient, setSelectedPatient] = useState(null); + const [selectedLens, setSelectedLens] = useState(null); + + const [searchPatientString, setSearchPatientString] = useState(""); + const [searchLensString, setSearchLensString] = useState(""); + + useEffect(() => { + if (visible) { + fetchPatients(); + fetchLenses(); + } + }, [visible]); + + const fetchPatients = async () => { + try { + const data = await getAllPatients(user.token); + setPatients(data); + } catch (error) { + console.log(error); + notification.error({ + message: "Ошибка загрузки пациентов", + description: "Проверьте подключение к сети.", + }); + } + }; + + const fetchLenses = async () => { + try { + const data = await getAllLenses(user.token); + setLenses(data); + } catch (error) { + console.log(error); + notification.error({ + message: "Ошибка загрузки линз", + description: "Проверьте подключение к сети.", + }); + } + }; + + const handleOk = async () => { + try { + const values = await form.validateFields(); + onSubmit({...values, patient: selectedPatient, lens: selectedLens}); + form.resetFields(); + setSelectedPatient(null); + setSelectedLens(null); + } catch (errorInfo) { + console.log("Validation Failed:", errorInfo); + } + }; + + const flteredPatients = patients + .filter((patient) => { + const searchLower = searchPatientString.toLowerCase(); + + return Object.values(patient) + .filter(value => typeof value === "string") + .some(value => value.toLowerCase().includes(searchLower)); + }); + + const filteredLenses = lenses + .filter((lens) => { + const searchLower = searchLensString.toLowerCase(); + return lens.side.toLowerCase().includes(searchLower); + }); + + const items = flteredPatients.map((patient) => ( + { + key: patient.id, + label: `${patient.last_name} ${patient.first_name} (${new Date(patient.birthday).toLocaleDateString("ru-RU")})`, + children: +
+

Пациент: {patient.last_name} {patient.first_name}

+

Дата рождения: {new Date(patient.birthday).toLocaleDateString("ru-RU")}

+

Диагноз: {patient.diagnosis}

+

Email: {patient.email}

+

Телефон: {patient.phone}

+
, + } + )); + + return ( + { + form.resetFields(); + setSelectedPatient(null); + setSelectedLens(null); + onCancel(); + }} + onOk={handleOk} + okText="Сохранить" + cancelText="Отмена" + maskClosable={false} + centered + > +
+ + + setSearchPatientString(e.target.value)} + style={{marginBottom: 16}} + allowClear + /> + +
+ +
+
+ + + + + + + + +
+
+ ); +}; + +LensIssueFormModal.propTypes = { + visible: PropTypes.bool.isRequired, + onCancel: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + 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, + }), + }), +}; + +export default LensIssueFormModal; diff --git a/web-app/src/pages/IssuesPage.jsx b/web-app/src/pages/IssuesPage.jsx index 2a9b17a..8675c80 100644 --- a/web-app/src/pages/IssuesPage.jsx +++ b/web-app/src/pages/IssuesPage.jsx @@ -1,10 +1,13 @@ -import {notification, Spin, Table, Input, Row, Col, DatePicker, Tooltip, Button, FloatButton} from "antd"; +import {notification, Spin, Table, Input, Row, Col, DatePicker, Tooltip, Button, FloatButton, Typography} from "antd"; import getAllLensIssues from "../api/lens_issues/GetAllLensIssues.jsx"; import {useEffect, useState} from "react"; import {useAuth} from "../AuthContext.jsx"; -import {LoadingOutlined, PlusOutlined} from "@ant-design/icons"; +import {DatabaseOutlined, LoadingOutlined, PlusOutlined} from "@ant-design/icons"; import LensIssueViewModal from "../components/lens_issues/LensIssueViewModal.jsx"; import dayjs from "dayjs"; +import LensIssueFormModal from "../components/lens_issues/LensIssueFormModal.jsx"; + +const {Title} = Typography; const IssuesPage = () => { const {user} = useAuth(); @@ -13,6 +16,7 @@ const IssuesPage = () => { const [lensIssues, setLensIssues] = useState([]); const [searchTerm, setSearchTerm] = useState(""); const [selectedIssue, setSelectedIssue] = useState(null); + const [isModalVisible, setIsModalVisible] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); @@ -22,6 +26,7 @@ const IssuesPage = () => { useEffect(() => { fetchLensIssuesWithCache(); + document.title = "Выдача линз"; }, []); useEffect(() => { @@ -43,13 +48,21 @@ const IssuesPage = () => { const handleAddIssue = () => { setSelectedIssue(null); - + setIsModalVisible(true); }; const handleCloseViewModal = () => { setSelectedIssue(null); }; + const handleCloseFormModal = () => { + setIsModalVisible(false); + }; + + const handleSubmitFormModal = () => { + + }; + const fetchLensIssues = async () => { try { const data = await getAllLensIssues(user.token); @@ -129,6 +142,7 @@ const IssuesPage = () => { return (
+ <DatabaseOutlined/> Выдача линз { tooltip={"Добавить выдачу линзы"} /> + + { const {user} = useAuth(); @@ -53,6 +62,7 @@ const LensesPage = () => { useEffect(() => { fetchLensWithCache(); fetchViewModeFromCache(); + document.title = "Линзы"; }, []); useEffect(() => { @@ -98,11 +108,6 @@ const LensesPage = () => { } }; - const handleChangeViewMode = (mode) => { - setViewMode(mode); - localStorage.setItem("viewModeLenses", mode); - }; - const filteredLenses = lenses.filter((lens) => { const textMatch = Object.values(lens).some((value) => value?.toString().toLowerCase().includes(searchText.toLowerCase()) @@ -324,6 +329,7 @@ const LensesPage = () => { return (
+ <FolderViewOutlined/> Линзы { - - - + diff --git a/web-app/src/pages/LoginPage.jsx b/web-app/src/pages/LoginPage.jsx index 652372b..c68b8b7 100644 --- a/web-app/src/pages/LoginPage.jsx +++ b/web-app/src/pages/LoginPage.jsx @@ -16,6 +16,7 @@ const LoginPage = () => { if (user) { navigate("/"); } + document.title = "Авторизация"; }, [user, navigate]); const onFinish = async (values) => { diff --git a/web-app/src/pages/PatientsPage.jsx b/web-app/src/pages/PatientsPage.jsx index 239cb8a..e6ba86a 100644 --- a/web-app/src/pages/PatientsPage.jsx +++ b/web-app/src/pages/PatientsPage.jsx @@ -1,6 +1,26 @@ import {useEffect, useState} from "react"; -import {Input, Select, List, FloatButton, Row, Col, Spin, notification, Tooltip, Table, Button, Popconfirm} from "antd"; -import {LoadingOutlined, PlusOutlined} from "@ant-design/icons"; +import { + Input, + Select, + List, + FloatButton, + Row, + Col, + Spin, + notification, + Tooltip, + Table, + Button, + Popconfirm, + Typography +} from "antd"; +import { + LoadingOutlined, + PlusOutlined, + SortAscendingOutlined, + SortDescendingOutlined, + TeamOutlined +} from "@ant-design/icons"; import {useAuth} from "../AuthContext.jsx"; import getAllPatients from "../api/patients/GetAllPatients.jsx"; import PatientListCard from "../components/patients/PatientListCard.jsx"; @@ -8,8 +28,10 @@ import PatientFormModal from "../components/patients/PatientFormModal.jsx"; import updatePatient from "../api/patients/UpdatePatient.jsx"; import addPatient from "../api/patients/AddPatient.jsx"; import deletePatient from "../api/patients/DeletePatient.jsx"; +import SelectViewMode from "../components/SelectViewMode.jsx"; const {Option} = Select; +const {Title} = Typography const PatientsPage = () => { const {user} = useAuth(); @@ -28,6 +50,7 @@ const PatientsPage = () => { useEffect(() => { fetchPatientsWithCache(); fetchViewModeFromCache(); + document.title = "Пациенты"; }, []); useEffect(() => { @@ -80,11 +103,6 @@ const PatientsPage = () => { } }; - const handleChangeViewMode = (mode) => { - setViewMode(mode); - localStorage.setItem("viewModePatients", mode); - }; - const filteredPatients = patients .filter((patient) => { const searchLower = searchText.toLowerCase(); @@ -293,8 +311,9 @@ const PatientsPage = () => { return (
+ <TeamOutlined/> Пациенты - + setSearchText(e.target.value)} @@ -302,37 +321,42 @@ const PatientsPage = () => { allowClear /> - - - - - - - - - + + + + )} + + + - {loading ? ( + {loading ? (
{ const {user} = useAuth(); @@ -201,6 +203,7 @@ const SetLensesPage = () => { return (
+ <SwitcherOutlined/> Наборы линз