From dd974e013eb852b9cd21eba8c5fe75321bc1b950 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Fri, 19 Dec 2025 10:51:43 -0500 Subject: [PATCH 1/2] fix devtool error --- frontends/api/src/hooks/articles/index.ts | 31 +++++++++++++++---- .../components/TiptapEditor/ArticleEditor.tsx | 11 +++---- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/frontends/api/src/hooks/articles/index.ts b/frontends/api/src/hooks/articles/index.ts index b25e4eceac..a21a91ee75 100644 --- a/frontends/api/src/hooks/articles/index.ts +++ b/frontends/api/src/hooks/articles/index.ts @@ -1,3 +1,4 @@ +import { useRef } from "react" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import type { AxiosProgressEvent } from "axios" @@ -51,19 +52,37 @@ const useArticleCreate = () => { } export const useMediaUpload = () => { - return useMutation({ - mutationFn: async (data: { - file: File - onUploadProgress?: (progressEvent: AxiosProgressEvent) => void - }) => { + const nextProgressCb = useRef<((percent: number) => void) | undefined>( + undefined, + ) + + const mutation = useMutation({ + mutationFn: async (data: { file: File }) => { const response = await mediaApi.mediaUpload( { image_file: data.file }, - { onUploadProgress: data.onUploadProgress }, + { + onUploadProgress: (e: AxiosProgressEvent) => { + const percent = Math.round((e.loaded * 100) / (e.total ?? 1)) + nextProgressCb.current?.(percent) + }, + }, ) return response.data }, + onSettled: () => { + nextProgressCb.current = undefined + }, }) + + return { + ...mutation, + setNextProgressCallback: ( + callback: ((percent: number) => void) | undefined, + ) => { + nextProgressCb.current = callback + }, + } } const useArticleDestroy = () => { diff --git a/frontends/ol-components/src/components/TiptapEditor/ArticleEditor.tsx b/frontends/ol-components/src/components/TiptapEditor/ArticleEditor.tsx index 07c3493f30..6e1f3eca56 100644 --- a/frontends/ol-components/src/components/TiptapEditor/ArticleEditor.tsx +++ b/frontends/ol-components/src/components/TiptapEditor/ArticleEditor.tsx @@ -190,13 +190,10 @@ const ArticleEditor = ({ onSave, readOnly, article }: ArticleEditorProps) => { file, async (file: File, progressCb?: (percent: number) => void) => { try { - const response = await uploadImage.mutateAsync({ - file, - onUploadProgress: (e) => { - const percent = Math.round((e.loaded * 100) / (e.total ?? 1)) - progressCb?.(percent) - }, - }) + uploadImage.setNextProgressCallback(progressCb) + + const response = await uploadImage.mutateAsync({ file }) + if (!response?.url) throw new Error("Upload failed") return response.url } catch (error) { From 90d7f2e31027f8a3d44d04ccb4b8968cf9874728 Mon Sep 17 00:00:00 2001 From: Chris Chudzicki Date: Fri, 19 Dec 2025 11:03:28 -0500 Subject: [PATCH 2/2] add a note --- frontends/api/src/hooks/articles/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontends/api/src/hooks/articles/index.ts b/frontends/api/src/hooks/articles/index.ts index a21a91ee75..0dad69ddb8 100644 --- a/frontends/api/src/hooks/articles/index.ts +++ b/frontends/api/src/hooks/articles/index.ts @@ -77,6 +77,15 @@ export const useMediaUpload = () => { return { ...mutation, + /** + * Set a callback to be called on the next upload progress event. + * + * NOTES: + * - This callback will be cleared after the mutation settles (either success or error). + * - This is a separate method, not part of the mutate/mutateAsync options, + * to avoid errors with function serialization. (E.g., Tanstack Query + * devtools attempt to serialize mutation options.) + */ setNextProgressCallback: ( callback: ((percent: number) => void) | undefined, ) => {