Improve dashboard maintainability before the next release
The dashboard had several oversized orchestration, component, and CSS files that made product-copy changes and mobile/performance work risky. This refactor preserves behavior while splitting scan terminal CSS, opportunity helpers, future forecast panels, history/detail charts, and probability/model sections into smaller ownership boundaries. Constraint: No user-visible version bump because this batch is architecture and performance cleanup, not a release announcement. Rejected: Rewrite dashboard state management in the same batch | too broad for a safe upload after CSS and component splitting. Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep new component/CSS boundaries instead of moving product copy back into the large dashboard files. Tested: npm run build; npm run test:business; git diff --check Not-tested: Browser visual smoke test after push
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import type { ScanOpportunityRow } from "@/lib/dashboard-types";
|
||||
import { normalizeTemperatureLabel } from "@/lib/temperature-utils";
|
||||
|
||||
export function normalizeBucketLabel(value?: string | null, tempSymbol?: string | null) {
|
||||
return normalizeTemperatureLabel(value, tempSymbol)
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "")
|
||||
.replace(/℃/g, "°c");
|
||||
}
|
||||
|
||||
export function extractNumbers(value?: string | null) {
|
||||
return Array.from(String(value || "").matchAll(/-?\d+(?:\.\d+)?/g)).map((match) =>
|
||||
Number(match[0]),
|
||||
);
|
||||
}
|
||||
|
||||
export function getTargetRange(row: ScanOpportunityRow) {
|
||||
const lower =
|
||||
row.target_lower != null && Number.isFinite(Number(row.target_lower))
|
||||
? Number(row.target_lower)
|
||||
: null;
|
||||
const upper =
|
||||
row.target_upper != null && Number.isFinite(Number(row.target_upper))
|
||||
? Number(row.target_upper)
|
||||
: null;
|
||||
if (lower != null || upper != null) return { lower, upper };
|
||||
|
||||
const rawLabel = String(row.target_label || row.action || "");
|
||||
const numbers = extractNumbers(rawLabel);
|
||||
if (numbers.length >= 2) {
|
||||
return { lower: Math.min(numbers[0], numbers[1]), upper: Math.max(numbers[0], numbers[1]) };
|
||||
}
|
||||
const value =
|
||||
row.target_threshold ??
|
||||
row.target_value ??
|
||||
(numbers.length ? numbers[0] : null);
|
||||
if (value == null || !Number.isFinite(Number(value))) {
|
||||
return { lower: null, upper: null };
|
||||
}
|
||||
const numeric = Number(value);
|
||||
if (/(\+|above|higher|or\s+higher|>=|≥|以上)/i.test(rawLabel)) {
|
||||
return { lower: numeric, upper: null };
|
||||
}
|
||||
if (/(below|or\s+below|<=|≤|以下)/i.test(rawLabel)) {
|
||||
return { lower: null, upper: numeric };
|
||||
}
|
||||
return { lower: numeric, upper: numeric };
|
||||
}
|
||||
Reference in New Issue
Block a user