diff --git a/components/analytics/PredictionsChart.tsx b/components/analytics/PredictionsChart.tsx index 1d85572..42f3b1f 100644 --- a/components/analytics/PredictionsChart.tsx +++ b/components/analytics/PredictionsChart.tsx @@ -90,6 +90,8 @@ export default function PredictionsChart({ 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": @@ -101,6 +103,21 @@ export default function PredictionsChart({ } }; + 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 ( @@ -212,14 +229,43 @@ export default function PredictionsChart({
{formatGBP(predictions.sales.predicted)}
-
+
- {predictions.sales.confidence} confidence + {getConfidenceLabel(predictions.sales.confidence)} Confidence + {predictions.sales.confidenceScore !== undefined && ( + + ({Math.round(predictions.sales.confidenceScore * 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 @@ -230,7 +276,38 @@ export default function PredictionsChart({ orders
)} - {predictions.sales.minPrediction && + {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)} -{" "} @@ -266,7 +343,7 @@ export default function PredictionsChart({ predictions.demand.confidence, )} > - {predictions.demand.confidence} confidence + {getConfidenceLabel(predictions.demand.confidence)} Confidence
{predictions.demand.predictedWeekly && ( @@ -279,6 +356,12 @@ export default function PredictionsChart({ ~{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 +
+ )} ) : (
@@ -369,19 +452,56 @@ export default function PredictionsChart({ {prediction.currentStock} {prediction.unitType} - {prediction.prediction.daysUntilOutOfStock !== null - ? `${prediction.prediction.daysUntilOutOfStock} days` - : "N/A"} + {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", - ) - : "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" + )}
- {prediction.prediction.confidence} + {getConfidenceLabel(prediction.prediction.confidence)} diff --git a/lib/services/analytics-service.ts b/lib/services/analytics-service.ts index d16fc56..8c294f9 100644 --- a/lib/services/analytics-service.ts +++ b/lib/services/analytics-service.ts @@ -308,17 +308,42 @@ export interface SalesPrediction { predicted: number; date: string; }>; - confidence: "high" | "medium" | "low"; + confidence: "very_high" | "high" | "medium" | "low"; method: string; methods?: { - movingAverage?: number | null; - exponentialAverage?: number | null; - linearRegression?: number | null; - trendAverage?: number | null; + weightedMovingAverage?: number | null; + exponentialSmoothing?: number | null; + holtWinters?: number | null; + weightedLinearRegression?: number | null; + trendAdjusted?: number | null; + }; + trend?: { + direction: "up" | "down" | "neutral"; + strength: number; + acceleration: number; + slope?: number; }; variance?: number; minPrediction?: number; maxPrediction?: number; + confidenceScore?: number; + confidenceIntervals?: { + lower: number; + upper: number; + confidenceScore?: number; + modelAgreement?: number; + avgModelAccuracy?: number; + dataConsistency?: number; + }; + modelPerformance?: { + [key: string]: { + mae?: number; + mape?: number; + rmse?: number; + accuracy?: number; + confidence?: string; + }; + }; seasonality?: { dayOfWeek: Record; month: Record; @@ -333,10 +358,18 @@ export interface DemandPrediction { predictedDaily: number | null; predictedWeekly: number | null; predictedMonthly: number | null; - confidence: "high" | "medium" | "low"; + confidence: "very_high" | "high" | "medium" | "low"; averageDaily?: number; trendFactor?: number; stdDev?: number; + confidenceIntervals?: { + lower: number; + upper: number; + confidenceScore?: number; + modelAgreement?: number; + avgModelAccuracy?: number; + dataConsistency?: number; + }; historicalPeriod: number; predictionPeriod: number; productId?: string | null; @@ -352,9 +385,13 @@ export interface StockPrediction { prediction: { daysUntilOutOfStock: number | null; estimatedDate: string | null; - confidence: "high" | "medium" | "low"; + confidence: "very_high" | "high" | "medium" | "low"; averageDailySales?: number; stdDev?: number; + optimisticDays?: number | null; + pessimisticDays?: number | null; + optimisticDate?: string | null; + pessimisticDate?: string | null; message?: string; }; needsRestock: boolean;