"use client"; import { useState, useEffect, memo, useMemo, useCallback } from "react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { TrendingUp, TrendingDown, Package, DollarSign, AlertTriangle, RefreshCw, Calendar, BarChart3, Sparkles, } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { Skeleton } from "@/components/ui/skeleton"; import { getPredictionsOverviewWithStore, getStockPredictionsWithStore, type PredictionsOverview, type StockPredictionsResponse, } from "@/lib/services/analytics-service"; import { formatGBP } from "@/utils/format"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { format } from "date-fns"; interface PredictionsChartProps { timeRange?: number; } export default function PredictionsChart({ timeRange = 90, }: PredictionsChartProps) { const [predictions, setPredictions] = useState( null, ); const [stockPredictions, setStockPredictions] = useState(null); const [loading, setLoading] = useState(true); const [daysAhead, setDaysAhead] = useState(7); const [activeTab, setActiveTab] = useState<"overview" | "stock">("overview"); const { toast } = useToast(); const fetchPredictions = async () => { try { setLoading(true); const [overview, stock] = await Promise.all([ getPredictionsOverviewWithStore(daysAhead, timeRange), getStockPredictionsWithStore(timeRange), ]); setPredictions(overview); setStockPredictions(stock); } catch (error) { console.error("Error fetching predictions:", error); toast({ title: "Error", description: "Failed to load predictions", variant: "destructive", }); } finally { setLoading(false); } }; useEffect(() => { fetchPredictions(); }, [daysAhead, timeRange]); const getConfidenceColor = (confidence: string) => { switch (confidence) { case "very_high": return "bg-emerald-600/20 text-emerald-700 dark:text-emerald-400 border-emerald-600/30"; case "high": return "bg-green-500/10 text-green-700 dark:text-green-400"; case "medium": return "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400"; case "low": return "bg-red-500/10 text-red-700 dark:text-red-400"; default: return "bg-gray-500/10 text-gray-700 dark:text-gray-400"; } }; const getConfidenceLabel = (confidence: string) => { switch (confidence) { case "very_high": return "Very High"; case "high": return "High"; case "medium": return "Medium"; case "low": return "Low"; default: return confidence; } }; if (loading) { return (
); } if (!predictions) { return ( Predictions Forecast future sales, demand, and stock levels

No prediction data available. Need more historical data.

); } return (
Predictions & Forecasting {predictions.sales.aiModel?.used && ( )} {predictions.sales.aiModel?.used ? "AI neural network + statistical models for sales, demand, and inventory" : "AI-powered predictions for sales, demand, and inventory"}
{activeTab === "overview" && (
{/* Sales Predictions */}
Revenue Prediction {predictions.sales.predicted !== null ? (
{formatGBP(predictions.sales.predicted)}
{getConfidenceLabel(predictions.sales.confidence)} Confidence {predictions.sales.confidenceScore !== undefined && ( ({Math.round(predictions.sales.confidenceScore * 100)}%) )} {predictions.sales.aiModel?.used && ( 🤖 AI Powered {predictions.sales.aiModel.modelAccuracy !== undefined && ( ({Math.round(predictions.sales.aiModel.modelAccuracy * 100)}%) )} )} {predictions.sales.trend && ( {predictions.sales.trend.direction === "up" && ( )} {predictions.sales.trend.direction === "down" && ( )} {predictions.sales.trend.direction === "up" ? "Trending Up" : predictions.sales.trend.direction === "down" ? "Trending Down" : "Stable"} )} Next {daysAhead} days
{predictions.sales.predictedOrders && (
~{Math.round(predictions.sales.predictedOrders)}{" "} orders
)} {predictions.sales.confidenceIntervals && (
Range: {formatGBP(predictions.sales.confidenceIntervals.lower)} -{" "} {formatGBP(predictions.sales.confidenceIntervals.upper)}
95% confidence interval
{predictions.sales.confidenceIntervals.confidenceScore !== undefined && (
{predictions.sales.confidenceIntervals.avgModelAccuracy !== undefined && (
Model Accuracy: {Math.round(predictions.sales.confidenceIntervals.avgModelAccuracy * 100)}%
)} {predictions.sales.confidenceIntervals.modelAgreement !== undefined && (
Agreement: {Math.round(predictions.sales.confidenceIntervals.modelAgreement * 100)}%
)} {predictions.sales.confidenceIntervals.dataConsistency !== undefined && (
Data Quality: {Math.round(predictions.sales.confidenceIntervals.dataConsistency * 100)}%
)}
)}
)} {!predictions.sales.confidenceIntervals && predictions.sales.minPrediction && predictions.sales.maxPrediction && (
Range: {formatGBP(predictions.sales.minPrediction)} -{" "} {formatGBP(predictions.sales.maxPrediction)}
)}
) : (
{predictions.sales.message || "Insufficient data for prediction"}
)}
Demand Prediction {predictions.demand.predictedDaily !== null ? (
{predictions.demand.predictedDaily.toFixed(1)} units/day
{getConfidenceLabel(predictions.demand.confidence)} Confidence
{predictions.demand.predictedWeekly && (
~{predictions.demand.predictedWeekly.toFixed(0)} units/week
)} {predictions.demand.predictedMonthly && (
~{predictions.demand.predictedMonthly.toFixed(0)} units/month
)} {predictions.demand.confidenceIntervals && (
Range: {predictions.demand.confidenceIntervals.lower.toFixed(1)} -{" "} {predictions.demand.confidenceIntervals.upper.toFixed(1)} units/day
)}
) : (
{predictions.demand.message || "Insufficient data for prediction"}
)}
{/* Daily Predictions Chart */} {predictions.sales.dailyPredictions && predictions.sales.dailyPredictions.length > 0 && ( Daily Revenue Forecast
{predictions.sales.dailyPredictions.map((day) => (
Day {day.day}
{format(new Date(day.date), "MMM d, yyyy")}
{formatGBP(day.predicted)}
))}
)}
)} {activeTab === "stock" && (
{stockPredictions && stockPredictions.predictions.length > 0 ? ( <>

{stockPredictions.totalProducts} products tracked

{stockPredictions.productsNeedingRestock > 0 && (

{stockPredictions.productsNeedingRestock} products need restocking soon

)}
Product Current Stock Days Until Out Estimated Date Confidence Status {stockPredictions.predictions.map((prediction) => ( {prediction.productName} {prediction.currentStock} {prediction.unitType} {prediction.prediction.daysUntilOutOfStock !== null ? (
{prediction.prediction.daysUntilOutOfStock} days
{prediction.prediction.optimisticDays !== null && prediction.prediction.pessimisticDays && (
{prediction.prediction.optimisticDays} -{" "} {prediction.prediction.pessimisticDays} days
)}
) : ( "N/A" )}
{prediction.prediction.estimatedDate ? (
{format( new Date( prediction.prediction.estimatedDate, ), "MMM d, yyyy", )}
{prediction.prediction.optimisticDate && prediction.prediction.pessimisticDate && (
{format( new Date( prediction.prediction.optimisticDate, ), "MMM d", )}{" "} -{" "} {format( new Date( prediction.prediction.pessimisticDate, ), "MMM d", )}
)}
) : ( "N/A" )}
{getConfidenceLabel(prediction.prediction.confidence)} {prediction.needsRestock ? ( Restock Soon ) : ( OK )}
))}
) : (

No stock predictions available

Enable stock tracking on products to get predictions

)}
)}
); }