Fix city selector fallback coverage
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user