From 4d174f50215460767dbbe981b262e8c6352910fa Mon Sep 17 00:00:00 2001 From: andrei Date: Tue, 3 Jun 2025 23:18:17 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20compressorjs=20=D0=B8=20react-dropzone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-app/package-lock.json | 74 +++++++++++++++++++ web-app/package.json | 2 + .../useAppointmentFormModalUI.js | 68 +++++++---------- 3 files changed, 104 insertions(+), 40 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 0504126..c428b5e 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -17,6 +17,7 @@ "antd-mask-input": "^2.0.7", "axios": "^1.7.9", "chart.js": "^4.4.9", + "compressorjs": "^1.2.1", "dayjs": "^1.11.13", "jodit-react": "^5.2.19", "lodash": "^4.17.21", @@ -24,6 +25,7 @@ "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", + "react-dropzone": "^14.3.8", "react-redux": "^9.2.0", "react-router-dom": "^7.1.1", "validator": "^13.12.0" @@ -1897,6 +1899,15 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/autobind-decorator": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-2.4.0.tgz", @@ -1941,6 +1952,12 @@ "dev": true, "license": "MIT" }, + "node_modules/blueimp-canvas-to-blob": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz", + "integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2078,6 +2095,16 @@ "node": ">= 0.8" } }, + "node_modules/compressorjs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.2.1.tgz", + "integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==", + "license": "MIT", + "dependencies": { + "blueimp-canvas-to-blob": "^3.29.0", + "is-blob": "^2.1.0" + } + }, "node_modules/compute-scroll-into-view": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", @@ -2774,6 +2801,18 @@ "node": ">=16.0.0" } }, + "node_modules/file-selector": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "license": "MIT", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3244,6 +3283,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-blob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -4789,6 +4840,23 @@ "react": "^18.3.1" } }, + "node_modules/react-dropzone": { + "version": "14.3.8", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz", + "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -5437,6 +5505,12 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/web-app/package.json b/web-app/package.json index 9820eef..a2df22d 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -19,6 +19,7 @@ "antd-mask-input": "^2.0.7", "axios": "^1.7.9", "chart.js": "^4.4.9", + "compressorjs": "^1.2.1", "dayjs": "^1.11.13", "jodit-react": "^5.2.19", "lodash": "^4.17.21", @@ -26,6 +27,7 @@ "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", + "react-dropzone": "^14.3.8", "react-redux": "^9.2.0", "react-router-dom": "^7.1.1", "validator": "^13.12.0" diff --git a/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js b/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js index cae22a0..17ce983 100644 --- a/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js +++ b/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js @@ -5,6 +5,8 @@ import {useEffect, useMemo, useRef, useState} from "react"; import dayjs from "dayjs"; import {useGetAppointmentsQuery} from "../../../Api/appointmentsApi.js"; import {Grid} from "antd"; +import {useUploadAppointmentFileMutation} from "../../../Api/appointmentFilesApi.js"; +import Compressor from 'compressorjs'; // Импортируем Compressor const {useBreakpoint} = Grid; @@ -23,8 +25,11 @@ const useAppointmentFormModalUI = (createAppointment, patients, cancelAppointmen const [formValues, setFormValues] = useState({}); const [isDrawerVisible, setIsDrawerVisible] = useState(false); const [searchPreviousAppointments, setSearchPreviousAppointments] = useState(""); + const [draftFiles, setDraftFiles] = useState([]); const editorRef = useRef(null); + const [uploadAppointmentFile] = useUploadAppointmentFileMutation(); + const {data: appointments = []} = useGetAppointmentsQuery(userData.id, { pollingInterval: 20000, }); @@ -56,46 +61,14 @@ const useAppointmentFormModalUI = (createAppointment, patients, cancelAppointmen height: 150, toolbarAdaptive: false, buttons: [ - "bold", - "italic", - "underline", - "strikethrough", - "|", - "superscript", - "subscript", - "|", - "ul", - "ol", - "outdent", - "indent", - "|", - "font", - "fontsize", - "brush", - "paragraph", - "|", - "align", - "hr", - "|", - "table", - "link", - "image", - "video", - "symbols", - "|", - "undo", - "redo", - "cut", - "copy", - "paste", - "selectall", - "eraser", - "|", - "find", - "source", - "fullsize", - "print", - "preview", + "bold", "italic", "underline", "strikethrough", "|", + "superscript", "subscript", "|", + "ul", "ol", "outdent", "indent", "|", + "font", "fontsize", "brush", "paragraph", "|", + "align", "hr", "|", + "table", "link", "image", "video", "symbols", "|", + "undo", "redo", "cut", "copy", "paste", "selectall", "eraser", "|", + "find", "source", "fullsize", "print", "preview", ], autofocus: false, preserveSelection: true, @@ -128,6 +101,21 @@ const useAppointmentFormModalUI = (createAppointment, patients, cancelAppointmen video: { allowedSources: ["youtube", "vimeo"], }, + uploader: { + insertImageAsBase64URI: true, + }, + paste: { + insertAsBase64: true, + mimeTypes: ["image/png", "image/jpeg", "image/gif"], + maxFileSize: 5 * 1024 * 1024, // 5MB + error: () => { + notification.error({ + message: "Ошибка вставки", + description: "Файл слишком большой или неподдерживаемый формат.", + placement: "topRight", + }); + }, + }, }), [] );