- All fetch calls to Supabase Edge Functions now include Authorization: Bearer <anon_key> (was missing → 401 errors) - Fix Firecrawl screenshot API: remove invalid screenshotOptions, use "screenshot@fullPage" format (v2 API compatibility) - Fix screenshot response handling: v2 returns URL not base64, now downloads and converts to base64 for Gemini Vision - Add about page to Vision Analysis capture targets - Add retry utility, channel error tracking, pipeline resume, enrichment retry, EmptyState improvements (Sprint 2-3) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.6 KiB
TypeScript
92 lines
2.6 KiB
TypeScript
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
import { enrichChannels, fetchReportById } from '../lib/supabase';
|
|
import { mergeEnrichment, type EnrichmentData } from '../lib/transformReport';
|
|
import type { MarketingReport } from '../types/report';
|
|
|
|
type EnrichmentStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
|
|
interface UseEnrichmentResult {
|
|
status: EnrichmentStatus;
|
|
enrichedReport: MarketingReport | null;
|
|
/** Number of retry attempts made */
|
|
retryCount: number;
|
|
/** Call this to retry enrichment (max 2 retries) */
|
|
retry: () => void;
|
|
}
|
|
|
|
interface EnrichmentParams {
|
|
reportId: string | null;
|
|
clinicName: string;
|
|
instagramHandle?: string;
|
|
instagramHandles?: string[];
|
|
youtubeChannelId?: string;
|
|
facebookHandle?: string;
|
|
address?: string;
|
|
}
|
|
|
|
const MAX_RETRIES = 2;
|
|
|
|
/**
|
|
* Triggers background channel enrichment after Phase 1 report renders.
|
|
* Fires once, waits for the Edge Function to complete (~27s),
|
|
* then returns the merged report. Supports up to 2 manual retries.
|
|
*/
|
|
export function useEnrichment(
|
|
baseReport: MarketingReport | null,
|
|
params: EnrichmentParams | null,
|
|
): UseEnrichmentResult {
|
|
const [status, setStatus] = useState<EnrichmentStatus>('idle');
|
|
const [enrichedReport, setEnrichedReport] = useState<MarketingReport | null>(null);
|
|
const [retryCount, setRetryCount] = useState(0);
|
|
const hasTriggered = useRef(false);
|
|
|
|
const doEnrich = useCallback(async () => {
|
|
if (!baseReport || !params?.reportId) return;
|
|
|
|
setStatus('loading');
|
|
|
|
try {
|
|
const result = await enrichChannels({
|
|
reportId: params.reportId,
|
|
clinicName: params.clinicName,
|
|
instagramHandle: params.instagramHandle,
|
|
instagramHandles: params.instagramHandles,
|
|
youtubeChannelId: params.youtubeChannelId,
|
|
facebookHandle: params.facebookHandle,
|
|
address: params.address,
|
|
});
|
|
|
|
if (result.success && result.data) {
|
|
const merged = mergeEnrichment(baseReport, result.data as EnrichmentData);
|
|
setEnrichedReport(merged);
|
|
setStatus('success');
|
|
} else {
|
|
setStatus('error');
|
|
}
|
|
} catch {
|
|
setStatus('error');
|
|
}
|
|
}, [baseReport, params]);
|
|
|
|
// Initial trigger
|
|
useEffect(() => {
|
|
if (!baseReport || !params?.reportId || hasTriggered.current) return;
|
|
hasTriggered.current = true;
|
|
doEnrich();
|
|
}, [baseReport, params, doEnrich]);
|
|
|
|
// Manual retry
|
|
const retry = useCallback(() => {
|
|
if (retryCount >= MAX_RETRIES) return;
|
|
setRetryCount(prev => prev + 1);
|
|
doEnrich();
|
|
}, [retryCount, doEnrich]);
|
|
|
|
return {
|
|
status,
|
|
enrichedReport,
|
|
retryCount,
|
|
retry,
|
|
};
|
|
}
|