better stuffs
This commit is contained in:
@@ -90,6 +90,8 @@ export default function PredictionsChart({
|
|||||||
|
|
||||||
const getConfidenceColor = (confidence: string) => {
|
const getConfidenceColor = (confidence: string) => {
|
||||||
switch (confidence) {
|
switch (confidence) {
|
||||||
|
case "very_high":
|
||||||
|
return "bg-emerald-600/20 text-emerald-700 dark:text-emerald-400 border-emerald-600/30";
|
||||||
case "high":
|
case "high":
|
||||||
return "bg-green-500/10 text-green-700 dark:text-green-400";
|
return "bg-green-500/10 text-green-700 dark:text-green-400";
|
||||||
case "medium":
|
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) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
@@ -212,14 +229,43 @@ export default function PredictionsChart({
|
|||||||
<div className="text-2xl font-bold">
|
<div className="text-2xl font-bold">
|
||||||
{formatGBP(predictions.sales.predicted)}
|
{formatGBP(predictions.sales.predicted)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<Badge
|
<Badge
|
||||||
className={getConfidenceColor(
|
className={getConfidenceColor(
|
||||||
predictions.sales.confidence,
|
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>
|
</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">
|
<span className="text-xs text-muted-foreground">
|
||||||
Next {daysAhead} days
|
Next {daysAhead} days
|
||||||
</span>
|
</span>
|
||||||
@@ -230,7 +276,38 @@ export default function PredictionsChart({
|
|||||||
orders
|
orders
|
||||||
</div>
|
</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 && (
|
predictions.sales.maxPrediction && (
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
Range: {formatGBP(predictions.sales.minPrediction)} -{" "}
|
Range: {formatGBP(predictions.sales.minPrediction)} -{" "}
|
||||||
@@ -266,7 +343,7 @@ export default function PredictionsChart({
|
|||||||
predictions.demand.confidence,
|
predictions.demand.confidence,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{predictions.demand.confidence} confidence
|
{getConfidenceLabel(predictions.demand.confidence)} Confidence
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
{predictions.demand.predictedWeekly && (
|
{predictions.demand.predictedWeekly && (
|
||||||
@@ -279,6 +356,12 @@ export default function PredictionsChart({
|
|||||||
~{predictions.demand.predictedMonthly.toFixed(0)} units/month
|
~{predictions.demand.predictedMonthly.toFixed(0)} units/month
|
||||||
</div>
|
</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>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
@@ -369,19 +452,56 @@ export default function PredictionsChart({
|
|||||||
{prediction.currentStock} {prediction.unitType}
|
{prediction.currentStock} {prediction.unitType}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{prediction.prediction.daysUntilOutOfStock !== null
|
{prediction.prediction.daysUntilOutOfStock !== null ? (
|
||||||
? `${prediction.prediction.daysUntilOutOfStock} days`
|
<div className="space-y-1">
|
||||||
: "N/A"}
|
<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>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{prediction.prediction.estimatedDate
|
{prediction.prediction.estimatedDate ? (
|
||||||
? format(
|
<div className="space-y-1">
|
||||||
new Date(
|
<div>
|
||||||
prediction.prediction.estimatedDate,
|
{format(
|
||||||
),
|
new Date(
|
||||||
"MMM d, yyyy",
|
prediction.prediction.estimatedDate,
|
||||||
)
|
),
|
||||||
: "N/A"}
|
"MMM d, yyyy",
|
||||||
|
)}
|
||||||
|
</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>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge
|
<Badge
|
||||||
@@ -389,7 +509,7 @@ export default function PredictionsChart({
|
|||||||
prediction.prediction.confidence,
|
prediction.prediction.confidence,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{prediction.prediction.confidence}
|
{getConfidenceLabel(prediction.prediction.confidence)}
|
||||||
</Badge>
|
</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|||||||
@@ -308,17 +308,42 @@ export interface SalesPrediction {
|
|||||||
predicted: number;
|
predicted: number;
|
||||||
date: string;
|
date: string;
|
||||||
}>;
|
}>;
|
||||||
confidence: "high" | "medium" | "low";
|
confidence: "very_high" | "high" | "medium" | "low";
|
||||||
method: string;
|
method: string;
|
||||||
methods?: {
|
methods?: {
|
||||||
movingAverage?: number | null;
|
weightedMovingAverage?: number | null;
|
||||||
exponentialAverage?: number | null;
|
exponentialSmoothing?: number | null;
|
||||||
linearRegression?: number | null;
|
holtWinters?: number | null;
|
||||||
trendAverage?: number | null;
|
weightedLinearRegression?: number | null;
|
||||||
|
trendAdjusted?: number | null;
|
||||||
|
};
|
||||||
|
trend?: {
|
||||||
|
direction: "up" | "down" | "neutral";
|
||||||
|
strength: number;
|
||||||
|
acceleration: number;
|
||||||
|
slope?: number;
|
||||||
};
|
};
|
||||||
variance?: number;
|
variance?: number;
|
||||||
minPrediction?: number;
|
minPrediction?: number;
|
||||||
maxPrediction?: 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?: {
|
seasonality?: {
|
||||||
dayOfWeek: Record<string, number>;
|
dayOfWeek: Record<string, number>;
|
||||||
month: Record<string, number>;
|
month: Record<string, number>;
|
||||||
@@ -333,10 +358,18 @@ export interface DemandPrediction {
|
|||||||
predictedDaily: number | null;
|
predictedDaily: number | null;
|
||||||
predictedWeekly: number | null;
|
predictedWeekly: number | null;
|
||||||
predictedMonthly: number | null;
|
predictedMonthly: number | null;
|
||||||
confidence: "high" | "medium" | "low";
|
confidence: "very_high" | "high" | "medium" | "low";
|
||||||
averageDaily?: number;
|
averageDaily?: number;
|
||||||
trendFactor?: number;
|
trendFactor?: number;
|
||||||
stdDev?: number;
|
stdDev?: number;
|
||||||
|
confidenceIntervals?: {
|
||||||
|
lower: number;
|
||||||
|
upper: number;
|
||||||
|
confidenceScore?: number;
|
||||||
|
modelAgreement?: number;
|
||||||
|
avgModelAccuracy?: number;
|
||||||
|
dataConsistency?: number;
|
||||||
|
};
|
||||||
historicalPeriod: number;
|
historicalPeriod: number;
|
||||||
predictionPeriod: number;
|
predictionPeriod: number;
|
||||||
productId?: string | null;
|
productId?: string | null;
|
||||||
@@ -352,9 +385,13 @@ export interface StockPrediction {
|
|||||||
prediction: {
|
prediction: {
|
||||||
daysUntilOutOfStock: number | null;
|
daysUntilOutOfStock: number | null;
|
||||||
estimatedDate: string | null;
|
estimatedDate: string | null;
|
||||||
confidence: "high" | "medium" | "low";
|
confidence: "very_high" | "high" | "medium" | "low";
|
||||||
averageDailySales?: number;
|
averageDailySales?: number;
|
||||||
stdDev?: number;
|
stdDev?: number;
|
||||||
|
optimisticDays?: number | null;
|
||||||
|
pessimisticDays?: number | null;
|
||||||
|
optimisticDate?: string | null;
|
||||||
|
pessimisticDate?: string | null;
|
||||||
message?: string;
|
message?: string;
|
||||||
};
|
};
|
||||||
needsRestock: boolean;
|
needsRestock: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user