210 lines
5.9 KiB
TypeScript
210 lines
5.9 KiB
TypeScript
/**
|
|
* 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<void>;
|
|
refreshPOIs: () => Promise<void>;
|
|
fetchContext: () => Promise<void>;
|
|
fetchFeatureImportance: () => Promise<void>;
|
|
fetchCompetitorAnalysis: () => Promise<void>;
|
|
deletePOIContext: () => Promise<void>;
|
|
}
|
|
|
|
export function usePOIContext({ tenantId, autoFetch = true }: UsePOIContextOptions): UsePOIContextResult {
|
|
const [poiContext, setPOIContext] = useState<POIContext | null>(null);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [isStale, setIsStale] = useState(false);
|
|
const [needsRefresh, setNeedsRefresh] = useState(false);
|
|
const [featureImportance, setFeatureImportance] = useState<FeatureImportanceResponse | null>(null);
|
|
const [competitorAnalysis, setCompetitorAnalysis] = useState<CompetitorAnalysis | null>(null);
|
|
const [competitiveInsights, setCompetitiveInsights] = useState<string[]>([]);
|
|
|
|
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
|
|
};
|
|
}
|