//import "tui-image-editor/dist/tui-image-editor.css"; import axios from "axios"; import { Result } from "antd"; import * as markerjs2 from "markerjs2"; import { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import { handleUpload } from "../documents-upload-imgproxy/documents-upload-imgproxy.utility.js"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, bodyshop: selectBodyshop }); const mapDispatchToProps = () => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); export function DocumentEditorComponent({ currentUser, bodyshop, document }) { const imgRef = useRef(null); const [loading, setLoading] = useState(false); const [uploaded, setuploaded] = useState(false); const [imageUrl, setImageUrl] = useState(null); const [imageLoaded, setImageLoaded] = useState(false); const [imageLoading, setImageLoading] = useState(true); const markerArea = useRef(null); const { t } = useTranslation(); const notification = useNotification(); const triggerUpload = useCallback( async (dataUrl) => { setLoading(true); handleUpload( { filename: `${document.key.split("/").pop()}-${Date.now()}.jpg`, file: await b64toBlob(dataUrl), onSuccess: () => { setLoading(false); setuploaded(true); }, onError: () => setLoading(false) }, { bodyshop: bodyshop, uploaded_by: currentUser.email, jobId: document.jobid, //billId: billId, tagsArray: ["edited"] //callback: callbackAfterUpload, }, notification ); }, [bodyshop, currentUser, document, notification] ); useEffect(() => { if (imgRef.current !== null && imageLoaded && !markerArea.current) { // create a marker.js MarkerArea markerArea.current = new markerjs2.MarkerArea(imgRef.current); // attach an event handler to assign annotated image back to our image element markerArea.current.addEventListener("close", () => { // NO OP }); markerArea.current.addEventListener("render", (event) => { const dataUrl = event.dataUrl; imgRef.current.src = dataUrl; markerArea.current.close(); triggerUpload(dataUrl); }); // launch marker.js markerArea.current.renderAtNaturalSize = true; markerArea.current.renderImageType = "image/jpeg"; markerArea.current.renderImageQuality = 1; //markerArea.current.settings.displayMode = "inline"; markerArea.current.show(); } }, [triggerUpload, imageLoaded]); useEffect(() => { if (!document?.id) return; const controller = new AbortController(); const loadImage = async () => { setImageLoaded(false); setImageLoading(true); try { const response = await axios.post( "/media/imgproxy/original", { documentId: document.id }, { responseType: "blob", signal: controller.signal } ); const blobUrl = URL.createObjectURL(response.data); setImageUrl((prevUrl) => { if (prevUrl) URL.revokeObjectURL(prevUrl); return blobUrl; }); } catch (error) { if (axios.isCancel?.(error) || error.name === "CanceledError") { // request was aborted — safe to ignore return; } console.error("Failed to fetch original image blob", error); } finally { setImageLoading(false); } }; loadImage(); return () => { controller.abort(); }; }, [document]); useEffect(() => { return () => { if (imageUrl) { URL.revokeObjectURL(imageUrl); } }; }, [imageUrl]); async function b64toBlob(url) { const res = await fetch(url); return await res.blob(); } return (