для страницы пациентов вынес фнукции связанные с API в отдельный хук, также в UI хук вынес функции и переменные связанные с UI и состояниями
This commit is contained in:
parent
f840a0ab34
commit
793a47a58d
@ -10,7 +10,6 @@ const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
|
|||||||
|
|
||||||
const birthday = new Date(patient.birthday)
|
const birthday = new Date(patient.birthday)
|
||||||
|
|
||||||
|
|
||||||
const deletePatient = () => {
|
const deletePatient = () => {
|
||||||
handleDeletePatient(patient.id);
|
handleDeletePatient(patient.id);
|
||||||
};
|
};
|
||||||
|
|||||||
90
web-app/src/hooks/useLenses.js
Normal file
90
web-app/src/hooks/useLenses.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {
|
||||||
|
useAddLensMutation,
|
||||||
|
useDeleteLensMutation,
|
||||||
|
useGetLensesQuery,
|
||||||
|
useUpdateLensMutation
|
||||||
|
} from "../redux/services/lensesApi.js";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import {
|
||||||
|
closeModal,
|
||||||
|
setViewMode,
|
||||||
|
} from "../redux/slices/lensesSlice.js";
|
||||||
|
import {getCachedInfo} from "../utils/cachedInfoUtils.js";
|
||||||
|
import {notification} from "antd";
|
||||||
|
|
||||||
|
|
||||||
|
const useLenses = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const {
|
||||||
|
selectedLens,
|
||||||
|
} = useSelector(state => state.lensesUI);
|
||||||
|
|
||||||
|
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();
|
||||||
|
notification.success({
|
||||||
|
message: "Линза удалена",
|
||||||
|
description: "Линза успешно удалена.",
|
||||||
|
placement: "topRight",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: "Ошибка удаления",
|
||||||
|
description: error.data?.message || "Не удалось удалить линзу",
|
||||||
|
placement: "topRight",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleModalSubmit = async (lensData) => {
|
||||||
|
try {
|
||||||
|
if (selectedLens) {
|
||||||
|
await updateLens({id: selectedLens.id, ...lensData}).unwrap();
|
||||||
|
notification.success({
|
||||||
|
message: "Линза обновлена",
|
||||||
|
description: "Линза успешно обновлена.",
|
||||||
|
placement: "topRight",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await addLens(lensData).unwrap();
|
||||||
|
notification.success({
|
||||||
|
message: "Линза добавлена",
|
||||||
|
description: "Линза успешно добавлена.",
|
||||||
|
placement: "topRight",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dispatch(closeModal());
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: "Ошибка",
|
||||||
|
description: error.data?.message || "Произошла ошибка при сохранении",
|
||||||
|
placement: "topRight",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
lenses,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
handleDeleteLens,
|
||||||
|
handleModalSubmit,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useLenses;
|
||||||
@ -1,4 +1,3 @@
|
|||||||
import { useEffect } from "react";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { notification } from "antd";
|
import { notification } from "antd";
|
||||||
import {
|
import {
|
||||||
@ -8,25 +7,13 @@ import {
|
|||||||
useUpdatePatientMutation
|
useUpdatePatientMutation
|
||||||
} from "../redux/services/patientsApi";
|
} from "../redux/services/patientsApi";
|
||||||
import {
|
import {
|
||||||
openModal,
|
|
||||||
closeModal,
|
closeModal,
|
||||||
selectPatient,
|
|
||||||
setSearchText,
|
|
||||||
setSortOrder,
|
|
||||||
setViewMode,
|
|
||||||
setCurrentPage,
|
|
||||||
setPageSize
|
|
||||||
} from "../redux/slices/patientsSlice";
|
} from "../redux/slices/patientsSlice";
|
||||||
import { getCachedInfo } from "../utils/cachedInfoUtils";
|
|
||||||
|
|
||||||
const usePatients = () => {
|
const usePatients = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const {
|
const {
|
||||||
searchText,
|
|
||||||
sortOrder,
|
|
||||||
viewMode,
|
|
||||||
selectedPatient,
|
selectedPatient,
|
||||||
isModalVisible
|
|
||||||
} = useSelector(state => state.patientsUI);
|
} = useSelector(state => state.patientsUI);
|
||||||
|
|
||||||
const { data: patients = [], isLoading, isError } = useGetPatientsQuery(undefined, {
|
const { data: patients = [], isLoading, isError } = useGetPatientsQuery(undefined, {
|
||||||
@ -36,22 +23,6 @@ const usePatients = () => {
|
|||||||
const [updatePatient] = useUpdatePatientMutation();
|
const [updatePatient] = useUpdatePatientMutation();
|
||||||
const [deletePatient] = useDeletePatientMutation();
|
const [deletePatient] = useDeletePatientMutation();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = "Пациенты";
|
|
||||||
const cachedViewMode = getCachedInfo("viewModePatients");
|
|
||||||
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
const handleAddPatient = () => {
|
|
||||||
dispatch(selectPatient(null));
|
|
||||||
dispatch(openModal());
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditPatient = (patient) => {
|
|
||||||
dispatch(selectPatient(patient));
|
|
||||||
dispatch(openModal());
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeletePatient = async (patientId) => {
|
const handleDeletePatient = async (patientId) => {
|
||||||
try {
|
try {
|
||||||
await deletePatient(patientId).unwrap();
|
await deletePatient(patientId).unwrap();
|
||||||
@ -69,7 +40,7 @@ const usePatients = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalPatientSubmit = async (patientData) => {
|
const handleModalSubmit = async (patientData) => {
|
||||||
try {
|
try {
|
||||||
if (selectedPatient) {
|
if (selectedPatient) {
|
||||||
await updatePatient({ id: selectedPatient.id, ...patientData }).unwrap();
|
await updatePatient({ id: selectedPatient.id, ...patientData }).unwrap();
|
||||||
@ -100,20 +71,8 @@ const usePatients = () => {
|
|||||||
patients,
|
patients,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
searchText,
|
|
||||||
sortOrder,
|
|
||||||
viewMode,
|
|
||||||
isModalVisible,
|
|
||||||
selectedPatient,
|
|
||||||
handleAddPatient,
|
|
||||||
handleEditPatient,
|
|
||||||
handleDeletePatient,
|
handleDeletePatient,
|
||||||
handleModalPatientSubmit,
|
handleModalSubmit,
|
||||||
setSearchText: (text) => dispatch(setSearchText(text)),
|
|
||||||
setSortOrder: (order) => dispatch(setSortOrder(order)),
|
|
||||||
setViewMode: (mode) => dispatch(setViewMode(mode)),
|
|
||||||
setCurrentPage: (page) => dispatch(setCurrentPage(page)),
|
|
||||||
setPageSize: (size) => dispatch(setPageSize(size)),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
101
web-app/src/hooks/usePatientsUI.js
Normal file
101
web-app/src/hooks/usePatientsUI.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { useEffect, useMemo } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
openModal,
|
||||||
|
selectPatient,
|
||||||
|
setCurrentPage,
|
||||||
|
setPageSize,
|
||||||
|
setSearchText,
|
||||||
|
setSortOrder,
|
||||||
|
setViewMode
|
||||||
|
} 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();
|
||||||
|
const {
|
||||||
|
searchText,
|
||||||
|
sortOrder,
|
||||||
|
viewMode,
|
||||||
|
selectedPatient,
|
||||||
|
isModalVisible,
|
||||||
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
} = useSelector(state => state.patientsUI);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = "Пациенты";
|
||||||
|
const cachedViewMode = getCachedInfo("viewModePatients");
|
||||||
|
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const containerStyle = { padding: 20 };
|
||||||
|
const filterBarStyle = { marginBottom: 20 };
|
||||||
|
const formItemStyle = { width: "100%" };
|
||||||
|
|
||||||
|
const handleSetSearchText = (value) => dispatch(setSearchText(value));
|
||||||
|
const handleSetSortOrder = (value) => dispatch(setSortOrder(value));
|
||||||
|
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
|
||||||
|
const handleSetPageSize = (size) => dispatch(setPageSize(size));
|
||||||
|
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
|
||||||
|
const handleCloseModal = () => dispatch(closeModal());
|
||||||
|
|
||||||
|
const handlePaginationChange = (page, pageSize) => {
|
||||||
|
handleSetCurrentPage(page);
|
||||||
|
handleSetPageSize(pageSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddPatient = () => {
|
||||||
|
dispatch(selectPatient(null));
|
||||||
|
dispatch(openModal());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditPatient = (patient) => {
|
||||||
|
dispatch(selectPatient(patient));
|
||||||
|
dispatch(openModal());
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredPatients = useMemo(() => {
|
||||||
|
return patients
|
||||||
|
.filter(patient =>
|
||||||
|
Object.values(patient)
|
||||||
|
.filter(value => typeof value === "string")
|
||||||
|
.some(value => value.toLowerCase().includes(searchText.toLowerCase()))
|
||||||
|
)
|
||||||
|
.sort((a, b) => {
|
||||||
|
const fullNameA = `${a.last_name} ${a.first_name}`;
|
||||||
|
const fullNameB = `${b.last_name} ${b.first_name}`;
|
||||||
|
return sortOrder === "asc" ? fullNameA.localeCompare(fullNameB) : fullNameB.localeCompare(fullNameA);
|
||||||
|
});
|
||||||
|
}, [patients, searchText, sortOrder]);
|
||||||
|
|
||||||
|
const formatDate = (date) => new Date(date).toLocaleDateString();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
searchText,
|
||||||
|
sortOrder,
|
||||||
|
viewMode,
|
||||||
|
selectedPatient,
|
||||||
|
isModalVisible,
|
||||||
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
containerStyle,
|
||||||
|
filterBarStyle,
|
||||||
|
formItemStyle,
|
||||||
|
filteredPatients: patients.map(p => ({ ...p, key: p.id })),
|
||||||
|
handleSetSearchText,
|
||||||
|
handleSetSortOrder,
|
||||||
|
handleSetViewMode,
|
||||||
|
handleCloseModal,
|
||||||
|
handleAddPatient,
|
||||||
|
handleEditPatient,
|
||||||
|
formatDate,
|
||||||
|
handlePaginationChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default usePatientsUI;
|
||||||
@ -1,4 +1,3 @@
|
|||||||
import {useEffect, useMemo} from 'react';
|
|
||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
Select,
|
Select,
|
||||||
@ -16,67 +15,23 @@ import {
|
|||||||
BuildOutlined,
|
BuildOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
SortAscendingOutlined,
|
SortAscendingOutlined,
|
||||||
SortDescendingOutlined,
|
SortDescendingOutlined, TableOutlined,
|
||||||
TableOutlined,
|
|
||||||
TeamOutlined
|
TeamOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import {useDispatch, useSelector} from "react-redux";
|
|
||||||
import {
|
|
||||||
setSearchText,
|
|
||||||
setSortOrder,
|
|
||||||
setViewMode,
|
|
||||||
closeModal,
|
|
||||||
setCurrentPage,
|
|
||||||
setPageSize
|
|
||||||
} from "../redux/slices/patientsSlice.js";
|
|
||||||
import PatientListCard from "../components/patients/PatientListCard.jsx";
|
import PatientListCard from "../components/patients/PatientListCard.jsx";
|
||||||
import PatientFormModal from "../components/patients/PatientFormModal.jsx";
|
import PatientFormModal from "../components/patients/PatientFormModal.jsx";
|
||||||
import SelectViewMode from "../components/SelectViewMode.jsx";
|
import SelectViewMode from "../components/SelectViewMode.jsx";
|
||||||
import LoadingIndicator from "../components/LoadingIndicator.jsx";
|
import LoadingIndicator from "../components/LoadingIndicator.jsx";
|
||||||
import usePatients from "../hooks/usePatients.js";
|
import usePatients from "../hooks/usePatients.js";
|
||||||
|
import usePatientsUI from "../hooks/usePatientsUI.js";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
|
|
||||||
const PatientsPage = () => {
|
const PatientsPage = () => {
|
||||||
const dispatch = useDispatch();
|
const patientsData = usePatients();
|
||||||
const {
|
|
||||||
patients,
|
|
||||||
isLoading,
|
|
||||||
isError,
|
|
||||||
handleAddPatient,
|
|
||||||
handleEditPatient,
|
|
||||||
handleDeletePatient,
|
|
||||||
handleModalPatientSubmit
|
|
||||||
} = usePatients();
|
|
||||||
|
|
||||||
const {
|
const patientsUI = usePatientsUI(patientsData.patients);
|
||||||
searchText,
|
|
||||||
sortOrder,
|
|
||||||
viewMode,
|
|
||||||
selectedPatient,
|
|
||||||
isModalVisible,
|
|
||||||
currentPage,
|
|
||||||
pageSize
|
|
||||||
} = useSelector(state => state.patientsUI);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = "Пациенты";
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filteredPatients = useMemo(() => {
|
|
||||||
return patients
|
|
||||||
.filter(patient =>
|
|
||||||
Object.values(patient)
|
|
||||||
.filter(value => typeof value === "string")
|
|
||||||
.some(value => value.toLowerCase().includes(searchText.toLowerCase()))
|
|
||||||
)
|
|
||||||
.sort((a, b) => {
|
|
||||||
const fullNameA = `${a.last_name} ${a.first_name}`;
|
|
||||||
const fullNameB = `${b.last_name} ${b.first_name}`;
|
|
||||||
return sortOrder === "asc" ? fullNameA.localeCompare(fullNameB) : fullNameB.localeCompare(fullNameA);
|
|
||||||
});
|
|
||||||
}, [patients, searchText, sortOrder]);
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@ -97,41 +52,36 @@ const PatientsPage = () => {
|
|||||||
title: "Отчество",
|
title: "Отчество",
|
||||||
dataIndex: "patronymic",
|
dataIndex: "patronymic",
|
||||||
key: "patronymic",
|
key: "patronymic",
|
||||||
sorter: (a, b) => a.patronymic.localeCompare(b.patronymic),
|
|
||||||
sortDirections: ["ascend", "descend"],
|
sortDirections: ["ascend", "descend"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Дата рождения",
|
title: "Дата рождения",
|
||||||
dataIndex: "birthday",
|
dataIndex: "birthday",
|
||||||
key: "birthday",
|
|
||||||
sorter: (a, b) => new Date(a.birthday).getTime() - new Date(b.birthday).getTime(),
|
sorter: (a, b) => new Date(a.birthday).getTime() - new Date(b.birthday).getTime(),
|
||||||
sortDirections: ["ascend", "descend"],
|
sortDirections: ["ascend", "descend"],
|
||||||
render: (date) => new Date(date).toLocaleDateString()
|
render: patientsUI.formatDate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Телефон",
|
title: "Телефон",
|
||||||
dataIndex: "phone",
|
dataIndex: "phone",
|
||||||
key: "phone",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Email",
|
title: "Email",
|
||||||
dataIndex: "email",
|
dataIndex: "email",
|
||||||
key: "email",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Действия",
|
title: "Действия",
|
||||||
key: "actions",
|
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Row gutter={[8, 8]}>
|
<Row gutter={[8, 8]}>
|
||||||
<Col xs={24} xl={12}>
|
<Col xs={24} xl={12}>
|
||||||
<Button block onClick={() => handleEditPatient(record)}>Изменить</Button>
|
<Button block onClick={() => patientsUI.handleEditPatient(record)}>Изменить</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} xl={12}>
|
<Col xs={24} xl={12}>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="Вы уверены, что хотите удалить пациента?"
|
title="Вы уверены, что хотите удалить пациента?"
|
||||||
onConfirm={() => handleDeletePatient(record.id)}
|
onConfirm={() => patientsData.handleDeletePatient(record.id)}
|
||||||
okText="Да, удалить"
|
okText="Да, удалить"
|
||||||
cancelText="Отмена"
|
cancelText="Отмена"
|
||||||
>
|
>
|
||||||
@ -156,31 +106,35 @@ const PatientsPage = () => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isError) return <Result status="error" title="Ошибка" subTitle="Произошла ошибка в работе страницы"/>;
|
if (patientsData.isError) return (
|
||||||
|
<Result
|
||||||
|
status="error"
|
||||||
|
title="Ошибка"
|
||||||
|
subTitle="Произошла ошибка в работе страницы"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{padding: 20}}>
|
<div style={patientsUI.containerStyle}>
|
||||||
<Title level={1}><TeamOutlined/> Пациенты</Title>
|
<Title level={1}><TeamOutlined/> Пациенты</Title>
|
||||||
<Row gutter={[16, 16]} style={{marginBottom: 20}}>
|
<Row gutter={[16, 16]} style={patientsUI.filterBarStyle}>
|
||||||
<Col xs={24} md={14} sm={10} xl={18} xxl={19}>
|
<Col xs={24} md={14} sm={10} xl={18} xxl={19}>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Поиск пациента"
|
placeholder="Поиск пациента"
|
||||||
value={searchText}
|
value={patientsUI.searchText}
|
||||||
onChange={(e) => dispatch(setSearchText(e.target.value))}
|
onChange={(e) => patientsUI.handleSetSearchText(e.target.value)}
|
||||||
style={{width: "100%"}}
|
style={patientsUI.formItemStyle}
|
||||||
allowClear
|
allowClear
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
{viewMode === "tile" && (
|
{patientsUI.viewMode === "tile" && (
|
||||||
<Col xs={24} md={5} sm={6} xl={3} xxl={2}>
|
<Col xs={24} md={5} sm={6} xl={3} xxl={2}>
|
||||||
<Tooltip
|
<Tooltip title={"Сортировка пациентов"}>
|
||||||
title={"Сортировка пациентов"}
|
|
||||||
>
|
|
||||||
<Select
|
<Select
|
||||||
value={sortOrder}
|
value={patientsUI.sortOrder}
|
||||||
onChange={(value) => dispatch(setSortOrder(value))}
|
onChange={patientsUI.handleSetSortOrder}
|
||||||
style={{width: "100%"}}
|
style={patientsUI.formItemStyle}
|
||||||
>
|
>
|
||||||
<Option value="asc"><SortAscendingOutlined/> А-Я</Option>
|
<Option value="asc"><SortAscendingOutlined/> А-Я</Option>
|
||||||
<Option value="desc"><SortDescendingOutlined/> Я-А</Option>
|
<Option value="desc"><SortDescendingOutlined/> Я-А</Option>
|
||||||
@ -189,18 +143,13 @@ const PatientsPage = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Col xs={24} md={
|
<Col xs={24} md={patientsUI.viewMode === "tile" ? 5 : 10}
|
||||||
viewMode === "tile" ? 5 : 10
|
sm={patientsUI.viewMode === "tile" ? 8 : 14}
|
||||||
} sm={
|
xl={patientsUI.viewMode === "tile" ? 3 : 5}
|
||||||
viewMode === "tile" ? 8 : 14
|
xxl={patientsUI.viewMode === "tile" ? 3 : 5}>
|
||||||
} xl={
|
|
||||||
viewMode === "tile" ? 3 : 5
|
|
||||||
} xxl={
|
|
||||||
viewMode === "tile" ? 3 : 5
|
|
||||||
}>
|
|
||||||
<SelectViewMode
|
<SelectViewMode
|
||||||
viewMode={viewMode}
|
viewMode={patientsUI.viewMode}
|
||||||
setViewMode={value => dispatch(setViewMode(value))}
|
setViewMode={patientsUI.handleSetViewMode}
|
||||||
localStorageKey={"viewModePatients"}
|
localStorageKey={"viewModePatients"}
|
||||||
toolTipText={"Формат отображения пациентов"}
|
toolTipText={"Формат отображения пациентов"}
|
||||||
viewModes={viewModes}
|
viewModes={viewModes}
|
||||||
@ -208,48 +157,61 @@ const PatientsPage = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{isLoading ? <LoadingIndicator/> : viewMode === "tile" ? (
|
{patientsData.isLoading ? <LoadingIndicator/> : patientsUI.viewMode === "tile" ? (
|
||||||
<List
|
<List
|
||||||
grid={{gutter: 16, column: 3}}
|
grid={{gutter: 16, column: 3}}
|
||||||
dataSource={filteredPatients}
|
dataSource={patientsUI.filteredPatients}
|
||||||
renderItem={patient => (
|
renderItem={patient => (
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<PatientListCard
|
<PatientListCard
|
||||||
patient={patient}
|
patient={patient}
|
||||||
handleEditPatient={handleEditPatient}
|
handleEditPatient={patientsUI.handleEditPatient}
|
||||||
handleDeletePatient={handleDeletePatient}
|
handleDeletePatient={patientsData.handleDeletePatient}
|
||||||
/>
|
/>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
)}
|
)}
|
||||||
pagination={{
|
pagination={{
|
||||||
current: currentPage, pageSize, onChange: (p, s) => {
|
currentPage: patientsUI.currentPage,
|
||||||
dispatch(setCurrentPage(p));
|
pageSize: patientsUI.pageSize,
|
||||||
dispatch(setPageSize(s));
|
showSizeChanger: true,
|
||||||
}
|
pageSizeOptions: ["5", "10", "20", "50"],
|
||||||
|
onChange: (page, newPageSize) => {
|
||||||
|
patientsUI.handlePaginationChange(page, newPageSize);
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={filteredPatients.map(p => ({...p, key: p.id}))}
|
dataSource={patientsUI.filteredPatients}
|
||||||
pagination={{
|
pagination={{
|
||||||
current: currentPage, pageSize, onChange: (p, s) => {
|
currentPage: patientsUI.currentPage,
|
||||||
dispatch(setCurrentPage(p));
|
pageSize: patientsUI.pageSize,
|
||||||
dispatch(setPageSize(s));
|
showSizeChanger: true,
|
||||||
}
|
pageSizeOptions: ["5", "10", "20", "50"],
|
||||||
|
onChange: (page, newPageSize) => {
|
||||||
|
patientsUI.handlePaginationChange(page, newPageSize);
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<FloatButton icon={<PlusOutlined/>} type="primary" onClick={handleAddPatient} tooltip="Добавить пациента"/>
|
<FloatButton
|
||||||
|
icon={<PlusOutlined/>}
|
||||||
|
type="primary"
|
||||||
|
onClick={patientsUI.handleAddPatient}
|
||||||
|
tooltip="Добавить пациента"
|
||||||
|
/>
|
||||||
|
|
||||||
<PatientFormModal
|
<PatientFormModal
|
||||||
visible={isModalVisible}
|
visible={patientsUI.isModalVisible}
|
||||||
onCancel={() => dispatch(closeModal())}
|
onCancel={patientsUI.handleCloseModal}
|
||||||
onSubmit={handleModalPatientSubmit}
|
onSubmit={patientsData.handleModalSubmit}
|
||||||
patient={selectedPatient}
|
patient={patientsUI.selectedPatient}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
;
|
||||||
|
|
||||||
export default PatientsPage;
|
export default PatientsPage;
|
||||||
|
|||||||
@ -34,6 +34,9 @@ import LensFormModal from "../../components/lenses/LensFormModal.jsx";
|
|||||||
import SelectViewMode from "../../components/SelectViewMode.jsx";
|
import SelectViewMode from "../../components/SelectViewMode.jsx";
|
||||||
import LoadingIndicator from "../../components/LoadingIndicator.jsx";
|
import LoadingIndicator from "../../components/LoadingIndicator.jsx";
|
||||||
import {getCachedInfo, getCacheTimestamp} from "../../utils/cachedInfoUtils.js";
|
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";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
const {useBreakpoint} = Grid;
|
const {useBreakpoint} = Grid;
|
||||||
|
|||||||
53
web-app/src/redux/services/lensesApi.js
Normal file
53
web-app/src/redux/services/lensesApi.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
|
||||||
|
import CONFIG from "../../core/сonfig.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const lensesApi = createApi({
|
||||||
|
reducerPath: 'lensesApi',
|
||||||
|
baseQuery: fetchBaseQuery({
|
||||||
|
baseUrl: CONFIG.BASE_URL,
|
||||||
|
prepareHeaders: (headers) => {
|
||||||
|
const token = localStorage.getItem('access_token');
|
||||||
|
if (token) headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
tagTypes: ['Lens'],
|
||||||
|
endpoints: (builder) => ({
|
||||||
|
getLenses: builder.query({
|
||||||
|
query: () => '/lenses/',
|
||||||
|
providesTags: ['Lens'],
|
||||||
|
refetchOnMountOrArgChange: 5
|
||||||
|
}),
|
||||||
|
addLens: builder.mutation({
|
||||||
|
query: (lens) => ({
|
||||||
|
url: '/lenses/',
|
||||||
|
method: 'POST',
|
||||||
|
body: lens
|
||||||
|
}),
|
||||||
|
invalidatesTags: ['Lens']
|
||||||
|
}),
|
||||||
|
updateLens: builder.mutation({
|
||||||
|
query: ({ id, ...lens }) => ({
|
||||||
|
url: `/lenses/${id}/`,
|
||||||
|
method: 'PUT',
|
||||||
|
body: lens
|
||||||
|
}),
|
||||||
|
invalidatesTags: ['Lens']
|
||||||
|
}),
|
||||||
|
deleteLens: builder.mutation({
|
||||||
|
query: (id) => ({
|
||||||
|
url: `/lenses/${id}/`,
|
||||||
|
method: 'DELETE'
|
||||||
|
}),
|
||||||
|
invalidatesTags: ['Lens']
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
useGetLensesQuery,
|
||||||
|
useAddLensMutation,
|
||||||
|
useUpdateLensMutation,
|
||||||
|
useDeleteLensMutation,
|
||||||
|
} = lensesApi;
|
||||||
@ -5,10 +5,10 @@ export const patientsApi = createApi({
|
|||||||
reducerPath: 'patientsApi',
|
reducerPath: 'patientsApi',
|
||||||
baseQuery: fetchBaseQuery({
|
baseQuery: fetchBaseQuery({
|
||||||
baseUrl: CONFIG.BASE_URL,
|
baseUrl: CONFIG.BASE_URL,
|
||||||
prepareHeaders: (headers, { getState }) => {
|
prepareHeaders: (headers) => {
|
||||||
const token = localStorage.getItem('access_token')
|
const token = localStorage.getItem('access_token');
|
||||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
if (token) headers.set('Authorization', `Bearer ${token}`);
|
||||||
return headers
|
return headers;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
tagTypes: ['Patient'],
|
tagTypes: ['Patient'],
|
||||||
@ -40,9 +40,9 @@ export const patientsApi = createApi({
|
|||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
}),
|
}),
|
||||||
invalidatesTags: ['Patient']
|
invalidatesTags: ['Patient']
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
})
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetPatientsQuery,
|
useGetPatientsQuery,
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
import {createSlice} from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
const appointmentsSlice = createSlice({
|
|
||||||
name: 'appointments',
|
|
||||||
initialState: {
|
|
||||||
data: [],
|
|
||||||
status: 'idle',
|
|
||||||
error: null,
|
|
||||||
},
|
|
||||||
reducers: {
|
|
||||||
setAppointments(state, action) {
|
|
||||||
state.data = action.payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const {setAppointments} = appointmentsSlice.actions;
|
|
||||||
|
|
||||||
export default appointmentsSlice.reducer;
|
|
||||||
72
web-app/src/redux/slices/lensesSlice.js
Normal file
72
web-app/src/redux/slices/lensesSlice.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import {createSlice} from '@reduxjs/toolkit'
|
||||||
|
import {cacheInfo} from "../../utils/cachedInfoUtils.js";
|
||||||
|
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
searchText: '',
|
||||||
|
viewMode: 'tile',
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
selectedLens: null,
|
||||||
|
isModalVisible: false,
|
||||||
|
showAvancedSearch: false,
|
||||||
|
searchParams: {
|
||||||
|
tor: null,
|
||||||
|
diameter: null,
|
||||||
|
preset_refraction: null,
|
||||||
|
periphery_toricity: null,
|
||||||
|
side: 'all',
|
||||||
|
issued: false,
|
||||||
|
trial: null
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const lensesSlice = createSlice({
|
||||||
|
name: 'lensesUI',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setSearchText: (state, action) => {
|
||||||
|
state.searchText = action.payload;
|
||||||
|
},
|
||||||
|
setCurrentPage: (state, action) => {
|
||||||
|
state.currentPage = action.payload;
|
||||||
|
},
|
||||||
|
setPageSize: (state, action) => {
|
||||||
|
state.pageSize = action.payload;
|
||||||
|
},
|
||||||
|
setViewMode: (state, action) => {
|
||||||
|
state.viewMode = action.payload;
|
||||||
|
cacheInfo("viewModeLenses", action.payload);
|
||||||
|
},
|
||||||
|
openModal: (state) => {
|
||||||
|
state.isModalVisible = true;
|
||||||
|
},
|
||||||
|
closeModal: (state) => {
|
||||||
|
state.isModalVisible = false;
|
||||||
|
state.selectedLens = null;
|
||||||
|
},
|
||||||
|
selectLens: (state, action) => {
|
||||||
|
state.selectedLens = action.payload;
|
||||||
|
},
|
||||||
|
setSearchParams: (state, action) => {
|
||||||
|
state.searchParams = action.payload;
|
||||||
|
},
|
||||||
|
setShowAdvancedSearch: (state, action) => {
|
||||||
|
state.showAvancedSearch = action.payload;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
setSearchText,
|
||||||
|
setCurrentPage,
|
||||||
|
setPageSize,
|
||||||
|
setViewMode,
|
||||||
|
openModal,
|
||||||
|
closeModal,
|
||||||
|
selectLens,
|
||||||
|
setSearchParams,
|
||||||
|
setShowAdvancedSearch
|
||||||
|
} = lensesSlice.actions;
|
||||||
|
|
||||||
|
export default lensesSlice.reducer;
|
||||||
@ -9,7 +9,7 @@ const initialState = {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
selectedPatient: null,
|
selectedPatient: null,
|
||||||
isModalVisible: false
|
isModalVisible: false
|
||||||
}
|
};
|
||||||
|
|
||||||
const patientsSlice = createSlice({
|
const patientsSlice = createSlice({
|
||||||
name: 'patientsUI',
|
name: 'patientsUI',
|
||||||
@ -53,6 +53,6 @@ export const {
|
|||||||
openModal,
|
openModal,
|
||||||
closeModal,
|
closeModal,
|
||||||
selectPatient
|
selectPatient
|
||||||
} = patientsSlice.actions
|
} = patientsSlice.actions;
|
||||||
|
|
||||||
export default patientsSlice.reducer
|
export default patientsSlice.reducer;
|
||||||
Loading…
x
Reference in New Issue
Block a user