fix(stats): tick the region-derivation counter live and merge name/code groups
Two issues from the first derived-regions pass:
- The 'Resolving N...' counter only updated when the whole pass finished, so it
looked frozen. fillDerivedRegions now reports progress per pin, the hook ticks
the counter down, and the card refreshes every 5 resolved pins so the numbers
climb while you watch.
- A country could appear twice ('United Kingdom' 1 + 1) when one pin carried a
country_code and another only a name. Learn name->code from pins that have
both and fold name-only pins into the same bucket.
This commit is contained in:
parent
7bad809878
commit
6091a0acd8
3 changed files with 37 additions and 11 deletions
|
|
@ -64,11 +64,20 @@ export function useDeriveRegions(): DeriveRegionsState {
|
|||
|
||||
running.current = true;
|
||||
void (async () => {
|
||||
let lastRefresh = 0;
|
||||
try {
|
||||
await fillDerivedRegions(misses);
|
||||
await fillDerivedRegions(misses, (done, total) => {
|
||||
setPending(Math.max(0, total - done));
|
||||
// Refresh the card as pins resolve (not just at the end) so the numbers
|
||||
// climb while you watch, instead of jumping once.
|
||||
if (done - lastRefresh >= 5) {
|
||||
lastRefresh = done;
|
||||
queryClient.invalidateQueries({ queryKey: ['growth-stats'] });
|
||||
}
|
||||
});
|
||||
const unresolved = misses.filter((c) => !getDerivedRegion(c.lat, c.lng)).length;
|
||||
setPending(unresolved);
|
||||
// Recompute the region card now that more pins have a derived region.
|
||||
// Final recompute now that every pin has (or has failed to get) a region.
|
||||
queryClient.invalidateQueries({ queryKey: ['growth-stats'] });
|
||||
} finally {
|
||||
running.current = false;
|
||||
|
|
|
|||
|
|
@ -315,13 +315,23 @@ export function useGrowthStats() {
|
|||
return null;
|
||||
};
|
||||
const regionEntries = allLocations.map((e) => regionOf(e));
|
||||
// A country can arrive WITH a code (tagged pins) or WITHOUT one (some
|
||||
// geocodes). Learn name→code from whichever pins carry both, so e.g.
|
||||
// "United Kingdom" with no code folds into the "GB" bucket instead of
|
||||
// splitting into two identical rows.
|
||||
const codeByName = new Map<string, string>();
|
||||
for (const region of regionEntries) {
|
||||
if (region?.country && region.code) codeByName.set(region.country.toLowerCase(), region.code);
|
||||
}
|
||||
const regionGroups = (kind: 'country' | 'city') => {
|
||||
const groups = new Map<string, { total: number; labels: Map<string, number> }>();
|
||||
for (const region of regionEntries) {
|
||||
if (!region) continue;
|
||||
const name = kind === 'country' ? region.country : region.city;
|
||||
if (!name) continue;
|
||||
const key = kind === 'country' ? region.code || name.toLowerCase() : name.toLowerCase();
|
||||
const key = kind === 'country'
|
||||
? region.code || codeByName.get(name.toLowerCase()) || name.toLowerCase()
|
||||
: name.toLowerCase();
|
||||
const g = groups.get(key) ?? { total: 0, labels: new Map<string, number>() };
|
||||
g.total += 1;
|
||||
g.labels.set(name, (g.labels.get(name) ?? 0) + 1);
|
||||
|
|
|
|||
|
|
@ -93,19 +93,26 @@ export function coordsOf(event: { tags: string[][] }): { lat: number; lng: numbe
|
|||
*/
|
||||
export async function fillDerivedRegions(
|
||||
coords: Array<{ lat: number; lng: number }>,
|
||||
onProgress?: (done: number, total: number) => void,
|
||||
): Promise<number> {
|
||||
let filled = 0;
|
||||
const seen = new Set<string>();
|
||||
for (let i = 0; i < coords.length; i += 1) {
|
||||
const { lat, lng } = coords[i];
|
||||
if (getDerivedRegion(lat, lng)) continue;
|
||||
const geo = await reverseGeocodeRegions(lat, lng);
|
||||
if (geo.city || geo.country || geo.countryCode) {
|
||||
setDerivedRegion(lat, lng, { city: geo.city, country: geo.country, countryCode: geo.countryCode });
|
||||
filled += 1;
|
||||
}
|
||||
if (i < coords.length - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, GEOCODE_SPACING_MS));
|
||||
const key = regionCoordKey(lat, lng);
|
||||
// Skip duplicates / already-cached pins, but still advance the progress bar.
|
||||
if (!seen.has(key) && !getDerivedRegion(lat, lng)) {
|
||||
seen.add(key);
|
||||
const geo = await reverseGeocodeRegions(lat, lng);
|
||||
if (geo.city || geo.country || geo.countryCode) {
|
||||
setDerivedRegion(lat, lng, { city: geo.city, country: geo.country, countryCode: geo.countryCode });
|
||||
filled += 1;
|
||||
}
|
||||
if (i < coords.length - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, GEOCODE_SPACING_MS));
|
||||
}
|
||||
}
|
||||
onProgress?.(i + 1, coords.length);
|
||||
}
|
||||
return filled;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue