// frontend/src/api/hooks/useForecast.ts /** * Forecasting Operations Hooks */ import { useState, useCallback } from 'react'; import { forecastingService } from '../services'; import type { SingleForecastRequest, BatchForecastRequest, ForecastResponse, BatchForecastResponse, ForecastAlert, QuickForecast, } from '../types'; export const useForecast = () => { const [forecasts, setForecasts] = useState([]); const [batchForecasts, setBatchForecasts] = useState([]); const [quickForecasts, setQuickForecasts] = useState([]); const [alerts, setAlerts] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const createSingleForecast = useCallback(async ( tenantId: string, request: SingleForecastRequest ): Promise => { try { setIsLoading(true); setError(null); const newForecasts = await forecastingService.createSingleForecast(tenantId, request); setForecasts(prev => [...newForecasts, ...(prev || [])]); return newForecasts; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to create forecast'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const createBatchForecast = useCallback(async ( tenantId: string, request: BatchForecastRequest ): Promise => { try { setIsLoading(true); setError(null); const batchForecast = await forecastingService.createBatchForecast(tenantId, request); setBatchForecasts(prev => [batchForecast, ...(prev || [])]); return batchForecast; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to create batch forecast'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getForecasts = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const response = await forecastingService.getForecasts(tenantId); setForecasts(response.data); return response.data; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get forecasts'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getBatchForecastStatus = useCallback(async ( tenantId: string, batchId: string ): Promise => { try { const batchForecast = await forecastingService.getBatchForecastStatus(tenantId, batchId); // Update batch forecast in state setBatchForecasts(prev => (prev || []).map(bf => bf.id === batchId ? batchForecast : bf )); return batchForecast; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get batch forecast status'; setError(message); throw error; } }, []); const getQuickForecasts = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const quickForecastData = await forecastingService.getQuickForecasts(tenantId); setQuickForecasts(quickForecastData); return quickForecastData; } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get quick forecasts'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const getForecastAlerts = useCallback(async (tenantId: string): Promise => { try { setIsLoading(true); setError(null); const response = await forecastingService.getForecastAlerts(tenantId); // Handle different response formats if (response && 'data' in response && response.data) { // Standard paginated format: { data: [...], pagination: {...} } setAlerts(response.data); return { alerts: response.data, ...response }; } else if (response && Array.isArray(response)) { // Direct array format setAlerts(response); return { alerts: response }; } else if (Array.isArray(response)) { // Direct array format setAlerts(response); return { alerts: response }; } else { // Unknown format - return empty setAlerts([]); return { alerts: [] }; } } catch (error) { const message = error instanceof Error ? error.message : 'Failed to get forecast alerts'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const acknowledgeForecastAlert = useCallback(async ( tenantId: string, alertId: string ): Promise => { try { setIsLoading(true); setError(null); const acknowledgedAlert = await forecastingService.acknowledgeForecastAlert(tenantId, alertId); setAlerts(prev => (prev || []).map(alert => alert.id === alertId ? acknowledgedAlert : alert )); } catch (error) { const message = error instanceof Error ? error.message : 'Failed to acknowledge alert'; setError(message); throw error; } finally { setIsLoading(false); } }, []); const exportForecasts = useCallback(async ( tenantId: string, format: 'csv' | 'excel' | 'json', params?: { inventory_product_id?: string; // Primary way to filter by product product_name?: string; // For backward compatibility start_date?: string; end_date?: string; } ): Promise => { try { setIsLoading(true); setError(null); const blob = await forecastingService.exportForecasts(tenantId, format, params); // Create download link const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `forecasts.${format}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { const message = error instanceof Error ? error.message : 'Export failed'; setError(message); throw error; } finally { setIsLoading(false); } }, []); return { forecasts, batchForecasts, quickForecasts, alerts, isLoading, error, createSingleForecast, createBatchForecast, getForecasts, getBatchForecastStatus, getQuickForecasts, getForecastAlerts, acknowledgeForecastAlert, exportForecasts, clearError: () => setError(null), }; };