better stuffs
This commit is contained in:
@@ -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 (
|
||||
<Card>
|
||||
@@ -212,14 +229,43 @@ export default function PredictionsChart({
|
||||
<div className="text-2xl font-bold">
|
||||
{formatGBP(predictions.sales.predicted)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Badge
|
||||
className={getConfidenceColor(
|
||||
predictions.sales.confidence,
|
||||
)}
|
||||
>
|
||||
{predictions.sales.confidence} confidence
|
||||
{getConfidenceLabel(predictions.sales.confidence)} Confidence
|
||||
{predictions.sales.confidenceScore !== undefined && (
|
||||
<span className="ml-1 opacity-75">
|
||||
({Math.round(predictions.sales.confidenceScore * 100)}%)
|
||||
</span>
|
||||
)}
|
||||
</Badge>
|
||||
{predictions.sales.trend && (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={
|
||||
predictions.sales.trend.direction === "up"
|
||||
? "text-green-600 border-green-600"
|
||||
: predictions.sales.trend.direction === "down"
|
||||
? "text-red-600 border-red-600"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{predictions.sales.trend.direction === "up" && (
|
||||
<TrendingUp className="h-3 w-3 mr-1" />
|
||||
)}
|
||||
{predictions.sales.trend.direction === "down" && (
|
||||
<TrendingDown className="h-3 w-3 mr-1" />
|
||||
)}
|
||||
{predictions.sales.trend.direction === "up"
|
||||
? "Trending Up"
|
||||
: predictions.sales.trend.direction === "down"
|
||||
? "Trending Down"
|
||||
: "Stable"}
|
||||
</Badge>
|
||||
)}
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Next {daysAhead} days
|
||||
</span>
|
||||
@@ -230,7 +276,38 @@ export default function PredictionsChart({
|
||||
orders
|
||||
</div>
|
||||
)}
|
||||
{predictions.sales.minPrediction &&
|
||||
{predictions.sales.confidenceIntervals && (
|
||||
<div className="text-xs text-muted-foreground space-y-1">
|
||||
<div>
|
||||
Range: {formatGBP(predictions.sales.confidenceIntervals.lower)} -{" "}
|
||||
{formatGBP(predictions.sales.confidenceIntervals.upper)}
|
||||
</div>
|
||||
<div className="text-xs opacity-75">
|
||||
95% confidence interval
|
||||
</div>
|
||||
{predictions.sales.confidenceIntervals.confidenceScore !== undefined && (
|
||||
<div className="flex gap-3 text-xs opacity-75 mt-2 pt-2 border-t">
|
||||
{predictions.sales.confidenceIntervals.avgModelAccuracy !== undefined && (
|
||||
<div>
|
||||
Model Accuracy: {Math.round(predictions.sales.confidenceIntervals.avgModelAccuracy * 100)}%
|
||||
</div>
|
||||
)}
|
||||
{predictions.sales.confidenceIntervals.modelAgreement !== undefined && (
|
||||
<div>
|
||||
Agreement: {Math.round(predictions.sales.confidenceIntervals.modelAgreement * 100)}%
|
||||
</div>
|
||||
)}
|
||||
{predictions.sales.confidenceIntervals.dataConsistency !== undefined && (
|
||||
<div>
|
||||
Data Quality: {Math.round(predictions.sales.confidenceIntervals.dataConsistency * 100)}%
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!predictions.sales.confidenceIntervals &&
|
||||
predictions.sales.minPrediction &&
|
||||
predictions.sales.maxPrediction && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
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
|
||||
</Badge>
|
||||
</div>
|
||||
{predictions.demand.predictedWeekly && (
|
||||
@@ -279,6 +356,12 @@ export default function PredictionsChart({
|
||||
~{predictions.demand.predictedMonthly.toFixed(0)} units/month
|
||||
</div>
|
||||
)}
|
||||
{predictions.demand.confidenceIntervals && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Range: {predictions.demand.confidenceIntervals.lower.toFixed(1)} -{" "}
|
||||
{predictions.demand.confidenceIntervals.upper.toFixed(1)} units/day
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
@@ -369,19 +452,56 @@ export default function PredictionsChart({
|
||||
{prediction.currentStock} {prediction.unitType}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{prediction.prediction.daysUntilOutOfStock !== null
|
||||
? `${prediction.prediction.daysUntilOutOfStock} days`
|
||||
: "N/A"}
|
||||
{prediction.prediction.daysUntilOutOfStock !== null ? (
|
||||
<div className="space-y-1">
|
||||
<div className="font-medium">
|
||||
{prediction.prediction.daysUntilOutOfStock} days
|
||||
</div>
|
||||
{prediction.prediction.optimisticDays !== null &&
|
||||
prediction.prediction.pessimisticDays && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{prediction.prediction.optimisticDays} -{" "}
|
||||
{prediction.prediction.pessimisticDays} days
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
"N/A"
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{prediction.prediction.estimatedDate
|
||||
? format(
|
||||
{prediction.prediction.estimatedDate ? (
|
||||
<div className="space-y-1">
|
||||
<div>
|
||||
{format(
|
||||
new Date(
|
||||
prediction.prediction.estimatedDate,
|
||||
),
|
||||
"MMM d, yyyy",
|
||||
)
|
||||
: "N/A"}
|
||||
)}
|
||||
</div>
|
||||
{prediction.prediction.optimisticDate &&
|
||||
prediction.prediction.pessimisticDate && (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{format(
|
||||
new Date(
|
||||
prediction.prediction.optimisticDate,
|
||||
),
|
||||
"MMM d",
|
||||
)}{" "}
|
||||
-{" "}
|
||||
{format(
|
||||
new Date(
|
||||
prediction.prediction.pessimisticDate,
|
||||
),
|
||||
"MMM d",
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
"N/A"
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge
|
||||
@@ -389,7 +509,7 @@ export default function PredictionsChart({
|
||||
prediction.prediction.confidence,
|
||||
)}
|
||||
>
|
||||
{prediction.prediction.confidence}
|
||||
{getConfidenceLabel(prediction.prediction.confidence)}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
|
||||
@@ -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<string, number>;
|
||||
month: Record<string, number>;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user