IO-3464 Document Edit

Signed-off-by: Allan Carr <allan@imexsystems.ca>
This commit is contained in:
Allan Carr
2025-12-18 11:22:28 -08:00
parent c675a328a8
commit dfe0afd4f3
4 changed files with 56 additions and 41 deletions

View File

@@ -97,41 +97,45 @@ export function DocumentEditorLocalComponent({ imageUrl, filename, jobid }) {
}, [triggerUpload, imageLoaded]); }, [triggerUpload, imageLoaded]);
useEffect(() => { useEffect(() => {
// Load the image from imageUrl if (!imageUrl) return;
let isCancelled = false; const controller = new AbortController();
const loadImage = async () => { const loadImage = async () => {
if (!imageUrl) return;
setImageLoaded(false); setImageLoaded(false);
setImageLoading(true); setImageLoading(true);
try { try {
const response = await axios.get(imageUrl, { responseType: "blob" }); const response = await axios.get(imageUrl, { responseType: "blob", signal: controller.signal });
if (isCancelled) return;
const blobUrl = URL.createObjectURL(response.data); const blobUrl = URL.createObjectURL(response.data);
setLoadedImageUrl((prevUrl) => { setLoadedImageUrl((prevUrl) => {
if (prevUrl) URL.revokeObjectURL(prevUrl); if (prevUrl) URL.revokeObjectURL(prevUrl);
return blobUrl; return blobUrl;
}); });
} catch (error) { } catch (error) {
if (axios.isCancel?.(error) || error.name === "CanceledError") {
// request was aborted — safe to ignore
return;
}
console.error("Failed to fetch image blob", error); console.error("Failed to fetch image blob", error);
} finally { } finally {
if (!isCancelled) { if (!controller.signal.aborted) {
setImageLoading(false); setImageLoading(false);
} }
} }
}; };
loadImage(); loadImage();
return () => { return () => {
isCancelled = true; controller.abort();
}; };
}, [imageUrl]); }, [imageUrl]);
useEffect(() => {
return () => {
if (loadedImageUrl) {
URL.revokeObjectURL(loadedImageUrl);
}
};
}, [loadedImageUrl]);
async function b64toBlob(url) { async function b64toBlob(url) {
const res = await fetch(url); const res = await fetch(url);
return await res.blob(); return await res.blob();

View File

@@ -84,45 +84,50 @@ export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
}, [triggerUpload, imageLoaded]); }, [triggerUpload, imageLoaded]);
useEffect(() => { useEffect(() => {
// When the document changes, fetch the image via axios so auth and base URL are applied if (!document?.id) return;
let isCancelled = false; const controller = new AbortController();
const loadImage = async () => { const loadImage = async () => {
if (!document || !document.id) return;
setImageLoaded(false); setImageLoaded(false);
setImageLoading(true); setImageLoading(true);
try { try {
const response = await axios.post( const response = await axios.post(
"/media/imgproxy/original", "/media/imgproxy/original",
{ documentId: document.id }, { documentId: document.id },
{ responseType: "blob" } {
responseType: "blob",
signal: controller.signal
}
); );
if (isCancelled) return;
const blobUrl = URL.createObjectURL(response.data); const blobUrl = URL.createObjectURL(response.data);
setImageUrl((prevUrl) => { setImageUrl((prevUrl) => {
if (prevUrl) URL.revokeObjectURL(prevUrl); if (prevUrl) URL.revokeObjectURL(prevUrl);
return blobUrl; return blobUrl;
}); });
} catch (error) { } 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); console.error("Failed to fetch original image blob", error);
} finally { } finally {
if (!isCancelled) { setImageLoading(false);
setImageLoading(false);
}
} }
}; };
loadImage(); loadImage();
return () => { return () => {
isCancelled = true; controller.abort();
}; };
}, [document]); }, [document]);
useEffect(() => {
return () => {
if (imageUrl) {
URL.revokeObjectURL(imageUrl);
}
};
}, [imageUrl]);
async function b64toBlob(url) { async function b64toBlob(url) {
const res = await fetch(url); const res = await fetch(url);
return await res.blob(); return await res.blob();

View File

@@ -33,6 +33,19 @@ export function DocumentEditorContainer({ setBodyshop }) {
nextFetchPolicy: "network-only" nextFetchPolicy: "network-only"
}); });
const isLocalMedia = !!dataShop?.bodyshops?.[0]?.uselocalmediaserver;
const {
loading: loadingDoc,
error: errorDoc,
data: dataDoc
} = useQuery(GET_DOCUMENT_BY_PK, {
variables: { documentId },
skip: !documentId || isLocalMedia,
fetchPolicy: "network-only",
nextFetchPolicy: "network-only"
});
useEffect(() => { useEffect(() => {
if (dataShop) setBodyshop(dataShop.bodyshops[0]); if (dataShop) setBodyshop(dataShop.bodyshops[0]);
}, [dataShop, setBodyshop]); }, [dataShop, setBodyshop]);
@@ -40,7 +53,7 @@ export function DocumentEditorContainer({ setBodyshop }) {
if (loadingShop) return <LoadingSpinner />; if (loadingShop) return <LoadingSpinner />;
if (errorShop) return <AlertComponent message={errorShop.message} type="error" />; if (errorShop) return <AlertComponent message={errorShop.message} type="error" />;
if (dataShop?.bodyshops[0]?.uselocalmediaserver) { if (isLocalMedia) {
if (imageUrl && filename && jobid) { if (imageUrl && filename && jobid) {
return ( return (
<div> <div>
@@ -52,20 +65,13 @@ export function DocumentEditorContainer({ setBodyshop }) {
} }
} }
const { loading, error, data } = useQuery(GET_DOCUMENT_BY_PK, { if (loadingDoc) return <LoadingSpinner />;
variables: { documentId }, if (errorDoc) return <AlertComponent message={errorDoc.message} type="error" />;
skip: !documentId,
fetchPolicy: "network-only",
nextFetchPolicy: "network-only"
});
if (loading) return <LoadingSpinner />; if (!dataDoc || !dataDoc.documents_by_pk) return <Result status="404" title={t("general.errors.notfound")} />;
if (error) return <AlertComponent message={error.message} type="error" />;
if (!data || !data.documents_by_pk) return <Result status="404" title={t("general.errors.notfound")} />;
return ( return (
<div> <div>
<DocumentEditor document={data ? data.documents_by_pk : null} /> <DocumentEditor document={dataDoc ? dataDoc.documents_by_pk : null} />
</div> </div>
); );
} }

View File

@@ -190,7 +190,7 @@ export function JobsDocumentsLocalGallery({
key="edit" key="edit"
onClick={() => { onClick={() => {
const newWindow = window.open( const newWindow = window.open(
`${window.location.protocol}//${window.location.host}/edit-local?imageUrl=${ `${window.location.protocol}//${window.location.host}/edit?imageUrl=${
jobMedia.images[modalState.index].fullsize jobMedia.images[modalState.index].fullsize
}&filename=${jobMedia.images[modalState.index].filename}&jobid=${job.id}`, }&filename=${jobMedia.images[modalState.index].filename}&jobid=${job.id}`,
"_blank", "_blank",