сделал основу вкладки с наборами линз, а также методы API, и компонент модального окна
This commit is contained in:
parent
b0bca54f22
commit
033776deb6
@ -2,9 +2,9 @@ import axios from "axios";
|
||||
import CONFIG from "../../core/Config.jsx";
|
||||
|
||||
|
||||
const addSetContent = async (token, set_content) => {
|
||||
const addSetContent = async (token, set_content, set_id) => {
|
||||
try {
|
||||
const response = await axios.post(`${CONFIG.BASE_URL}/set_content/`, set_content, {
|
||||
const response = await axios.post(`${CONFIG.BASE_URL}/set_content/${set_id}/`, set_content, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
|
||||
@ -2,9 +2,9 @@ import axios from "axios";
|
||||
import CONFIG from "../../core/Config.jsx";
|
||||
|
||||
|
||||
const AddSet = async (token, set) => {
|
||||
const addSet = async (token, set) => {
|
||||
try {
|
||||
const response = await axios.post(`${CONFIG.API_URL}/sets`, set, {
|
||||
const response = await axios.post(`${CONFIG.BASE_URL}/sets/`, set, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
@ -18,4 +18,4 @@ const AddSet = async (token, set) => {
|
||||
}
|
||||
};
|
||||
|
||||
export default AddSet;
|
||||
export default addSet;
|
||||
@ -1,10 +1,10 @@
|
||||
import { Card, Modal, Tooltip } from "antd";
|
||||
import {Card, Modal, Tooltip} from "antd";
|
||||
import PropTypes from "prop-types";
|
||||
import { DeleteOutlined, EditOutlined, EyeOutlined } from "@ant-design/icons";
|
||||
import { useState } from "react";
|
||||
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
|
||||
import {useState} from "react";
|
||||
import LensViewModal from "./LensViewModal.jsx";
|
||||
|
||||
const LensListCard = ({ lens, handleEditLens, handleDeleteLens }) => {
|
||||
const LensListCard = ({lens, handleEditLens, handleDeleteLens}) => {
|
||||
const [showModalInfo, setShowModalInfo] = useState(false);
|
||||
|
||||
const deleteLensConfirm = () => {
|
||||
@ -23,15 +23,15 @@ const LensListCard = ({ lens, handleEditLens, handleDeleteLens }) => {
|
||||
|
||||
const actions = [
|
||||
<Tooltip title="Просмотр линзы" key={"viewLens"}>
|
||||
<EyeOutlined onClick={handleViewLens} />
|
||||
<EyeOutlined onClick={handleViewLens}/>
|
||||
</Tooltip>,
|
||||
<Tooltip title="Редактирование линзы" key={"editLens"}>
|
||||
<EditOutlined onClick={() => handleEditLens(lens)} />
|
||||
<EditOutlined onClick={() => handleEditLens(lens)}/>
|
||||
</Tooltip>,
|
||||
<Tooltip title="Удаление линзы" key={"deleteLens"}>
|
||||
<DeleteOutlined
|
||||
onClick={deleteLensConfirm}
|
||||
style={{ color: "red" }}
|
||||
style={{color: "red"}}
|
||||
/>
|
||||
</Tooltip>,
|
||||
];
|
||||
@ -50,13 +50,11 @@ const LensListCard = ({ lens, handleEditLens, handleDeleteLens }) => {
|
||||
{lens.issued && <p><strong>✅ Линза выдана</strong></p>}
|
||||
</Card>
|
||||
|
||||
{showModalInfo && (
|
||||
<LensViewModal
|
||||
visible={showModalInfo}
|
||||
onCancel={() => setShowModalInfo(false)}
|
||||
lens={lens}
|
||||
/>
|
||||
)}
|
||||
<LensViewModal
|
||||
visible={showModalInfo}
|
||||
onCancel={() => setShowModalInfo(false)}
|
||||
lens={lens}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -61,14 +61,12 @@ const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
|
||||
{patient.email && <p><strong>✉️ Email:</strong> {patient.email}</p>}
|
||||
</Card>
|
||||
|
||||
{showModalInfo && (
|
||||
<PatientViewModal
|
||||
visible={showModalInfo}
|
||||
onCancel={() => setShowModalInfo(false)}
|
||||
patient={patient}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<PatientViewModal
|
||||
visible={showModalInfo}
|
||||
onCancel={() => setShowModalInfo(false)}
|
||||
patient={patient}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
257
web-app/src/components/sets/SetFormModal.jsx
Normal file
257
web-app/src/components/sets/SetFormModal.jsx
Normal file
@ -0,0 +1,257 @@
|
||||
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 axios from "axios";
|
||||
import getAllLensTypes from "../../api/lens_types/GetAllLensTypes.jsx";
|
||||
import {useAuth} from "../../AuthContext.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
import getSetContentBySetId from "../../api/set_content/GetSetContentBySetId.jsx";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
const SetFormModal = ({visible, onCancel, setData, onSubmit}) => {
|
||||
const {user} = 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;
|
||||
|
||||
try {
|
||||
const data = await getSetContentBySetId(user.token, setData.id);
|
||||
setContent(data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
notification.error({
|
||||
message: "Ошибка загрузки контента",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const fetchLensTypes = async () => {
|
||||
try {
|
||||
const data = await getAllLensTypes(user.token);
|
||||
setLensTypes(data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
notification.error({
|
||||
message: "Ошибка загрузки типов линз",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const addContentItem = () => {
|
||||
setContent([...content, {
|
||||
id: Date.now(),
|
||||
tor: 0,
|
||||
trial: 0,
|
||||
esa: 0,
|
||||
fvc: 0,
|
||||
preset_refraction: 0,
|
||||
diameter: 0,
|
||||
periphery_toricity: 0,
|
||||
side: "left",
|
||||
count: 1,
|
||||
type_id: null
|
||||
}]);
|
||||
};
|
||||
|
||||
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 => {
|
||||
onSubmit({...values, contents: content});
|
||||
});
|
||||
};
|
||||
|
||||
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="left">Левая</Option>
|
||||
<Option value="right">Правая</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: PropTypes.shape({
|
||||
id: PropTypes.number,
|
||||
title: PropTypes.string,
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
export default SetFormModal;
|
||||
@ -0,0 +1,62 @@
|
||||
import PropTypes from "prop-types";
|
||||
import {Card, Modal, Tooltip} from "antd";
|
||||
import {DeleteOutlined, EditOutlined, PlusOutlined} from "@ant-design/icons";
|
||||
|
||||
const SetListCard = ({set, handleEditSet, handleAddSet, handleDeleteSet}) => {
|
||||
|
||||
const confirmSetDelete = () => {
|
||||
Modal.confirm({
|
||||
title: "Удаление набора",
|
||||
content: `Вы уверены, что хотите удалить набор ${set.title}?`,
|
||||
okText: "Да, удалить",
|
||||
cancelText: "Отмена",
|
||||
onOk: () => handleDeleteSet(set.id),
|
||||
});
|
||||
};
|
||||
|
||||
const actions = [
|
||||
<Tooltip title="Добавить набор" key={"add"}>
|
||||
<PlusOutlined
|
||||
onClick={handleAddSet}
|
||||
/>
|
||||
</Tooltip>,
|
||||
|
||||
<Tooltip title="Редактирование набора" key={"edit"}>
|
||||
<EditOutlined
|
||||
onClick={() => {
|
||||
handleEditSet(set);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>,
|
||||
|
||||
<Tooltip title="Удаление набора" key={"delete"}>
|
||||
<DeleteOutlined
|
||||
style={{color: "red"}}
|
||||
onClick={confirmSetDelete}
|
||||
/>
|
||||
</Tooltip>,
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card
|
||||
type="inner"
|
||||
title={set.title}
|
||||
actions={actions}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
SetListCard.propTypes = {
|
||||
set: PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
handleEditSet: PropTypes.func.isRequired,
|
||||
handleAddSet: PropTypes.func.isRequired,
|
||||
handleDeleteSet: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
export default SetListCard;
|
||||
@ -1,21 +1,10 @@
|
||||
import {useState, useEffect} from "react";
|
||||
import {
|
||||
Input,
|
||||
Select,
|
||||
List,
|
||||
FloatButton,
|
||||
Row,
|
||||
Col,
|
||||
Spin,
|
||||
Button,
|
||||
Form,
|
||||
InputNumber,
|
||||
Card, Grid, notification, Tabs
|
||||
Tabs
|
||||
} from "antd";
|
||||
import LensesPage from "../pages/LensesPage.jsx";
|
||||
import {FolderViewOutlined, SwitcherOutlined} from "@ant-design/icons";
|
||||
import SetLensesPage from "../pages/SetLensesPage.jsx";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
const items = [
|
||||
{
|
||||
@ -27,7 +16,7 @@ const items = [
|
||||
{
|
||||
key: '2',
|
||||
label: 'Наборы линз',
|
||||
children: '1233',
|
||||
children: <SetLensesPage/>,
|
||||
icon: <SwitcherOutlined/>
|
||||
}
|
||||
]
|
||||
|
||||
@ -124,11 +124,9 @@ const LensesPage = () => {
|
||||
};
|
||||
|
||||
const handleDeleteLens = async (lensId) => {
|
||||
if (!user || !user.token) return;
|
||||
|
||||
try {
|
||||
await deleteLens(user.token, lensId);
|
||||
fetchLenses(user.token);
|
||||
await fetchLenses(user.token);
|
||||
notification.success({
|
||||
message: "Линза удалена",
|
||||
description: "Линза успешно удалена.",
|
||||
@ -215,7 +213,6 @@ const LensesPage = () => {
|
||||
boxShadow: "0 1px 6px rgba(0, 0, 0, 0.15)",
|
||||
borderRadius: 8
|
||||
}}
|
||||
type={"inner"}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={12}>
|
||||
|
||||
@ -96,8 +96,6 @@ const PatientsPage = () => {
|
||||
};
|
||||
|
||||
const handleDeletePatient = async (patient_id) => {
|
||||
if (!user || !user.token) return;
|
||||
|
||||
try {
|
||||
await deletePatient(user.token, patient_id);
|
||||
await fetchPatients();
|
||||
@ -123,19 +121,9 @@ const PatientsPage = () => {
|
||||
const handleModalPatientSubmit = async (newPatient) => {
|
||||
try {
|
||||
if (selectedPatient) {
|
||||
await updatePatient(user.token, selectedPatient.id, newPatient);
|
||||
notification.success({
|
||||
message: "Пациент обновлён",
|
||||
description: `Данные пациента ${newPatient.first_name} ${newPatient.last_name} успешно обновлены.`,
|
||||
placement: "topRight",
|
||||
});
|
||||
await editPatient(newPatient);
|
||||
} else {
|
||||
await addPatient(user.token, newPatient);
|
||||
notification.success({
|
||||
message: "Пациент добавлен",
|
||||
description: `Пациент ${newPatient.first_name} ${newPatient.last_name} успешно добавлен.`,
|
||||
placement: "topRight",
|
||||
});
|
||||
await addPatient(newPatient);
|
||||
}
|
||||
setIsModalVisible(false);
|
||||
await fetchPatients();
|
||||
@ -150,6 +138,24 @@ const PatientsPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const editPatient = async (patient) => {
|
||||
await updatePatient(user.token, selectedPatient.id, patient);
|
||||
notification.success({
|
||||
message: "Пациент обновлён",
|
||||
description: `Данные пациента ${patient.first_name} ${patient.last_name} успешно обновлены.`,
|
||||
placement: "topRight",
|
||||
});
|
||||
};
|
||||
|
||||
const addPatient = async (patient) => {
|
||||
await addPatient(user.token, patient);
|
||||
notification.success({
|
||||
message: "Пациент добавлен",
|
||||
description: `Пациент ${patient.first_name} ${patient.last_name} успешно добавлен.`,
|
||||
placement: "topRight",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{padding: 20}}>
|
||||
<Row gutter={[16, 16]} style={{marginBottom: 20}}>
|
||||
|
||||
@ -1,8 +1,239 @@
|
||||
|
||||
import {useAuth} from "../AuthContext.jsx";
|
||||
import {useEffect, useState} from "react";
|
||||
import {Col, FloatButton, Input, List, notification, Row, Select, Spin, Tooltip} from "antd";
|
||||
import getAllSets from "../api/sets/GetAllSets.jsx";
|
||||
import {LoadingOutlined, PlusOutlined} from "@ant-design/icons";
|
||||
import SetListCard from "../components/sets/SetListCard.jsx";
|
||||
import SetFormModal from "../components/sets/SetFormModal.jsx";
|
||||
import updateSet from "../api/sets/UpdateSet.jsx";
|
||||
import addSet from "../api/sets/AddSet.jsx";
|
||||
import deleteSet from "../api/sets/DeleteSet.jsx";
|
||||
import addSetContent from "../api/set_content/AddSetContent.jsx";
|
||||
|
||||
|
||||
const SetLensesPage = () => {
|
||||
const {user} = useAuth();
|
||||
|
||||
const [current, setCurrent] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [sets, setSets] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [selectedSet, setSelectedSet] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSetsWithCache();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isModalVisible) {
|
||||
const intervalId = setInterval(fetchSets, 5000);
|
||||
return () => clearInterval(intervalId);
|
||||
}
|
||||
}, [user, isModalVisible]);
|
||||
|
||||
const fetchSetsWithCache = async () => {
|
||||
const cachedData = localStorage.getItem("setsData");
|
||||
const cacheTimestamp = localStorage.getItem("setsTimestamp");
|
||||
|
||||
if (cachedData && cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 60 * 1000) {
|
||||
setSets(JSON.parse(cachedData));
|
||||
setLoading(false);
|
||||
} else {
|
||||
await fetchSets();
|
||||
}
|
||||
};
|
||||
|
||||
const fetchSets = async () => {
|
||||
if (!user || !user.token) return;
|
||||
|
||||
try {
|
||||
const data = await getAllSets(user.token);
|
||||
setSets(data);
|
||||
|
||||
localStorage.setItem("setsData", JSON.stringify(data));
|
||||
localStorage.setItem("setsTimestamp", Date.now().toString());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
notification.error({
|
||||
message: "Ошибка загрузки данных",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
})
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const filteredSets = sets.filter(set => set.title.toLowerCase().includes(searchText.toLowerCase()));
|
||||
|
||||
const handleAddSet = () => {
|
||||
setSelectedSet(null);
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const handleEditSet = (set) => {
|
||||
setSelectedSet(set);
|
||||
setIsModalVisible(true);
|
||||
}
|
||||
|
||||
const handleDeleteSet = async (set_id) => {
|
||||
try {
|
||||
await deleteSet(user.token, set_id);
|
||||
notification.success({
|
||||
message: "Набор удален",
|
||||
description: "Набор успешно удален.",
|
||||
placement: "topRight",
|
||||
});
|
||||
await fetchSets();
|
||||
} catch (error) {
|
||||
console.error("Ошибка удаления набора:", error);
|
||||
notification.error({
|
||||
message: "Ошибка удаления набора",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
setIsModalVisible(false);
|
||||
};
|
||||
|
||||
const handleModalSetSubmit = async (set, content = []) => {
|
||||
try {
|
||||
let refreshed_set;
|
||||
|
||||
if (selectedSet) {
|
||||
refreshed_set = await editCurrentSet(set);
|
||||
} else {
|
||||
refreshed_set = await addNewSet(set);
|
||||
}
|
||||
|
||||
if (refreshed_set) {
|
||||
await setContent(content, refreshed_set.id);
|
||||
}
|
||||
|
||||
setIsModalVisible(false);
|
||||
await fetchSets();
|
||||
} catch (error) {
|
||||
console.error("Ошибка сохранения набора:", error);
|
||||
notification.error({
|
||||
message: "Ошибка сохранения набора",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const setContent = async (content, set_id) => {
|
||||
try {
|
||||
await addSetContent(user.token, content, set_id);
|
||||
} catch (error) {
|
||||
console.error("Ошибка сохранения набора:", error);
|
||||
notification.error({
|
||||
message: "Ошибка сохранения набора",
|
||||
description: "Проверьте подключение к сети.",
|
||||
placement: "topRight",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const editCurrentSet = async (set) => {
|
||||
const refreshed_set = await updateSet(user.token, selectedSet.id, set);
|
||||
notification.success({
|
||||
message: "Набор обновлен",
|
||||
description: "Набор успешно обновлен.",
|
||||
placement: "topRight",
|
||||
});
|
||||
return refreshed_set;
|
||||
};
|
||||
|
||||
const addNewSet = async (set) => {
|
||||
const refreshed_set = await addSet(user.token, set);
|
||||
notification.success({
|
||||
message: "Набор добавлен",
|
||||
description: "Набор успешно добавлен.",
|
||||
placement: "topRight",
|
||||
});
|
||||
return refreshed_set;
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{padding: 20}}>
|
||||
<Row style={{marginBottom: 20}}>
|
||||
<Input
|
||||
placeholder="Поиск набора"
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
style={{width: "100%"}}
|
||||
allowClear
|
||||
/>
|
||||
</Row>
|
||||
|
||||
{loading ? (
|
||||
<div style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
}}>
|
||||
<Spin indicator={<LoadingOutlined style={{fontSize: 64, color: "#1890ff"}} spin/>}/>
|
||||
</div>
|
||||
) : (
|
||||
<List
|
||||
grid={{
|
||||
gutter: 16,
|
||||
xs: 1,
|
||||
sm: 1,
|
||||
md: 2,
|
||||
lg: 2,
|
||||
xl: 3,
|
||||
xxl: 3,
|
||||
}}
|
||||
dataSource={filteredSets}
|
||||
renderItem={(set) => (
|
||||
<List.Item>
|
||||
<SetListCard
|
||||
set={set}
|
||||
handleEditSet={handleEditSet}
|
||||
handleAddSet={handleAddSet}
|
||||
handleDeleteSet={handleDeleteSet}
|
||||
/>
|
||||
</List.Item>
|
||||
)}
|
||||
pagination={{
|
||||
current,
|
||||
pageSize,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["5", "10", "20", "50"],
|
||||
onChange: (page, newPageSize) => {
|
||||
setCurrent(page);
|
||||
setPageSize(newPageSize);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FloatButton
|
||||
icon={<PlusOutlined/>}
|
||||
type="primary"
|
||||
style={{position: "fixed", bottom: 40, right: 40}}
|
||||
tooltip="Добавить набор"
|
||||
onClick={handleAddSet}
|
||||
/>
|
||||
|
||||
<SetFormModal
|
||||
visible={isModalVisible}
|
||||
onCancel={handleCancel}
|
||||
onSubmit={handleModalSetSubmit}
|
||||
setData={selectedSet}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SetLensesPage;
|
||||
Loading…
x
Reference in New Issue
Block a user