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(
|
||||
new Date(
|
||||
prediction.prediction.estimatedDate,
|
||||
),
|
||||
"MMM d, yyyy",
|
||||
)
|
||||
: "N/A"}
|
||||
{prediction.prediction.estimatedDate ? (
|
||||
<div className="space-y-1">
|
||||
<div>
|
||||
{format(
|
||||
new Date(
|
||||
prediction.prediction.estimatedDate,
|
||||
),
|
||||
"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>
|
||||
<Badge
|
||||
@@ -389,7 +509,7 @@ export default function PredictionsChart({
|
||||
prediction.prediction.confidence,
|
||||
)}
|
||||
>
|
||||
{prediction.prediction.confidence}
|
||||
{getConfidenceLabel(prediction.prediction.confidence)}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
|
||||
Reference in New Issue
Block a user