Files
SaaS-PDF/frontend/src/hooks/useTaskPolling.ts
Your Name d4c7195eeb feat: Implement rating prompt feature across tools
- Added a rating prompt dispatch mechanism to various tools (ChatPdf, PdfFlowchart, QrCodeGenerator, SummarizePdf, TranslatePdf, TableExtractor) to encourage user feedback after tool usage.
- Introduced a new utility for handling rating prompts, including event dispatching and current tool identification.
- Updated the ToolRating component to manage user feedback submission, including UI enhancements and state management.
- Enhanced the sitemap generation script to include new routes for pricing and blog pages.
- Removed hardcoded API key in pdf_ai_service.py for improved security.
- Added a project status report documenting current implementation against the roadmap.
- Updated translations for rating prompts in Arabic, English, and French.
- Ensured consistency in frontend route registry and backend task processing.
2026-03-10 23:52:56 +02:00

93 lines
2.7 KiB
TypeScript

import { useState, useEffect, useCallback, useRef } from 'react';
import { getTaskStatus, type TaskStatus, type TaskResult } from '@/services/api';
import { trackEvent } from '@/services/analytics';
interface UseTaskPollingOptions {
taskId: string | null;
intervalMs?: number;
onComplete?: (result: TaskResult) => void;
onError?: (error: string) => void;
}
interface UseTaskPollingReturn {
status: TaskStatus | null;
isPolling: boolean;
result: TaskResult | null;
error: string | null;
stopPolling: () => void;
}
export function useTaskPolling({
taskId,
intervalMs = 1500,
onComplete,
onError,
}: UseTaskPollingOptions): UseTaskPollingReturn {
const [status, setStatus] = useState<TaskStatus | null>(null);
const [isPolling, setIsPolling] = useState(false);
const [result, setResult] = useState<TaskResult | null>(null);
const [error, setError] = useState<string | null>(null);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const stopPolling = useCallback(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
setIsPolling(false);
}, []);
useEffect(() => {
if (!taskId) return;
setIsPolling(true);
setResult(null);
setError(null);
const poll = async () => {
try {
const taskStatus = await getTaskStatus(taskId);
setStatus(taskStatus);
if (taskStatus.state === 'SUCCESS') {
stopPolling();
const taskResult = taskStatus.result;
if (taskResult?.status === 'completed') {
setResult(taskResult);
trackEvent('task_completed', { task_id: taskId });
onComplete?.(taskResult);
} else {
const errMsg = taskResult?.error || 'Processing failed.';
setError(errMsg);
trackEvent('task_failed', { task_id: taskId, reason: 'result_failed' });
onError?.(errMsg);
}
} else if (taskStatus.state === 'FAILURE') {
stopPolling();
const errMsg = taskStatus.error || 'Task failed.';
setError(errMsg);
trackEvent('task_failed', { task_id: taskId, reason: 'state_failure' });
onError?.(errMsg);
}
} catch (err) {
stopPolling();
const errMsg = err instanceof Error ? err.message : 'Polling failed.';
setError(errMsg);
trackEvent('task_failed', { task_id: taskId, reason: 'polling_error' });
onError?.(errMsg);
}
};
// Poll immediately, then set interval
poll();
intervalRef.current = setInterval(poll, intervalMs);
return () => {
stopPolling();
};
}, [taskId, intervalMs]);
return { status, isPolling, result, error, stopPolling };
}