/** * POI Context React Hook * * Custom hook for managing POI context state and operations */ import { useState, useEffect, useCallback } from 'react'; import { poiContextApi } from '@/services/api/poiContextApi'; import type { POIContext, POIDetectionResponse, FeatureImportanceResponse, CompetitorAnalysis } from '@/types/poi'; export interface UsePOIContextOptions { tenantId: string; autoFetch?: boolean; } export interface UsePOIContextResult { poiContext: POIContext | null; isLoading: boolean; isRefreshing: boolean; error: string | null; isStale: boolean; needsRefresh: boolean; featureImportance: FeatureImportanceResponse | null; competitorAnalysis: CompetitorAnalysis | null; competitiveInsights: string[]; // Actions detectPOIs: (latitude: number, longitude: number, forceRefresh?: boolean) => Promise; refreshPOIs: () => Promise; fetchContext: () => Promise; fetchFeatureImportance: () => Promise; fetchCompetitorAnalysis: () => Promise; deletePOIContext: () => Promise; } export function usePOIContext({ tenantId, autoFetch = true }: UsePOIContextOptions): UsePOIContextResult { const [poiContext, setPOIContext] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const [error, setError] = useState(null); const [isStale, setIsStale] = useState(false); const [needsRefresh, setNeedsRefresh] = useState(false); const [featureImportance, setFeatureImportance] = useState(null); const [competitorAnalysis, setCompetitorAnalysis] = useState(null); const [competitiveInsights, setCompetitiveInsights] = useState([]); const fetchContext = useCallback(async () => { if (!tenantId) return; try { setIsLoading(true); setError(null); const response = await poiContextApi.getPOIContext(tenantId); setPOIContext(response.poi_context); setIsStale(response.is_stale); setNeedsRefresh(response.needs_refresh); } catch (err: any) { if (err.response?.status === 404) { // No POI context found - this is normal for new tenants setPOIContext(null); setError(null); } else { setError(err.message || 'Failed to fetch POI context'); console.error('Error fetching POI context:', err); } } finally { setIsLoading(false); } }, [tenantId]); const detectPOIs = useCallback(async ( latitude: number, longitude: number, forceRefresh: boolean = false ) => { if (!tenantId) return; try { setIsLoading(true); setError(null); const response = await poiContextApi.detectPOIs( tenantId, latitude, longitude, forceRefresh ); setPOIContext(response.poi_context); setIsStale(false); setNeedsRefresh(false); // Update competitor analysis if available if (response.competitor_analysis) { setCompetitorAnalysis(response.competitor_analysis); } // Update competitive insights if available if (response.competitive_insights) { setCompetitiveInsights(response.competitive_insights); } } catch (err: any) { setError(err.message || 'Failed to detect POIs'); console.error('Error detecting POIs:', err); } finally { setIsLoading(false); } }, [tenantId]); const refreshPOIs = useCallback(async () => { if (!tenantId) return; try { setIsRefreshing(true); setError(null); const response = await poiContextApi.refreshPOIContext(tenantId); setPOIContext(response.poi_context); setIsStale(false); setNeedsRefresh(false); // Update competitor analysis if available if (response.competitor_analysis) { setCompetitorAnalysis(response.competitor_analysis); } // Update competitive insights if available if (response.competitive_insights) { setCompetitiveInsights(response.competitive_insights); } } catch (err: any) { setError(err.message || 'Failed to refresh POI context'); console.error('Error refreshing POI context:', err); } finally { setIsRefreshing(false); } }, [tenantId]); const fetchFeatureImportance = useCallback(async () => { if (!tenantId) return; try { const response = await poiContextApi.getFeatureImportance(tenantId); setFeatureImportance(response); } catch (err: any) { console.error('Error fetching feature importance:', err); } }, [tenantId]); const fetchCompetitorAnalysis = useCallback(async () => { if (!tenantId) return; try { const response = await poiContextApi.getCompetitorAnalysis(tenantId); setCompetitorAnalysis(response.competitor_analysis); setCompetitiveInsights(response.insights); } catch (err: any) { console.error('Error fetching competitor analysis:', err); } }, [tenantId]); const deletePOIContext = useCallback(async () => { if (!tenantId) return; try { await poiContextApi.deletePOIContext(tenantId); setPOIContext(null); setFeatureImportance(null); setCompetitorAnalysis(null); setCompetitiveInsights([]); setIsStale(false); setNeedsRefresh(false); } catch (err: any) { setError(err.message || 'Failed to delete POI context'); console.error('Error deleting POI context:', err); } }, [tenantId]); // Auto-fetch on mount if enabled useEffect(() => { if (autoFetch && tenantId) { fetchContext(); } }, [autoFetch, tenantId, fetchContext]); return { poiContext, isLoading, isRefreshing, error, isStale, needsRefresh, featureImportance, competitorAnalysis, competitiveInsights, detectPOIs, refreshPOIs, fetchContext, fetchFeatureImportance, fetchCompetitorAnalysis, deletePOIContext }; }