diff --git a/web-app/src/hooks/useLenses.js b/web-app/src/hooks/useLenses.js
index cba0558..6737292 100644
--- a/web-app/src/hooks/useLenses.js
+++ b/web-app/src/hooks/useLenses.js
@@ -5,12 +5,9 @@ import {
useGetLensesQuery,
useUpdateLensMutation
} from "../redux/services/lensesApi.js";
-import {useEffect} from "react";
import {
- closeModal,
- setViewMode,
+ closeModal
} from "../redux/slices/lensesSlice.js";
-import {getCachedInfo} from "../utils/cachedInfoUtils.js";
import {notification} from "antd";
@@ -24,16 +21,11 @@ const useLenses = () => {
const {data: lenses = [], isLoading, isError} = useGetLensesQuery(undefined, {
pollingInterval: 20000,
});
+
const [addLens] = useAddLensMutation();
const [updateLens] = useUpdateLensMutation();
const [deleteLens] = useDeleteLensMutation();
- useEffect(() => {
- document.title = "Линзы";
- const cachedViewMode = getCachedInfo("viewModeLenses");
- if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
- }, [dispatch]);
-
const handleDeleteLens = async (lensId) => {
try {
await deleteLens(lensId).unwrap();
diff --git a/web-app/src/hooks/useLensesUI.js b/web-app/src/hooks/useLensesUI.js
new file mode 100644
index 0000000..95c0a2a
--- /dev/null
+++ b/web-app/src/hooks/useLensesUI.js
@@ -0,0 +1,115 @@
+import {useEffect} from "react";
+import {getCachedInfo} from "../utils/cachedInfoUtils.js";
+import {
+ closeModal,
+ openModal,
+ selectLens, setCurrentPage, setPageSize,
+ setSearchParams,
+ setSearchText, setShowAdvancedSearch,
+ setViewMode
+} from "../redux/slices/lensesSlice.js";
+import {useDispatch, useSelector} from "react-redux";
+
+
+const useLensesUI = (lenses) => {
+ const dispatch = useDispatch();
+ const {
+ searchText,
+ viewMode,
+ currentPage,
+ pageSize,
+ selectedLens,
+ isModalVisible,
+ showAdvancedSearch,
+ searchParams,
+ } = useSelector(state => state.lensesUI);
+
+ useEffect(() => {
+ document.title = "Линзы";
+ const cachedViewMode = getCachedInfo("viewModeLenses");
+ if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
+ }, [dispatch]);
+
+ const handleSetSearchText = (value) => dispatch(setSearchText(value));
+ const handleCloseModal = () => dispatch(closeModal());
+ const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
+ const handleSetPageSize = (size) => dispatch(setPageSize(size));
+ const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
+
+ const handleAddLens = () => {
+ dispatch(selectLens(null));
+ dispatch(openModal());
+ };
+
+ const handleEditLens = (lens) => {
+ dispatch(selectLens(lens));
+ dispatch(openModal());
+ };
+
+ const handleParamChange = (param, value) => {
+ dispatch(setSearchParams({...searchParams, [param]: value}));
+ };
+
+ const toggleAdvancedSearch = () => {
+ dispatch(setShowAdvancedSearch(!showAdvancedSearch));
+ };
+
+ const handlePaginationChange = (page, pageSize) => {
+ handleSetCurrentPage(page);
+ handleSetPageSize(pageSize);
+ };
+
+ const filteredLenses = lenses.filter((lens) => {
+ const textMatch = Object.values(lens).some((value) =>
+ value?.toString().toLowerCase().includes(searchText.toLowerCase())
+ );
+
+ const advancedMatch = Object.entries(searchParams).every(([key, value]) => {
+ if (value === null || value === '') return true;
+ if (key === 'side') {
+ if (value === 'all') return true;
+ return lens.side === value;
+ }
+ if (key === 'issued') {
+ return lens.issued === value || value === "all";
+ }
+ return lens[key] === value;
+ });
+
+ return textMatch && advancedMatch && (searchParams.issued || lens.issued === false);
+ }).sort((a, b) => {
+ return a.preset_refraction - b.preset_refraction;
+ });
+
+ const pagination = {
+ currentPage: currentPage,
+ pageSize: pageSize,
+ showSizeChanger: true,
+ pageSizeOptions: ["5", "10", "20", "50"],
+ onChange: (page, newPageSize) => {
+ handlePaginationChange(page, newPageSize);
+ },
+ };
+
+ return {
+ searchText,
+ viewMode,
+ currentPage,
+ pageSize,
+ selectedLens,
+ isModalVisible,
+ showAdvancedSearch,
+ searchParams,
+ pagination,
+ filteredLenses: filteredLenses.map(lens => ({...lens, key: lens.id})),
+ handleSetSearchText,
+ handleAddLens,
+ handleEditLens,
+ handleCloseModal,
+ handleParamChange,
+ toggleAdvancedSearch,
+ handleSetViewMode,
+ }
+};
+
+export default useLensesUI;
\ No newline at end of file
diff --git a/web-app/src/hooks/usePatientsUI.js b/web-app/src/hooks/usePatientsUI.js
index 6ede3ee..6421c31 100644
--- a/web-app/src/hooks/usePatientsUI.js
+++ b/web-app/src/hooks/usePatientsUI.js
@@ -11,7 +11,6 @@ import {
} from "../redux/slices/patientsSlice";
import { closeModal } from "../redux/slices/lensesSlice";
import { getCachedInfo } from "../utils/cachedInfoUtils";
-import {BuildOutlined, TableOutlined} from "@ant-design/icons";
const usePatientsUI = (patients) => {
const dispatch = useDispatch();
@@ -73,7 +72,15 @@ const usePatientsUI = (patients) => {
const formatDate = (date) => new Date(date).toLocaleDateString();
-
+ const pagination = {
+ currentPage: currentPage,
+ pageSize: pageSize,
+ showSizeChanger: true,
+ pageSizeOptions: ["5", "10", "20", "50"],
+ onChange: (page, newPageSize) => {
+ handlePaginationChange(page, newPageSize);
+ },
+ };
return {
searchText,
@@ -86,7 +93,8 @@ const usePatientsUI = (patients) => {
containerStyle,
filterBarStyle,
formItemStyle,
- filteredPatients: patients.map(p => ({ ...p, key: p.id })),
+ pagination,
+ filteredPatients: filteredPatients.map(p => ({ ...p, key: p.id })),
handleSetSearchText,
handleSetSortOrder,
handleSetViewMode,
diff --git a/web-app/src/pages/PatientsPage.jsx b/web-app/src/pages/PatientsPage.jsx
index 512836a..0b31867 100644
--- a/web-app/src/pages/PatientsPage.jsx
+++ b/web-app/src/pages/PatientsPage.jsx
@@ -30,7 +30,6 @@ const {Title} = Typography;
const PatientsPage = () => {
const patientsData = usePatients();
-
const patientsUI = usePatientsUI(patientsData.patients);
const columns = [
@@ -170,29 +169,13 @@ const PatientsPage = () => {
/>
)}
- pagination={{
- currentPage: patientsUI.currentPage,
- pageSize: patientsUI.pageSize,
- showSizeChanger: true,
- pageSizeOptions: ["5", "10", "20", "50"],
- onChange: (page, newPageSize) => {
- patientsUI.handlePaginationChange(page, newPageSize);
- },
- }}
+ pagination={patientsUI.pagination}
/>
) : (
{
- patientsUI.handlePaginationChange(page, newPageSize);
- },
- }}
+ pagination={patientsUI.pagination}
/>
)}
diff --git a/web-app/src/pages/lenses_layout/LensesPage.jsx b/web-app/src/pages/lenses_layout/LensesPage.jsx
index 46b703f..7f89929 100644
--- a/web-app/src/pages/lenses_layout/LensesPage.jsx
+++ b/web-app/src/pages/lenses_layout/LensesPage.jsx
@@ -1,4 +1,3 @@
-import {useState, useEffect} from "react";
import {
Input,
Select,
@@ -11,10 +10,9 @@ import {
InputNumber,
Card,
Grid,
- notification,
Table,
Popconfirm,
- Typography
+ Typography, Result
} from "antd";
import {
PlusOutlined,
@@ -25,188 +23,22 @@ import {
BuildOutlined
} from "@ant-design/icons";
import LensCard from "../../components/lenses/LensListCard.jsx";
-import getAllLenses from "../../api/lenses/getAllLenses.js";
-import addLens from "../../api/lenses/addLens.js";
-import updateLens from "../../api/lenses/updateLens.js";
-import deleteLens from "../../api/lenses/deleteLens.js";
-import {useAuth} from "../../AuthContext.jsx";
import LensFormModal from "../../components/lenses/LensFormModal.jsx";
import SelectViewMode from "../../components/SelectViewMode.jsx";
import LoadingIndicator from "../../components/LoadingIndicator.jsx";
-import {getCachedInfo, getCacheTimestamp} from "../../utils/cachedInfoUtils.js";
-import {useDispatch} from "react-redux";
import useLenses from "../../hooks/useLenses.js";
-import {openModal, selectLens} from "../../redux/slices/lensesSlice.js";
+import useLensesUI from "../../hooks/useLensesUI.js";
const {Option} = Select;
const {useBreakpoint} = Grid;
const {Title} = Typography;
const LensesPage = () => {
- const {api} = useAuth();
+ const lensesData = useLenses();
+ const lensesUI = useLensesUI(lensesData.lenses);
+
const screens = useBreakpoint();
- const [current, setCurrent] = useState(1);
- const [pageSize, setPageSize] = useState(10);
-
- const [searchText, setSearchText] = useState("");
- const [viewMode, setViewMode] = useState("tile");
- const [loading, setLoading] = useState(true);
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [showAdvancedSearch, setShowAdvancedSearch] = useState(false);
-
- const [selectedLens, setSelectedLens] = useState(null);
- const [lenses, setLenses] = useState([]);
-
- const [searchParams, setSearchParams] = useState({
- tor: null,
- diameter: null,
- preset_refraction: null,
- periphery_toricity: null,
- side: 'all',
- issued: false,
- trial: null
- });
-
- useEffect(() => {
- fetchLensWithCache();
- fetchViewModeFromCache();
- document.title = "Линзы";
- }, []);
-
- useEffect(() => {
- if (!isModalVisible && !selectedLens) {
- const intervalId = setInterval(fetchLenses, 5000);
- return () => clearInterval(intervalId);
- }
- }, [isModalVisible, selectedLens]);
-
- const fetchLensWithCache = async () => {
- const cachedData = getCachedInfo("lensData");
- const cacheTimestamp = getCacheTimestamp("lensData");
-
- if (cachedData && cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 60 * 1000) {
- setLenses(JSON.parse(cachedData));
- setLoading(false);
- return;
- }
-
- await fetchLenses();
- };
-
- const fetchLenses = async () => {
- const data = await getAllLenses(api);
- setLenses(data);
- setLoading(false);
- };
-
- const fetchViewModeFromCache = () => {
- const cachedViewMode = getCachedInfo("viewModeLenses");
- if (cachedViewMode) {
- setViewMode(cachedViewMode);
- }
- };
-
- const filteredLenses = lenses.filter((lens) => {
- const textMatch = Object.values(lens).some((value) =>
- value?.toString().toLowerCase().includes(searchText.toLowerCase())
- );
-
- const advancedMatch = Object.entries(searchParams).every(([key, value]) => {
- if (value === null || value === '') return true;
- if (key === 'side') {
- if (value === 'all') return true;
- return lens.side === value;
- }
- if (key === 'issued') {
- return lens.issued === value || value === "all";
- }
- return lens[key] === value;
- });
-
- return textMatch && advancedMatch && (searchParams.issued || lens.issued === false);
- }).sort((a, b) => {
- return a.preset_refraction - b.preset_refraction;
- });
-
- const handleAddLens = () => {
- setSelectedLens(null);
- setIsModalVisible(true);
- };
-
- const handleEditLens = (lens) => {
- setSelectedLens(lens);
- setIsModalVisible(true);
- };
-
- const handleDeleteLens = async (lensId) => {
- await deleteLens(api, lensId);
- await fetchLenses(api);
- notification.success({
- message: "Линза удалена",
- description: "Линза успешно удалена.",
- placement: "topRight",
- })
- };
-
- const handleModalSubmit = async (lensData) => {
- 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 = () => {
- setShowAdvancedSearch(!showAdvancedSearch);
- };
-
- const handleParamChange = (param, value) => {
- setSearchParams({...searchParams, [param]: value});
- };
-
- const handleCancel = () => {
- setIsModalVisible(false);
- };
-
- const TileView = () => (
- (
-
- handleDeleteLens(lens.id)}
- handleEditLens={() => handleEditLens(lens)}
- />
-
- )}
- pagination={{
- current,
- pageSize,
- showSizeChanger: true,
- pageSizeOptions: ["5", "10", "20", "50"],
- onChange: (page, newPageSize) => {
- setCurrent(page);
- setPageSize(newPageSize);
- },
- }}
- />
- );
-
const viewModes = [
{
value: "tile",
@@ -284,11 +116,11 @@ const LensesPage = () => {
fixed: 'right',
render: (text, record) => (
-
+
handleDeleteLens(record.id)}
+ onConfirm={() => lensesData.handleDeleteLens(record.id)}
okText="Да, удалить"
cancelText="Отмена"
>
@@ -299,24 +131,11 @@ const LensesPage = () => {
},
];
- const TableView = () => (
- ({...lens, key: lens.id}))}
- scroll={{
- x: "max-content"
- }}
- showSorterTooltip={false}
- pagination={{
- current,
- pageSize,
- showSizeChanger: true,
- pageSizeOptions: ["5", "10", "20", "50"],
- onChange: (page, newPageSize) => {
- setCurrent(page);
- setPageSize(newPageSize);
- },
- }}
+ if (lensesData.isError) return (
+
);
@@ -327,15 +146,16 @@ const LensesPage = () => {
setSearchText(e.target.value)}
+ value={lensesUI.searchText}
+ onChange={(e) => lensesUI.handleSetSearchText(e.target.value)}
style={{width: "100%"}}
allowClear
/>
: }
+ onClick={lensesUI.toggleAdvancedSearch}
+ icon={lensesUI.showAdvancedSearch ? : }
block
>
Расширенный поиск
@@ -343,8 +163,8 @@ const LensesPage = () => {
{
- {showAdvancedSearch && (
+ {lensesUI.showAdvancedSearch && (
{
handleParamChange("tor", value)}
+ value={lensesUI.searchParams.tor || 0}
+ onChange={(value) => lensesUI.handleParamChange("tor", value)}
style={{width: "100%"}}
defaultValue={0}
step={0.1}
@@ -376,8 +196,8 @@ const LensesPage = () => {
handleParamChange("diameter", value)}
+ value={lensesUI.searchParams.diameter || 0}
+ onChange={(value) => lensesUI.handleParamChange("diameter", value)}
style={{width: "100%"}}
defaultValue={0}
step={0.1}
@@ -386,8 +206,8 @@ const LensesPage = () => {
handleParamChange("preset_refraction", value)}
+ value={lensesUI.searchParams.preset_refraction || 0}
+ onChange={(value) => lensesUI.handleParamChange("preset_refraction", value)}
style={{width: "100%"}}
defaultValue={0}
step={0.1}
@@ -396,8 +216,8 @@ const LensesPage = () => {
handleParamChange("periphery_toricity", value)}
+ value={lensesUI.searchParams.periphery_toricity || 0}
+ onChange={(value) => lensesUI.handleParamChange("periphery_toricity", value)}
style={{width: "100%"}}
defaultValue={0}
step={0.1}
@@ -410,8 +230,8 @@ const LensesPage = () => {
)}
- {loading ? (
+ {lensesData.isLoading ? (
- ) : viewMode === "tile" ? (
-
+ ) : lensesUI.viewMode === "tile" ? (
+ (
+
+ lensesData.handleDeleteLens(lens.id)}
+ handleEditLens={() => lensesUI.handleEditLens(lens)}
+ />
+
+ )}
+ pagination={lensesUI.pagination}
+ />
) : (
-
+
)}
}
type="primary"
style={{position: "fixed", bottom: 40, right: 40}}
- onClick={handleAddLens}
+ onClick={lensesUI.handleAddLens}
tooltip="Добавить линзу"
/>
);
diff --git a/web-app/src/redux/slices/lensesSlice.js b/web-app/src/redux/slices/lensesSlice.js
index 1468d68..f26bfc1 100644
--- a/web-app/src/redux/slices/lensesSlice.js
+++ b/web-app/src/redux/slices/lensesSlice.js
@@ -9,7 +9,7 @@ const initialState = {
pageSize: 10,
selectedLens: null,
isModalVisible: false,
- showAvancedSearch: false,
+ showAdvancedSearch: false,
searchParams: {
tor: null,
diameter: null,
@@ -52,7 +52,7 @@ const lensesSlice = createSlice({
state.searchParams = action.payload;
},
setShowAdvancedSearch: (state, action) => {
- state.showAvancedSearch = action.payload;
+ state.showAdvancedSearch = action.payload;
},
}
});
diff --git a/web-app/src/redux/store.js b/web-app/src/redux/store.js
index d4e1c00..a42656c 100644
--- a/web-app/src/redux/store.js
+++ b/web-app/src/redux/store.js
@@ -1,15 +1,20 @@
-import { configureStore } from '@reduxjs/toolkit'
-import {patientsApi} from "./services/patientsApi.js";
-import patientsUIReducer from './slices/patientsSlice.js'
+import {configureStore} from '@reduxjs/toolkit';
+import {patientsApi} from './services/patientsApi.js';
+import patientsUIReducer from './slices/patientsSlice.js';
+import {lensesApi} from './services/lensesApi.js';
+import lensesReducer from './slices/lensesSlice.js';
export const store = configureStore({
reducer: {
[patientsApi.reducerPath]: patientsApi.reducer,
- patientsUI: patientsUIReducer
- },
- middleware: (getDefaultMiddleware) =>
- getDefaultMiddleware().concat(patientsApi.middleware)
-})
+ patientsUI: patientsUIReducer,
+ [lensesApi.reducerPath]: lensesApi.reducer,
+ lensesUI: lensesReducer,
+ },
+ middleware: (getDefaultMiddleware) => (
+ getDefaultMiddleware().concat(patientsApi.middleware, lensesApi.middleware)
+ )
+});
export default store;