setShowModalInfo(false)}
+ lens={lens}
+ />
+ )}
+ >
+ );
+};
+
+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,
+ handleEditLens: PropTypes.func.isRequired,
+ handleDeleteLens: PropTypes.func.isRequired,
+};
+
+export default LensListCard;
diff --git a/web-app/src/components/lenses/LensViewModal.jsx b/web-app/src/components/lenses/LensViewModal.jsx
new file mode 100644
index 0000000..6a3aad9
--- /dev/null
+++ b/web-app/src/components/lenses/LensViewModal.jsx
@@ -0,0 +1,80 @@
+import {Button, Col, Modal, Row, Typography, Divider} from "antd";
+import PropTypes from "prop-types";
+
+const {Text, Title} = Typography;
+
+const LensViewModal = ({visible, onCancel, lens}) => {
+ if (!lens) return null;
+
+ return (
+
+ Закрыть
+
+ }
+ >
+
+
+
+
🔬 Тор
+ {lens.tor} D
+
+
+
+
📏 Диаметр
+ {lens.diameter} мм
+
+
+
+
🔄 Пресетная рефракция
+ {lens.preset_refraction} D
+
+
+
+
+
+
⚙️ Перефирийная торичность
+ {lens.periphery_toricity} D
+
+
+
+
⛓ Сторона
+ {lens.side}
+
+
+
+
✅ Статус выдачи
+ {lens.issued ? 'Выдана' : 'Не выдана'}
+
+
+
+
+
+
+
+
⚖️ Пробная линза (Trial)
+ {lens.trial.toFixed(2)} D
+
+
+ );
+};
+
+LensViewModal.propTypes = {
+ visible: PropTypes.bool.isRequired,
+ onCancel: PropTypes.func.isRequired,
+ lens: PropTypes.shape({
+ tor: PropTypes.number.isRequired,
+ diameter: 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 LensViewModal;
diff --git a/web-app/src/pages/LensPage.jsx b/web-app/src/pages/LensPage.jsx
index 90d539f..97c9798 100644
--- a/web-app/src/pages/LensPage.jsx
+++ b/web-app/src/pages/LensPage.jsx
@@ -1,12 +1,156 @@
+import {useState, useEffect} from "react";
+import {Input, Select, List, FloatButton, Row, Col, Spin} from "antd";
+import {LoadingOutlined, PlusOutlined} from "@ant-design/icons";
+import LensCard from "../components/lenses/LensListCard.jsx";
+import getAllLenses from "../api/lenses/GetAllLenses.jsx";
+import addLens from "../api/lenses/AddLens.jsx";
+import updateLens from "../api/lenses/UpdateLens.jsx";
+import deleteLens from "../api/lenses/DeleteLens.jsx";
+import {useAuth} from "../AuthContext.jsx";
+const {Option} = Select;
+const LensesPage = () => {
+ const {user} = useAuth();
+
+ const [current, setCurrent] = useState(1);
+ const [pageSize, setPageSize] = useState(10);
+
+ const [searchText, setSearchText] = useState("");
+ const [sortOrder, setSortOrder] = useState("asc");
+ const [lenses, setLenses] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [selectedLens, setSelectedLens] = useState(null);
+
+ useEffect(() => {
+ fetchLenses();
+ }, []);
+
+ const fetchLenses = async () => {
+ if (!user || !user.token) return;
+
+ try {
+ const data = await getAllLenses(user.token);
+ setLenses(data);
+ setLoading(false);
+ } catch (error) {
+ console.error("Ошибка загрузки линз:", error);
+ setLoading(false);
+ }
+ };
+
+ const filteredLenses = lenses.filter((lens) =>
+ Object.values(lens).some((value) =>
+ value?.toString().toLowerCase().includes(searchText.toLowerCase())
+ )
+ ).sort((a, b) => {
+ return sortOrder === "asc"
+ ? a.preset_refraction - b.preset_refraction
+ : b.preset_refraction - a.preset_refraction;
+ });
+
+ const handleAddLens = () => {
+ setSelectedLens(null);
+ setIsModalVisible(true);
+ };
+
+ const handleEditLens = (lens) => {
+ setSelectedLens(lens);
+ setIsModalVisible(true);
+ };
+
+ const handleDeleteLens = async (lensId) => {
+ if (!user || !user.token) return;
+
+ try {
+ await deleteLens(lensId, user.token);
+ fetchLenses(user.token);
+ } catch (error) {
+ console.error("Ошибка удаления линзы:", error);
+ }
+ };
+
+ const handleModalSubmit = async (lensData) => {
+ try {
+ if (selectedLens) {
+ await updateLens(selectedLens.id, lensData);
+ } else {
+ await addLens(lensData);
+ }
+ setIsModalVisible(false);
+ fetchLenses();
+ } catch (error) {
+ console.error("Ошибка сохранения линзы:", error);
+ }
+ };
-const LensPage = () => {
return (
- <>
-
- >
- )
-}
+
+
+
+ setSearchText(e.target.value)}
+ style={{width: "100%"}}
+ allowClear
+ />
+
+
+
+
+
-export default LensPage;
+ {loading ? (
+ }/>
+ ) : (
+ (
+
+ handleDeleteLens(lens.id)}
+ handleEditLens={() => handleEditLens(lens)}
+ />
+
+ )}
+ pagination={{
+ current,
+ pageSize,
+ showSizeChanger: true,
+ pageSizeOptions: ["5", "10", "20", "50"],
+ onChange: (page, newPageSize) => {
+ setCurrent(page);
+ setPageSize(newPageSize);
+ },
+ }}
+ />
+ )}
+
+ }
+ style={{position: "fixed", bottom: 20, right: 20}}
+ onClick={handleAddLens}
+ />
+
+ {/* setIsModalVisible(false)}*/}
+ {/* onSubmit={handleModalSubmit}*/}
+ {/* lens={selectedLens}*/}
+ {/*/>*/}
+
+ );
+};
+
+export default LensesPage;