Fix city selector fallback coverage

This commit is contained in:
2569718930@qq.com
2026-05-27 21:02:08 +08:00
parent fb7e27d9ed
commit 4d22191a2d
3 changed files with 95 additions and 3 deletions
@@ -50,7 +50,10 @@ import { KoyfinRowsTable } from "@/components/dashboard/scan-terminal/KoyfinRows
import { rowName, pct, money, temp, edgeClass } from "@/components/dashboard/scan-terminal/utils";
import { CitySelectorDropdown } from "@/components/dashboard/scan-terminal/CitySelectorDropdown";
import { GridLayoutSelector } from "@/components/dashboard/scan-terminal/GridLayoutSelector";
import { cityListItemsToScanRows } from "@/components/dashboard/scan-terminal/city-fallback-rows";
import {
cityListItemsToScanRows,
mergeScanRowsWithCityFallbackRows,
} from "@/components/dashboard/scan-terminal/city-fallback-rows";
function createEmptyAccess(loading = true): ProAccessState {
return {
@@ -1107,7 +1110,9 @@ function ScanTerminalScreen() {
const rows = useMemo(
() => {
const scanRows = terminalData?.rows || [];
return sortRowsByUserTime(scanRows.length ? scanRows : cityFallbackRows);
return sortRowsByUserTime(
mergeScanRowsWithCityFallbackRows(scanRows, cityFallbackRows),
);
},
[cityFallbackRows, terminalData?.rows],
);
@@ -1,4 +1,7 @@
import { cityListItemsToScanRows } from "@/components/dashboard/scan-terminal/city-fallback-rows";
import {
cityListItemsToScanRows,
mergeScanRowsWithCityFallbackRows,
} from "@/components/dashboard/scan-terminal/city-fallback-rows";
import type { CityListItem } from "@/lib/dashboard-types";
function assert(condition: unknown, message: string) {
@@ -49,6 +52,68 @@ export function runTests() {
assert(rows[0].temp_symbol === "°C", "celsius cities should use °C");
assert(rows[1].trading_region === "north_america", "known cities should keep their configured product region");
assert(rows[1].temp_symbol === "°F", "fahrenheit cities should use °F");
const scanRows = [
{
id: "scan:paris",
city: "paris",
city_display_name: "Paris",
current_temp: 31,
deb_prediction: 30.5,
temp_symbol: "°C",
},
] as any[];
const fallbackRows = cityListItemsToScanRows([
{
airport: "Paris Le Bourget",
display_name: "Paris",
icao: "LFPB",
lat: 48.97,
lon: 2.44,
name: "paris",
risk_level: "medium",
temp_unit: "celsius",
utc_offset_seconds: 7200,
},
{
airport: "Munich Airport",
display_name: "Munich",
icao: "EDDM",
lat: 48.35,
lon: 11.78,
name: "munich",
risk_level: "medium",
temp_unit: "celsius",
utc_offset_seconds: 7200,
},
{
airport: "Cape Town International",
display_name: "Cape Town",
icao: "FACT",
lat: -33.97,
lon: 18.6,
name: "cape town",
risk_level: "medium",
temp_unit: "celsius",
utc_offset_seconds: 7200,
},
]);
const merged = mergeScanRowsWithCityFallbackRows(scanRows, fallbackRows);
const mergedCities = merged.map((row) => row.city);
assert(merged.length === 3, "city selector data should include scan rows plus missing registry cities");
assert(mergedCities.includes("paris"), "merged rows should keep scan city");
assert(mergedCities.includes("munich"), "merged rows should include missing registry city");
assert(mergedCities.includes("cape town"), "merged rows should include another missing registry city");
assert(
merged.filter((row) => row.city === "paris").length === 1,
"merged rows should not duplicate cities already present in scan rows",
);
assert(
merged.find((row) => row.city === "paris")?.current_temp === 31,
"scan rows should win over fallback rows for cities already present",
);
assert(
dashboardSource.includes("cityListItemsToScanRows") &&
dashboardSource.includes("/api/cities") &&
@@ -61,3 +61,25 @@ export function cityListItemsToScanRows(cities: CityListItem[]): ScanOpportunity
};
});
}
export function mergeScanRowsWithCityFallbackRows(
scanRows: ScanOpportunityRow[],
fallbackRows: ScanOpportunityRow[],
): ScanOpportunityRow[] {
const merged = [...(scanRows || [])];
const seen = new Set<string>();
for (const row of merged) {
const key = normalizeCityKey(row.city || row.city_display_name || row.display_name || "");
if (key) seen.add(key);
}
for (const row of fallbackRows || []) {
const key = normalizeCityKey(row.city || row.city_display_name || row.display_name || "");
if (!key || seen.has(key)) continue;
seen.add(key);
merged.push(row);
}
return merged;
}