91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
import { OwlClient, ValidationError, ApiError } from './owlClient';
|
|
import type { ApiStationsNearestStations } from '@owlboard/owlboard-ts';
|
|
|
|
class NearestStationsState {
|
|
list = $state<ApiStationsNearestStations.StationsNearestStations[]>([]);
|
|
currentHash = $state('');
|
|
loading = $state(true);
|
|
error = $state<string | null>(null);
|
|
|
|
private geoConfig: PositionOptions = {
|
|
enableHighAccuracy: false,
|
|
timeout: 30000,
|
|
maximumAge: 120000
|
|
};
|
|
|
|
constructor() {
|
|
if (typeof window !== 'undefined' && 'geolocation' in navigator) {
|
|
this.jumpstart();
|
|
this.initWatcher();
|
|
}
|
|
}
|
|
|
|
private jumpstart() {
|
|
navigator.geolocation.getCurrentPosition(
|
|
(pos) => this.handleUpdate(pos.coords.latitude, pos.coords.longitude),
|
|
(err) => this.handleError(err),
|
|
this.geoConfig
|
|
);
|
|
}
|
|
|
|
private initWatcher() {
|
|
navigator.geolocation.watchPosition(
|
|
(pos) => this.handleUpdate(pos.coords.latitude, pos.coords.longitude),
|
|
(err) => this.handleError(err),
|
|
this.geoConfig
|
|
);
|
|
}
|
|
|
|
private async handleUpdate(lat: number, lon: number) {
|
|
const newHash = OwlClient.stationData.generateGeohash(lat, lon);
|
|
if (newHash !== this.currentHash) {
|
|
this.loading = true;
|
|
|
|
try {
|
|
const result = await OwlClient.stationData.getNearestStations(newHash);
|
|
this.list = result.data;
|
|
this.error = null;
|
|
this.currentHash = newHash;
|
|
} catch (e) {
|
|
this.handleApiError(e);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private handleError(err: GeolocationPositionError) {
|
|
if (err.code === 1) {
|
|
this.error = 'Location access denied by device';
|
|
} else {
|
|
this.error = 'Waiting for GPS signal...';
|
|
}
|
|
}
|
|
|
|
private handleApiError(e: unknown) {
|
|
if (e instanceof ValidationError) {
|
|
this.error = `Request Error: ${e.reason} (Field: ${e.field})`;
|
|
} else if (e instanceof ApiError) {
|
|
switch (e.status) {
|
|
case 404:
|
|
this.error = 'No stations found nearby';
|
|
break;
|
|
case 429:
|
|
this.error = 'Too many requests, will retry';
|
|
break;
|
|
case 500:
|
|
this.error = 'Server Error, will retry';
|
|
break;
|
|
default:
|
|
this.error = `Service error: ${e.code}`;
|
|
}
|
|
} else {
|
|
this.error = 'Connection lost, waiting for signal';
|
|
}
|
|
|
|
console.error('OwlBoard API Error:', e);
|
|
}
|
|
}
|
|
|
|
export const nearestStationsState = new NearestStationsState();
|