/** * React Query hooks wrapping the intelligence API for the CP dashboard. * * (c) 2026 TWWIM UG. All rights reserved. (www.twwim.com) */ import { useQuery } from '@tanstack/react-query'; import { intelligenceApi, type IntelligenceGranularity, type ProductDemandSortBy } from '@/infrastructure/http/api/intelligence'; const keys = { today: (tenantId: string, startISO?: string, endISO?: string) => ['intel', 'today', tenantId, startISO, endISO] as const, kpiSeries: (tenantId: string, gran: IntelligenceGranularity, s?: string, e?: string) => ['intel', 'kpiSeries', tenantId, gran, s, e] as const, overview: (tenantId: string, s?: string, e?: string) => ['intel', 'overview', tenantId, s, e] as const, errors: (tenantId: string, s?: string, e?: string) => ['intel', 'errors', tenantId, s, e] as const, timeseries: (tenantId: string, gran: IntelligenceGranularity, s?: string, e?: string) => ['intel', 'timeseries', tenantId, gran, s, e] as const, productDemand:(tenantId: string, sortBy: ProductDemandSortBy, s?: string, e?: string, l?: number) => ['intel', 'product', tenantId, sortBy, s, e, l] as const, queryPhrase: (tenantId: string, gapOnly: boolean, s?: string, e?: string, l?: number) => ['intel', 'phrase', tenantId, gapOnly, s, e, l] as const, intentTheme: (tenantId: string, s?: string, e?: string) => ['intel', 'intent', tenantId, s, e] as const, }; // Caller passes ISO strings — Date objects are recreated on every render and // would otherwise destabilise the queryKey (causing a refetch loop). The // hooks parse back to Date only when actually building the fetch call. const toDate = (s?: string | null): Date | undefined => (s ? new Date(s) : undefined); interface DateWindow { startISO?: string; endISO?: string } export function useTodayKpis(tenantId: string | null, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.today(tenantId ?? '', startISO, endISO), queryFn: () => intelligenceApi.today(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); } export function useKpiTimeseries(tenantId: string | null, granularity: IntelligenceGranularity, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.kpiSeries(tenantId ?? '', granularity, startISO, endISO), queryFn: () => intelligenceApi.kpiTimeseries(tenantId!, granularity, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); } export function useAnalyticsOverview(tenantId: string | null, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.overview(tenantId ?? '', startISO, endISO), queryFn: () => intelligenceApi.analyticsOverview(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); } export function useAnalyticsErrors(tenantId: string | null, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.errors(tenantId ?? '', startISO, endISO), queryFn: () => intelligenceApi.analyticsErrors(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); } export function useAnalyticsTimeseries(tenantId: string | null, granularity: IntelligenceGranularity, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.timeseries(tenantId ?? '', granularity, startISO, endISO), queryFn: () => intelligenceApi.analyticsTimeseries(tenantId!, granularity, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); } export function useProductDemand(tenantId: string | null, sortBy: ProductDemandSortBy, opts: DateWindow & { limit?: number } = {}) { const { startISO, endISO, limit } = opts; return useQuery({ queryKey: keys.productDemand(tenantId ?? '', sortBy, startISO, endISO, limit), queryFn: () => intelligenceApi.productDemand(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO), limit, sortBy }), enabled: !!tenantId, select: (r) => r.data, }); } export function useQueryPhrase(tenantId: string | null, opts: DateWindow & { limit?: number; gapOnly?: boolean } = {}) { const { startISO, endISO, limit, gapOnly } = opts; return useQuery({ queryKey: keys.queryPhrase(tenantId ?? '', !!gapOnly, startISO, endISO, limit), queryFn: () => intelligenceApi.queryPhrase(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO), limit, gapOnly }), enabled: !!tenantId, select: (r) => r.data, }); } export function useIntentTheme(tenantId: string | null, window: DateWindow = {}) { const { startISO, endISO } = window; return useQuery({ queryKey: keys.intentTheme(tenantId ?? '', startISO, endISO), queryFn: () => intelligenceApi.intentTheme(tenantId!, { startDate: toDate(startISO), endDate: toDate(endISO) }), enabled: !!tenantId, select: (r) => r.data, }); }