начал разделять компоненты и логику в отдельные файлы

This commit is contained in:
Андрей Дувакин 2025-04-05 21:34:09 +05:00
parent a1cf2f7c88
commit a5a6d1d7fa
25 changed files with 541 additions and 382 deletions

View File

@ -0,0 +1,21 @@
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
import CONFIG from "../Core/сonfig.js";
export const authApi = createApi({
reducerPath: 'authApi',
baseQuery: fetchBaseQuery({
baseUrl: CONFIG.BASE_URL,
}),
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: '/auth/login/',
method: 'POST',
body: credentials
})
}),
})
});
export const {useLoginMutation} = authApi;

View File

@ -15,7 +15,7 @@ export const lensIssuesApi = createApi({
tagTypes: ['LensIssues'],
endpoints: (builder) => ({
getLensIssues: builder.query({
query: () => '/LensIssues/',
query: () => '/lens_issues/',
providesTags: ['LensIssues'],
refetchOnMountOrArgChange: 5
}),

View File

@ -0,0 +1,22 @@
import CONFIG from "../Core/сonfig.js";
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
export const lensTypesApi = createApi({
reducerPath: 'lensTypesApi',
baseQuery: fetchBaseQuery({
baseUrl: CONFIG.BASE_URL,
prepareHeaders: (headers) => {
const token = localStorage.getItem('access_token');
if (token) headers.set('Authorization', `Bearer ${token}`);
return headers;
}
}),
endpoints: (builder) => ({
getLensTypes: builder.query({
query: () => `/lens_types/`,
}),
}),
});
export const {useGetLensTypesQuery} = lensTypesApi;

View File

@ -15,7 +15,7 @@ export const lensesApi = createApi({
tagTypes: ['Lens'],
endpoints: (builder) => ({
getLenses: builder.query({
query: () => '/Lenses/',
query: () => '/lenses/',
providesTags: ['Lens'],
refetchOnMountOrArgChange: 5
}),

View File

@ -14,7 +14,7 @@ export const patientsApi = createApi({
tagTypes: ['Patient'],
endpoints: (builder) => ({
getPatients: builder.query({
query: () => '/Patients/',
query: () => '/patients/',
providesTags: ['Patient'],
refetchOnMountOrArgChange: 5
}),

View File

@ -14,7 +14,7 @@ export const setContentApi = createApi({
tagTypes: ['SetContent'],
endpoints: (builder) => ({
getSetContent: builder.query({
query: (setId) => `/set_content/${setId}`,
query: (setId) => `/set_content/${setId}/`,
providesTags: ['SetContent'],
}),
addSetContent: builder.mutation({

View File

@ -14,7 +14,7 @@ export const setsApi = createApi({
tagTypes: ['Set'],
endpoints: (builder) => ({
getSets: builder.query({
query: () => '/Sets/',
query: () => '/sets/',
providesTags: ['Set'],
refetchOnMountOrArgChange: 5
}),

View File

@ -2,7 +2,7 @@ import {Card, Popconfirm, Tooltip} from "antd";
import PropTypes from "prop-types";
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
import {useState} from "react";
import LensViewModal from "../Widgets/LensViewModal.jsx";
import LensViewModal from "../Pages/LensesPage/Components/LensViewModal/LensViewModal.jsx";
import {LensPropType} from "../../Types/lensPropType.js";
const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {

View File

@ -2,7 +2,7 @@ import {Card, Modal, Popconfirm, Tooltip} from "antd";
import PropTypes from "prop-types";
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
import {useState} from "react";
import PatientViewModal from "../Widgets/PatientViewModal.jsx";
import PatientViewModal from "../Pages/PatientsPage/Components/PatientViewModal/PatientViewModal.jsx";
import {PatientPropType} from "../../Types/patientPropType.js";
const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {

View File

@ -1,63 +1,28 @@
import {Col, Form, InputNumber, Modal, notification, Row, Select} from "antd";
import {useEffect, useState} from "react";
import {Col, Form, InputNumber, Modal, Row, Select} from "antd";
import PropTypes from "prop-types";
import getAllLensTypes from "../../old_api/lens_types/getAllLensTypes.js";
import {useAuth} from "../../Hooks/AuthContext.jsx";
import {LensPropType} from "../../Types/lensPropType.js";
import {LensPropType} from "../../../../../Types/lensPropType.js";
import useLensFormModal from "./useLensFormModal.js";
import useLensFormModalUI from "./useLensFormModalUI.js";
const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
const {api} = useAuth();
const [form] = Form.useForm();
const [lensTypes, setLensTypes] = useState([]);
useEffect(() => {
fetchLensTypes();
}, []);
useEffect(() => {
if (visible) {
form.resetFields();
if (lens) {
form.setFieldsValue({
...lens,
});
}
}
}, [visible, lens]);
const fetchLensTypes = async () => {
const data = await getAllLensTypes(api);
setLensTypes(data);
};
const handleOk = async () => {
try {
const values = await form.validateFields();
onSubmit(values);
form.resetFields();
} catch (error) {
console.log("Validation Failed:", error);
}
};
const lensFormData = useLensFormModal();
const lensFormUI = useLensFormModalUI(lensFormData.lensTypes, visible, onCancel, onSubmit, lens);
return (
<Modal
title={lens ? "Редактировать лину" : "Добавить линзу"}
open={visible}
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={handleOk}
onCancel={lensFormUI.handleCancel}
onOk={lensFormUI.handleOk}
okText={"Сохранить"}
cancelText={"Отмена"}
maskClosable={false}
forceRender={true}
style={{top: 20}}
style={lensFormUI.modalStyle}
centered
>
<Form form={form} layout={"vertical"}>
<Form form={lensFormUI.form} layout={"vertical"}>
<Row gutter={16}>
<Col xs={24} md={12}>
<Form.Item
@ -66,9 +31,8 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите тор"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
</Form.Item>
</Col>
@ -79,7 +43,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите остроту зрения"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -94,7 +58,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите esa"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -107,7 +71,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите fvc"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -122,7 +86,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите пресетную рефракцию"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -135,7 +99,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите диаметр"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -150,7 +114,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
rules={[{required: true, message: "Введите периферию торичность"}]}
>
<InputNumber
style={{width: '100%'}}
style={lensFormUI.formItemStyle}
step={0.1}
/>
@ -162,7 +126,7 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
label="Сторона"
rules={[{required: true, message: "Выберите сторону"}]}
>
<Select style={{width: '100%'}}>
<Select style={lensFormUI.formItemStyle}>
<Select.Option value="левая">Левая</Select.Option>
<Select.Option value="правая">Правая</Select.Option>
</Select>
@ -174,8 +138,8 @@ const LensFormModal = ({visible, onCancel, onSubmit, lens}) => {
label="Тип линзы"
rules={[{required: true, message: "Выберите тип линзы"}]}
>
<Select style={{width: '100%'}}>
{lensTypes.map((type) => (
<Select style={lensFormUI.formItemStyle}>
{lensFormData.lensTypes.map((type) => (
<Select.Option key={type.id} value={type.id}>
{type.title}
</Select.Option>

View File

@ -0,0 +1,10 @@
import {useGetLensTypesQuery} from "../../../../../Api/lensTypesApi.js";
const useLensFormModal = () => {
const {data: lensTypes = [], isLoading, isError} = useGetLensTypesQuery(undefined);
return {lensTypes, isLoading, isError};
};
export default useLensFormModal;

View File

@ -0,0 +1,48 @@
import {useEffect} from "react";
import {Form} from "antd";
const useLensFormModalUI = (lensTypes, visible, onCancel, onSubmit, lens) => {
const [form] = Form.useForm();
useEffect(() => {
if (visible) {
form.resetFields();
if (lens) {
form.setFieldsValue({
...lens,
});
}
}
}, [visible, lens, form]);
const modalStyle = {
marginTop: 20,
};
const formItemStyle = { width: "100%" };
const handleOk = async () => {
try {
const values = await form.validateFields();
onSubmit(values);
form.resetFields();
} catch (error) {
console.log("Validation Failed:", error);
}
};
const handleCancel = () => {
form.resetFields();
onCancel();
};
return {
form,
modalStyle,
formItemStyle,
handleOk,
handleCancel,
};
};
export default useLensFormModalUI;

View File

@ -1,6 +1,6 @@
import {Button, Col, Modal, Row, Typography} from "antd";
import PropTypes from "prop-types";
import {LensPropType} from "../../Types/lensPropType.js";
import {LensPropType} from "../../../../../Types/lensPropType.js";
const {Text, Title} = Typography;

View File

@ -23,7 +23,7 @@ import {
BuildOutlined
} from "@ant-design/icons";
import LensCard from "../../Dummies/LensListCard.jsx";
import LensFormModal from "../../Widgets/LensFormModal.jsx";
import LensFormModal from "./Components/LensFormModal/LensFormModal.jsx";
import SelectViewMode from "../../Widgets/SelectViewMode.jsx";
import LoadingIndicator from "../../Widgets/LoadingIndicator.jsx";
import useLenses from "./useLenses.js";

View File

@ -1,64 +1,30 @@
import {useEffect} from "react";
import {Modal, Form, Input, DatePicker, notification} from "antd";
import {Modal, Form, Input, DatePicker} from "antd";
import PropTypes from "prop-types";
import locale from "antd/es/date-picker/locale/ru_RU";
import validator from "validator";
import {MaskedInput} from "antd-mask-input";
import dayjs from "dayjs";
import {PatientPropType} from "../../Types/patientPropType.js";
import {PatientPropType} from "../../../../../Types/patientPropType.js";
import usePatientFormModalUI from "./usePatientFormModalUI.js";
const {TextArea} = Input;
const PatientFormModal = ({visible, onCancel, onSubmit, patient}) => {
const [form] = Form.useForm();
useEffect(() => {
if (visible) {
form.resetFields();
if (patient) {
form.setFieldsValue({
...patient,
birthday: patient.birthday ? dayjs(patient.birthday, "YYYY-MM-DD") : null,
});
}
}
}, [visible, patient]);
const handleOk = async () => {
try {
const values = await form.validateFields();
if (values.birthday) {
values.birthday = values.birthday.format("YYYY-MM-DD");
}
onSubmit(values);
form.resetFields();
} catch (error) {
console.log("Validation Failed:", error);
notification.error({
message: "Ошибка валидации",
description: "Проверьте правильность заполнения полей.",
placement: "topRight",
});
}
};
const patientFormModalUI = usePatientFormModalUI(visible, onCancel, onSubmit, patient);
return (
<Modal
title={patient ? "Редактировать пациента" : "Добавить пациента"}
title={patientFormModalUI.modalTitle}
open={visible}
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={handleOk}
onCancel={patientFormModalUI.handleCancel}
onOk={patientFormModalUI.handleOk}
okText={"Сохранить"}
cancelText={"Отмена"}
maskClosable={false}
forceRender={true}
style={{marginTop: 20, marginBottom: 50}}
style={patientFormModalUI.modalStyle}
centered
>
<Form form={form} layout={"vertical"}>
<Form form={patientFormModalUI.form} layout={"vertical"}>
<Form.Item
name="first_name"
label="Имя"
@ -101,12 +67,7 @@ const PatientFormModal = ({visible, onCancel, onSubmit, patient}) => {
label="Email"
rules={[
{
validator: (_, value) => {
if (value && !validator.isEmail(value)) {
return Promise.reject("Некорректный email");
}
return Promise.resolve();
},
validator: patientFormModalUI.emailValidator,
},
]}
>

View File

@ -0,0 +1,68 @@
import {Form, notification} from "antd";
import {useEffect} from "react";
import dayjs from "dayjs";
import validator from "validator";
const usePatientFormModalUI = (visible, onCancel, onSubmit, patient) => {
const [form] = Form.useForm();
useEffect(() => {
if (visible) {
form.resetFields();
if (patient) {
form.setFieldsValue({
...patient,
birthday: patient.birthday ? dayjs(patient.birthday, "YYYY-MM-DD") : null,
});
}
}
}, [visible, patient, form]);
const modalStyle = {
marginTop: 20,
marginBottom: 50,
};
const modalTitle = patient ? "Редактировать пациента" : "Добавить пациента";
const emailValidator = (_, value) => {
if (value && !validator.isEmail(value)) {
return Promise.reject("Некорректный email");
}
return Promise.resolve();
};
const handleOk = async () => {
try {
const values = await form.validateFields();
if (values.birthday) {
values.birthday = values.birthday.format("YYYY-MM-DD");
}
onSubmit(values);
form.resetFields();
} catch (error) {
console.log("Validation Failed:", error);
notification.error({
message: "Ошибка валидации",
description: "Проверьте правильность заполнения полей.",
placement: "topRight",
});
}
};
const handleCancel = () => {
form.resetFields();
onCancel();
};
return {
form,
modalStyle,
modalTitle,
handleOk,
handleCancel,
emailValidator,
}
};
export default usePatientFormModalUI;

View File

@ -1,12 +1,10 @@
import {Button, Col, Modal, Row, Typography, Divider} from "antd";
import PropTypes from "prop-types";
import {PatientPropType} from "../../Types/patientPropType.js";
import {PatientPropType} from "../../../../../Types/patientPropType.js";
const { Text, Title } = Typography;
const PatientViewModal = ({ visible, onCancel, patient }) => {
if (!patient) return null;
return (
<Modal
title="Просмотр пациента"
@ -73,7 +71,7 @@ const PatientViewModal = ({ visible, onCancel, patient }) => {
PatientViewModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
patient: PatientPropType.isRequired,
patient: PatientPropType,
};
export default PatientViewModal;

View File

@ -19,7 +19,7 @@ import {
TeamOutlined
} from "@ant-design/icons";
import PatientListCard from "../../Dummies/PatientListCard.jsx";
import PatientFormModal from "../../Widgets/PatientFormModal.jsx";
import PatientFormModal from "./Components/PatientFormModal/PatientFormModal.jsx";
import SelectViewMode from "../../Widgets/SelectViewMode.jsx";
import LoadingIndicator from "../../Widgets/LoadingIndicator.jsx";
import usePatients from "./usePatients.js";

View File

@ -0,0 +1,180 @@
import {Modal, Button, Form, Input, Table, InputNumber, Select, Space, Result} from "antd";
import {PlusOutlined, DeleteOutlined} from "@ant-design/icons";
import PropTypes from "prop-types";
import {SetPropType} from "../../../../../Types/setPropType.js";
import useSetFormModal from "./useSetFormModal.js";
import useSetFormModalUI from "./useSetFormModalUI.js";
const {Option} = Select;
const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
const setFormModalData = useSetFormModal(setData);
const setFormModalUI = useSetFormModalUI(visible, onCancel, setData, onSubmit, setFormModalData.setContents, setFormModalData.lensTypes);
const columns = [
{
title: "Tor",
dataIndex: "tor",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.tor}
onChange={value => setFormModalUI.updateContentItem(index, "tor", value)}
/>,
},
{
title: "Trial",
dataIndex: "trial",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.trial}
onChange={value => setFormModalUI.updateContentItem(index, "trial", value)}
/>,
},
{
title: "ESA",
dataIndex: "esa",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.esa}
onChange={value => setFormModalUI.updateContentItem(index, "esa", value)}
/>,
},
{
title: "FVC",
dataIndex: "fvc",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.fvc}
onChange={value => setFormModalUI.updateContentItem(index, "fvc", value)}
/>,
},
{
title: "Пресетная рефракция",
dataIndex: "preset_refraction",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.preset_refraction}
onChange={value => setFormModalUI.updateContentItem(index, "preset_refraction", value)}
/>,
},
{
title: "Диаметр",
dataIndex: "diameter",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.diameter}
onChange={value => setFormModalUI.updateContentItem(index, "diameter", value)}
/>,
},
{
title: "Периферийная торичность",
dataIndex: "periphery_toricity",
render: (_, record, index) => <InputNumber
step={setFormModalUI.numberInputStep}
value={record.periphery_toricity}
onChange={value => setFormModalUI.updateContentItem(index, "periphery_toricity", value)}
/>,
},
{
title: "Сторона",
dataIndex: "side",
render: (_, record, index) => <Select
value={record.side}
onChange={value => setFormModalUI.updateContentItem(index, "side", value)}
>
<Option value="левая">Левая</Option>
<Option value="правая">Правая</Option>
</Select>,
},
{
title: "Количество",
dataIndex: "count",
render: (_, record, index) => <InputNumber
min={1}
value={record.count}
onChange={value => setFormModalUI.updateContentItem(index, "count", value)}
/>,
},
{
title: "Тип",
dataIndex: "type_id",
render: (_, record, index) => (
<Select
value={record.type_id}
onChange={value => setFormModalUI.updateContentItem(index, "type_id", value)}
style={setFormModalUI.selectTypeLensFieldStyle}
defaultValue={setFormModalData.lensTypes[0]?.id || null}
>
{setFormModalData.lensTypes.map(lensType =>
<Option key={lensType.id} value={lensType.id}>{lensType.title}</Option>
)}
</Select>
),
width: 200,
minWidth: 100
},
{
title: "Действие",
dataIndex: "actions",
render: (_, __, index) => (
<Button danger icon={<DeleteOutlined/>} onClick={() => setFormModalUI.removeContentItem(index)}/>
),
minWidth: 200,
}
];
return (
<Modal
title={setFormModalUI.modalTitle}
open={visible}
onCancel={setFormModalUI.onCancelModal}
onOk={setFormModalUI.handleSubmit}
okText={"Сохранить"}
cancelText={"Отмена"}
width="90%"
style={setFormModalUI.modalStyle}
>
{setFormModalData.isError ? (
<Result
status="error"
title="Ошибка"
subTitle="Произошла ошибка в работе страницы"
/>
) : (
<>
<Form form={setFormModalUI.form} layout="vertical">
<Form.Item label="Название набора" name="title"
rules={[{required: true, message: "Введите название"}]}>
<Input/>
</Form.Item>
</Form>
<div style={setFormModalUI.tableStyle}>
<Table
dataSource={setFormModalUI.currentContent}
columns={columns}
rowKey="id"
pagination={false}
scroll={{x: "max-content", y: 300}}
locale={{emptyText: "Добавьте элементы"}}
/>
</div>
<Space style={setFormModalUI.addContentButtonSpaceStyle}>
<Button icon={<PlusOutlined/>} onClick={setFormModalUI.addContentItem}>Добавить элемент</Button>
</Space>
</>
)}
</Modal>
);
};
SetFormModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
setData: SetPropType,
}
export default SetFormModal;

View File

@ -0,0 +1,27 @@
import {useGetLensTypesQuery} from "../../../../../Api/lensTypesApi.js";
import {useGetSetContentQuery} from "../../../../../Api/setContentApi.js";
const useSetFormModal = (setData) => {
const {data: lensTypes = [], isLoading: isLoadingLensTypes, isError: isErrorLensTypes} =
useGetLensTypesQuery(undefined);
const setId = setData?.id;
const {
data: setContents = [],
isLoading: isLoadingSetContents,
isError: isErrorSetContents
} = useGetSetContentQuery(setId, {
skip: !setId,
});
return {
lensTypes,
setContents,
isLoading: isLoadingLensTypes || (setId && isLoadingSetContents),
isError: isErrorLensTypes || (setId && isErrorSetContents),
};
};
export default useSetFormModal;

View File

@ -0,0 +1,115 @@
import {Form, notification} from "antd";
import {useEffect, useState} from "react";
const useSetFormModalUI = (visible, onCancel, setData, onSubmit, content, lensTypes) => {
const [form] = Form.useForm();
const [currentContent, setCurrentContent] = useState([]);
useEffect(() => {
if (visible && setData && content?.length) {
setCurrentContent(content);
}
}, [visible, setData?.id, setData, content]);
useEffect(() => {
if (setData) {
form.setFieldsValue({title: setData.title || ""});
}
}, [setData, form]);
const numberInputStep = 0.1;
const modalTitle = setData ? "Редактирование набора" : "Создание набора";
const modalStyle = {maxWidth: 2500};
const tableStyle = {maxWidth: "100%", overflowX: "auto"};
const addContentButtonSpaceStyle = {marginTop: 101};
const selectTypeLensFieldStyle = {width: "100%"};
const addContentItem = () => {
setCurrentContent([...currentContent, {
id: Date.now(),
tor: 0,
trial: 0,
esa: 0,
fvc: 0,
preset_refraction: 0,
diameter: 0,
periphery_toricity: 0,
side: "левая",
count: 1,
type_id: lensTypes ? lensTypes[0].id : null
}]);
};
const validateContent = () => {
for (const item of content) {
if (
item.tor === null ||
item.trial === null ||
item.esa === null ||
item.fvc === null ||
item.preset_refraction === null ||
item.diameter === null ||
item.periphery_toricity === null ||
item.side === null ||
item.count === null ||
item.type_id === null
) {
notification.error({
message: "Ошибка валидации",
description: "Все поля в таблице должны быть заполнены перед сохранением.",
placement: "topRight",
});
return false;
}
}
return true;
};
const updateContentItem = (index, field, value) => {
const updated = [...currentContent];
updated[index][field] = value;
setCurrentContent(updated);
};
const removeContentItem = (index) => {
setCurrentContent(currentContent.filter((_, i) => i !== index));
};
const resetModal = () => {
form.resetFields();
setCurrentContent([]);
};
const handleSubmit = () => {
form.validateFields().then(values => {
if (!validateContent()) return;
const sanitizedContent = currentContent.map(({id, ...rest}) => rest);
onSubmit({...values}, sanitizedContent);
}).then(resetModal);
};
const onCancelModal = () => {
resetModal();
onCancel();
};
return {
form,
currentContent,
numberInputStep,
modalTitle,
modalStyle,
tableStyle,
addContentButtonSpaceStyle,
selectTypeLensFieldStyle,
addContentItem,
updateContentItem,
removeContentItem,
handleSubmit,
onCancelModal,
};
};
export default useSetFormModalUI;

View File

@ -1,7 +1,7 @@
import {FloatButton, Input, List, Result, Row, Typography} from "antd";
import {PlusOutlined, SwitcherOutlined} from "@ant-design/icons";
import SetListCard from "../../Dummies/SetListCard.jsx";
import SetFormModal from "../../Widgets/SetFormModal.jsx";
import SetFormModal from "./Components/SetFormModal/SetFormModal.jsx";
import LoadingIndicator from "../../Widgets/LoadingIndicator.jsx";
import useSets from "./useSets.js";
import useSetsUI from "./useSetsUI.js";
@ -74,6 +74,7 @@ const SetsPage = () => {
onSubmit={setsData.handleModalSetSubmit}
setData={setsUI.selectedSet}
/>
</div>
);
};

View File

@ -16,7 +16,7 @@ const useSets = () => {
selectedSet,
} = useSelector(state => state.setsUI);
const {data: sets = [], isLoading, isError} = useGetSetsQuery({
const {data: sets = [], isLoading, isError} = useGetSetsQuery(undefined, {
pollingInterval: 20000,
});
const [addSet] = useAddSetMutation();

View File

@ -1,260 +0,0 @@
import {useState, useEffect} from "react";
import {Modal, Button, Form, Input, Table, InputNumber, Select, Space, notification} from "antd";
import {PlusOutlined, DeleteOutlined} from "@ant-design/icons";
import getAllLensTypes from "../../old_api/lens_types/getAllLensTypes.js";
import {useAuth} from "../../Hooks/AuthContext.jsx";
import PropTypes from "prop-types";
import getSetContentBySetId from "../../old_api/set_content/getSetContentBySetId.js";
import {SetPropType} from "../../Types/setPropType.js";
const {Option} = Select;
const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
const {api} = useAuth();
const [form] = Form.useForm();
const [content, setContent] = useState([]);
const [lensTypes, setLensTypes] = useState([]);
useEffect(() => {
fetchLensTypes();
fetchSetContents();
}, []);
useEffect(() => {
if (setData) {
form.setFieldsValue({title: setData.title || ""});
}
fetchSetContents();
}, [setData, form]);
const fetchSetContents = async () => {
if (!setData) return;
const data = await getSetContentBySetId(api, setData.id);
setContent(data);
};
const fetchLensTypes = async () => {
const data = await getAllLensTypes(api);
setLensTypes(data);
};
const addContentItem = () => {
setContent([...content, {
id: Date.now(),
tor: 0,
trial: 0,
esa: 0,
fvc: 0,
preset_refraction: 0,
diameter: 0,
periphery_toricity: 0,
side: "левая",
count: 1,
type_id: lensTypes ? lensTypes[0].id : null
}]);
};
const validateContent = () => {
for (const item of content) {
if (
item.tor === null ||
item.trial === null ||
item.esa === null ||
item.fvc === null ||
item.preset_refraction === null ||
item.diameter === null ||
item.periphery_toricity === null ||
item.side === null ||
item.count === null ||
item.type_id === null
) {
notification.error({
message: "Ошибка валидации",
description: "Все поля в таблице должны быть заполнены перед сохранением.",
placement: "topRight",
});
return false;
}
}
return true;
};
const updateContentItem = (index, field, value) => {
const updated = [...content];
updated[index][field] = value;
setContent(updated);
};
const removeContentItem = (index) => {
setContent(content.filter((_, i) => i !== index));
};
const handleSubmit = () => {
form.validateFields().then(values => {
if (!validateContent()) return;
const sanitizedContent = content.map(({id, ...rest}) => rest);
onSubmit({...values}, sanitizedContent);
});
};
const columns = [
{
title: "Tor",
dataIndex: "tor",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.tor}
onChange={value => updateContentItem(index, "tor", value)}
/>,
},
{
title: "Trial",
dataIndex: "trial",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.trial}
onChange={value => updateContentItem(index, "trial", value)}
/>,
},
{
title: "ESA",
dataIndex: "esa",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.esa}
onChange={value => updateContentItem(index, "esa", value)}
/>,
},
{
title: "FVC",
dataIndex: "fvc",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.fvc}
onChange={value => updateContentItem(index, "fvc", value)}
/>,
},
{
title: "Пресетная рефракция",
dataIndex: "preset_refraction",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.preset_refraction}
onChange={value => updateContentItem(index, "preset_refraction", value)}
/>,
},
{
title: "Диаметр",
dataIndex: "diameter",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.diameter}
onChange={value => updateContentItem(index, "diameter", value)}
/>,
},
{
title: "Периферийная торичность",
dataIndex: "periphery_toricity",
render: (_, record, index) => <InputNumber
step={0.1}
value={record.periphery_toricity}
onChange={value => updateContentItem(index, "periphery_toricity", value)}
/>,
},
{
title: "Сторона",
dataIndex: "side",
render: (_, record, index) => <Select
value={record.side}
onChange={value => updateContentItem(index, "side", value)}
>
<Option value="левая">Левая</Option>
<Option value="правая">Правая</Option>
</Select>,
},
{
title: "Количество",
dataIndex: "count",
render: (_, record, index) => <InputNumber
min={1}
value={record.count}
onChange={value => updateContentItem(index, "count", value)}
/>,
},
{
title: "Тип",
dataIndex: "type_id",
render: (_, record, index) => (
<Select
value={record.type_id}
onChange={value => updateContentItem(index, "type_id", value)}
style={{width: "100%"}}
defaultValue={lensTypes[0]?.id || null}
>
{lensTypes.map(lensType =>
<Option key={lensType.id} value={lensType.id}>{lensType.title}</Option>
)}
</Select>
),
width: 200,
minWidth: 100
},
{
title: "Действие",
dataIndex: "actions",
render: (_, __, index) => (
<Button danger icon={<DeleteOutlined/>} onClick={() => removeContentItem(index)}/>
),
minWidth: 200,
}
];
return (
<Modal
title={setData ? "Редактировать набор" : "Создать набор"}
open={visible}
onCancel={() => {
form.resetFields();
setContent([]);
onCancel();
}}
onOk={handleSubmit}
okText="Сохранить"
cancelText={"Отмена"}
width="90vw"
style={{maxWidth: 2500}}
>
<Form form={form} layout="vertical">
<Form.Item label="Название набора" name="title" rules={[{required: true, message: "Введите название"}]}>
<Input/>
</Form.Item>
</Form>
<div style={{maxWidth: "100%", overflowX: "auto"}}>
<Table
dataSource={content}
columns={columns}
rowKey="id"
pagination={false}
scroll={{x: "max-content", y: 300}}
locale={{emptyText: "Добавьте элементы"}}
/>
</div>
<Space style={{marginTop: 10}}>
<Button icon={<PlusOutlined/>} onClick={addContentItem}>Добавить элемент</Button>
</Space>
</Modal>
);
};
SetFormModal.propTypes = {
visible: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
setData: SetPropType,
}
export default SetFormModal;

View File

@ -8,6 +8,7 @@ import setsUIReducer from './Slices/setsSlice.js';
import {setContentApi} from "../Api/setContentApi.js";
import {lensIssuesApi} from "../Api/lensIssuesApi.js";
import lensIssuesReducer from "./Slices/lensIssuesSlice.js";
import {lensTypesApi} from "../Api/lensTypesApi.js";
export const store = configureStore({
reducer: {
@ -22,6 +23,8 @@ export const store = configureStore({
[setContentApi.reducerPath]: setContentApi.reducer,
[lensTypesApi.reducerPath]: lensTypesApi.reducer,
[lensIssuesApi.reducerPath]: lensIssuesApi.reducer,
lensIssuesUI: lensIssuesReducer,
},
@ -31,9 +34,10 @@ export const store = configureStore({
lensesApi.middleware,
setsApi.middleware,
setContentApi.middleware,
lensTypesApi.middleware,
lensIssuesApi.middleware,
)
)
});
export default store;
export default store;