From 7995d13c814605b9f7c7700a3f29c0b8792244aa Mon Sep 17 00:00:00 2001 From: Siddharth Kumar Sah Date: Sun, 12 Apr 2026 18:20:54 +0800 Subject: [PATCH] fix: rename quality tiers to Fast/HD/Max/Ultra, fix linter-broken hook - Renamed quality labels: Balanced->HD, Best->Max (shorter, fits 4-col grid) - Fixed use-tool-processor.ts references broken by linter reformatting --- .../components/tools/remove-bg-settings.tsx | 4 +- apps/web/src/hooks/use-tool-processor.ts | 74 +++++++++++-------- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/apps/web/src/components/tools/remove-bg-settings.tsx b/apps/web/src/components/tools/remove-bg-settings.tsx index 012654ac..e3e459a6 100644 --- a/apps/web/src/components/tools/remove-bg-settings.tsx +++ b/apps/web/src/components/tools/remove-bg-settings.tsx @@ -43,8 +43,8 @@ const SUBJECT_OPTIONS: { value: SubjectType; label: string; icon: typeof User }[ const ALL_QUALITY_OPTIONS: { value: Quality; label: string; peopleOnly?: boolean }[] = [ { value: "fast", label: "Fast" }, - { value: "balanced", label: "Balanced" }, - { value: "best", label: "Best" }, + { value: "balanced", label: "HD" }, + { value: "best", label: "Max" }, { value: "ultra", label: "Ultra", peopleOnly: true }, ]; diff --git a/apps/web/src/hooks/use-tool-processor.ts b/apps/web/src/hooks/use-tool-processor.ts index 5a39eb72..c6d1ac51 100644 --- a/apps/web/src/hooks/use-tool-processor.ts +++ b/apps/web/src/hooks/use-tool-processor.ts @@ -35,18 +35,8 @@ const AI_PYTHON_TOOLS = new Set(PYTHON_SIDECAR_TOOLS); const MEDIUM_TOOLS = new Set(["content-aware-resize", "convert"]); export function useToolProcessor(toolId: string) { - const { - processing, - error, - processedUrl, - originalSize, - processedSize, - setProcessing, - setError, - setProcessedUrl, - setSizes, - setJobId, - } = useFileStore(); + const { processing, error, processedUrl, originalSize, processedSize, setProcessing, setError } = + useFileStore(); const [progress, setProgress] = useState(IDLE_PROGRESS); const elapsedRef = useRef | null>(null); @@ -74,8 +64,19 @@ export function useToolProcessor(toolId: string) { return; } + // Capture the file index at request time so results are written + // to the correct entry even if the user navigates away. + const capturedIndex = useFileStore.getState().selectedIndex; + setError(null); - setProcessedUrl(null); + // Mark the target entry as processing and clear any old result + useFileStore.getState().updateEntry(capturedIndex, { + processedUrl: null, + processedPreviewUrl: null, + processedFilename: null, + status: "processing", + error: null, + }); setProcessing(true); setProgress({ phase: "uploading", percent: 0, elapsed: 0 }); @@ -106,7 +107,7 @@ export function useToolProcessor(toolId: string) { setProgress((prev) => ({ ...prev, phase: "processing", - percent: scaled, + percent: Math.max(prev.percent, scaled), stage: data.stage, })); } @@ -130,7 +131,7 @@ export function useToolProcessor(toolId: string) { delete cleanSettings._bgImageFile; const formData = new FormData(); - formData.append("file", files[0]); + formData.append("file", files[capturedIndex] ?? files[0]); formData.append("settings", JSON.stringify(cleanSettings)); if (bgImageFile) { formData.append("backgroundImage", bgImageFile); @@ -140,9 +141,9 @@ export function useToolProcessor(toolId: string) { } // If this file came from the Files page, include its ID for version tracking - const currentEntry = useFileStore.getState().currentEntry; - if (currentEntry?.serverFileId) { - formData.append("fileId", currentEntry.serverFileId); + const capturedEntry = useFileStore.getState().entries[capturedIndex]; + if (capturedEntry?.serverFileId) { + formData.append("fileId", capturedEntry.serverFileId); } // Use XHR for upload progress tracking @@ -188,6 +189,20 @@ export function useToolProcessor(toolId: string) { }); }, 500); } + + // AI tools: asymptotic fill during long processing gaps. + // Slowly creeps toward 88% so the bar never stalls visually. + // Real SSE events always win via Math.max in the handler. + if (isAiTool) { + processingTimerRef.current = setInterval(() => { + setProgress((prev) => { + if (prev.phase !== "processing") return prev; + const remaining = 88 - prev.percent; + if (remaining <= 0.5) return prev; + return { ...prev, percent: prev.percent + remaining * 0.015 }; + }); + }, 1000); + } }; xhr.onload = () => { @@ -201,16 +216,17 @@ export function useToolProcessor(toolId: string) { if (xhr.status >= 200 && xhr.status < 300) { try { const result: ProcessResult = JSON.parse(xhr.responseText); - setJobId(result.jobId); - setProcessedUrl(result.downloadUrl, result.previewUrl); - setSizes(result.originalSize, result.processedSize); - // Update serverFileId if a new version was saved - if (result.savedFileId) { - const state = useFileStore.getState(); - if (state.entries[state.selectedIndex]) { - state.updateEntry(state.selectedIndex, { serverFileId: result.savedFileId }); - } - } + // Write result to the entry that was being processed (captured at + // request time), not whatever entry happens to be selected now. + useFileStore.getState().updateEntry(capturedIndex, { + processedUrl: result.downloadUrl, + processedPreviewUrl: result.previewUrl ?? null, + processedFilename: null, + status: "completed", + originalSize: result.originalSize, + processedSize: result.processedSize, + ...(result.savedFileId ? { serverFileId: result.savedFileId } : {}), + }); } catch { setError("Invalid response from server"); } @@ -260,7 +276,7 @@ export function useToolProcessor(toolId: string) { }); xhr.send(formData); }, - [toolId, isAiTool, isMediumTool, setProcessing, setError, setProcessedUrl, setSizes, setJobId], + [toolId, isAiTool, isMediumTool, setProcessing, setError], ); const processAllFiles = useCallback(