159 lines
4.1 KiB
TypeScript
159 lines
4.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
import type {
|
|
ReviewIQAnalyticsResponse,
|
|
ReviewIQFilters,
|
|
} from '@/components/reviewiq/types';
|
|
|
|
interface UseReviewIQAnalyticsOptions {
|
|
jobId?: string | null;
|
|
businessId?: string | null;
|
|
filters: ReviewIQFilters;
|
|
issuesPage?: number;
|
|
issuesPageSize?: number;
|
|
spansPage?: number;
|
|
spansPageSize?: number;
|
|
}
|
|
|
|
interface UseReviewIQAnalyticsResult {
|
|
data: ReviewIQAnalyticsResponse | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refetch: () => void;
|
|
}
|
|
|
|
/**
|
|
* Custom hook for fetching ReviewIQ analytics data.
|
|
* Uses a single API call to fetch all dashboard data.
|
|
*/
|
|
export function useReviewIQAnalytics({
|
|
jobId,
|
|
businessId,
|
|
filters,
|
|
issuesPage = 1,
|
|
issuesPageSize = 10,
|
|
spansPage = 1,
|
|
spansPageSize = 10,
|
|
}: UseReviewIQAnalyticsOptions): UseReviewIQAnalyticsResult {
|
|
const [data, setData] = useState<ReviewIQAnalyticsResponse | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [refetchTrigger, setRefetchTrigger] = useState(0);
|
|
|
|
// Build query params from filters
|
|
const queryParams = useMemo(() => {
|
|
const params = new URLSearchParams();
|
|
|
|
if (jobId) {
|
|
params.set('job_id', jobId);
|
|
}
|
|
if (businessId) {
|
|
params.set('business_id', businessId);
|
|
}
|
|
|
|
params.set('time_range', filters.timeRange);
|
|
|
|
if (filters.sentiment.length > 0) {
|
|
params.set('sentiment', filters.sentiment.join(','));
|
|
}
|
|
|
|
if (filters.urtDomain) {
|
|
params.set('urt_domain', filters.urtDomain);
|
|
}
|
|
|
|
if (filters.intensity.length > 0) {
|
|
params.set('intensity', filters.intensity.join(','));
|
|
}
|
|
|
|
params.set('issues_page', issuesPage.toString());
|
|
params.set('issues_page_size', issuesPageSize.toString());
|
|
params.set('spans_page', spansPage.toString());
|
|
params.set('spans_page_size', spansPageSize.toString());
|
|
|
|
return params.toString();
|
|
}, [jobId, businessId, filters, issuesPage, issuesPageSize, spansPage, spansPageSize]);
|
|
|
|
const fetchData = useCallback(async () => {
|
|
if (!jobId && !businessId) {
|
|
setLoading(false);
|
|
setData(null);
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await fetch(`/api/pipelines/reviewiq/analytics?${queryParams}`);
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(errorData.detail || `HTTP error ${response.status}`);
|
|
}
|
|
|
|
const responseData: ReviewIQAnalyticsResponse = await response.json();
|
|
setData(responseData);
|
|
} catch (err) {
|
|
console.error('Failed to fetch ReviewIQ analytics:', err);
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch analytics');
|
|
setData(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [queryParams, jobId, businessId]);
|
|
|
|
// Fetch data when params change
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, [fetchData, refetchTrigger]);
|
|
|
|
const refetch = useCallback(() => {
|
|
setRefetchTrigger((prev) => prev + 1);
|
|
}, []);
|
|
|
|
return { data, loading, error, refetch };
|
|
}
|
|
|
|
/**
|
|
* Hook for fetching spans related to a specific issue.
|
|
*/
|
|
export function useIssueSpans(issueId: string | null) {
|
|
const [data, setData] = useState<ReviewIQAnalyticsResponse['spans']['items']>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!issueId) {
|
|
setData([]);
|
|
return;
|
|
}
|
|
|
|
const fetchSpans = async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await fetch(`/api/pipelines/reviewiq/issues/${issueId}/spans`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error ${response.status}`);
|
|
}
|
|
|
|
const spans = await response.json();
|
|
setData(spans);
|
|
} catch (err) {
|
|
console.error('Failed to fetch issue spans:', err);
|
|
setError(err instanceof Error ? err.message : 'Failed to fetch spans');
|
|
setData([]);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchSpans();
|
|
}, [issueId]);
|
|
|
|
return { data, loading, error };
|
|
}
|