mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
- i18n scanner: lastError sink, no false sinks on defaults and ternaries - shared src/i18n/marker.js for modules that only mark strings - wind field messages move to wind/fields.js; CITY_POIS imports from cityPois.js - drop review IDs, change history and stale references from comments and docs Co-Authored-By: Claude Opus 5.5 <[email protected]>
66 lines
2.7 KiB
JavaScript
66 lines
2.7 KiB
JavaScript
import { msg } from '../i18n/marker.js';
|
|
|
|
// layers/installations/controls.js translates describeInstallationFeedback().
|
|
const REASONS = Object.freeze({
|
|
rate_limited: msg('Overpass rate-limited'),
|
|
timeout: msg('Overpass timed out'),
|
|
query_failed: msg('Overpass could not complete the query'),
|
|
tiles_unavailable: msg('Map tiles temporarily unavailable'),
|
|
names_unavailable: msg('Mapped names temporarily unavailable'),
|
|
});
|
|
const FALLBACK_REASON = msg('Overpass temporarily unavailable');
|
|
|
|
/**
|
|
* Mapped-site availability as a message to render, without claiming an
|
|
* unobserved overload. Either `{ text, reason?, seconds? }`, where `text` is
|
|
* English (`{reason}` / `{seconds}` placeholders, `reason` English too), or
|
|
* `{ count, km }` for a found-sites count (`km` is null for the view).
|
|
* @param {object} [stats]
|
|
* @param {number} [now]
|
|
* @returns {{text: string, reason?: string, seconds?: number}|{count: number, km: ?number}}
|
|
*/
|
|
export function describeInstallationFeedback(stats = {}, now = Date.now()) {
|
|
const reason = REASONS[stats.failureReason] || FALLBACK_REASON;
|
|
if (stats.loading)
|
|
return {
|
|
text: stats.retrying
|
|
? msg('Retrying mapped sites…')
|
|
: msg('Fetching mapped sites…'),
|
|
};
|
|
if (stats.retryAt > 0) {
|
|
const seconds = Math.max(0, Math.ceil((stats.retryAt - now) / 1000));
|
|
return seconds
|
|
? { text: msg('{reason} — retrying in {seconds}s'), reason, seconds }
|
|
: { text: msg('{reason} — retry pending'), reason };
|
|
}
|
|
if (stats.status === 'unavailable') return { text: reason };
|
|
if (stats.status === 'zoom-in')
|
|
return { text: msg('Zoom in to search mapped installations') };
|
|
if (stats.stale) return { text: msg('Showing cached mapped sites') };
|
|
if (stats.status === 'idle') return { text: msg('Mapped sites not loaded') };
|
|
// With a count, say what was found and where; an empty area is not "loaded".
|
|
if (Number.isFinite(stats.count)) {
|
|
const km =
|
|
stats.coverage?.kind === 'subject' &&
|
|
Number.isFinite(stats.coverage.radiusM)
|
|
? Math.round(stats.coverage.radiusM / 1000)
|
|
: null;
|
|
return { count: stats.count, km: km || null };
|
|
}
|
|
return { text: msg('Mapped sites loaded') };
|
|
}
|
|
|
|
/** Explain mapped-site availability in English. */
|
|
export function installationFeedback(stats = {}, now = Date.now()) {
|
|
const feedback = describeInstallationFeedback(stats, now);
|
|
if (feedback.text !== undefined)
|
|
return feedback.text
|
|
.replace('{reason}', feedback.reason)
|
|
.replace('{seconds}', feedback.seconds);
|
|
const where = feedback.km
|
|
? ` within ${feedback.km} km of the contact`
|
|
: ' in view';
|
|
if (feedback.count === 0) return `No mapped sites${where}`;
|
|
return `${feedback.count} mapped site${feedback.count === 1 ? '' : 's'}${where}`;
|
|
}
|