feat: add global weather support
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
This commit is contained in:
@@ -5,7 +5,7 @@ import { ExternalLink, LoaderCircle, LocateFixed, MapPinned, ShieldAlert, X } fr
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useI18n } from "@/lib/i18n";
|
||||
import { fetchReverseLocation } from "@/lib/location-api";
|
||||
import { findNearestSynopStation, type LocatedSynopStation } from "@/lib/location-utils";
|
||||
import { createSelectedLocation, type LocatedSynopStation } from "@/lib/location-utils";
|
||||
import { useWeatherStore } from "@/lib/store";
|
||||
|
||||
const GPS_PROMPT_SEEN_KEY = "wtr:gps-prompt-seen";
|
||||
@@ -39,11 +39,6 @@ export function CurrentLocationControl({ stations }: { stations: LocatedSynopSta
|
||||
setMessage(t("location.gpsUnavailable"));
|
||||
return;
|
||||
}
|
||||
if (!stations.length) {
|
||||
setMessage(t("location.gpsStationsPending"));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLocating(true);
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
async ({ coords }) => {
|
||||
@@ -54,14 +49,16 @@ export function CurrentLocationControl({ stations }: { stations: LocatedSynopSta
|
||||
name: t("location.gpsFallbackName"),
|
||||
province: null,
|
||||
district: null,
|
||||
country: null,
|
||||
countryCode: null,
|
||||
admin1: null,
|
||||
admin2: null,
|
||||
timezone: null,
|
||||
region: "GLOBAL" as const,
|
||||
}));
|
||||
const nearest = findNearestSynopStation({ ...place, latitude, longitude }, stations);
|
||||
if (!nearest) {
|
||||
setMessage(t("location.gpsStationsPending"));
|
||||
return;
|
||||
}
|
||||
selectLocation(nearest);
|
||||
setMessage(t("location.gpsSelected", { location: nearest.name }));
|
||||
const selected = createSelectedLocation({ ...place, latitude, longitude }, stations);
|
||||
selectLocation(selected);
|
||||
setMessage(t("location.gpsSelected", { location: selected.name }));
|
||||
} catch {
|
||||
setMessage(t("location.gpsPositionUnavailable"));
|
||||
} finally {
|
||||
@@ -89,13 +86,13 @@ export function CurrentLocationControl({ stations }: { stations: LocatedSynopSta
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.isSecureContext || !stations.length || autoLocated.current || !navigator.permissions?.query) return;
|
||||
if (!window.isSecureContext || autoLocated.current || !navigator.permissions?.query) return;
|
||||
navigator.permissions.query({ name: "geolocation" }).then((permission) => {
|
||||
if (permission.state !== "granted" || autoLocated.current) return;
|
||||
autoLocated.current = true;
|
||||
locate();
|
||||
}).catch(() => undefined);
|
||||
}, [locate, stations.length]);
|
||||
}, [locate]);
|
||||
|
||||
return (
|
||||
<div className="mt-3 space-y-2">
|
||||
@@ -108,7 +105,7 @@ export function CurrentLocationControl({ stations }: { stations: LocatedSynopSta
|
||||
<p className="mt-1 text-xs leading-5 text-muted">{t("location.gpsPromptDescription")}</p>
|
||||
{!isSecureContext && <p className="mt-2 flex items-start gap-1.5 text-xs leading-5 text-warning"><ShieldAlert className="mt-0.5 size-3.5 shrink-0" />{t("location.gpsSecureContext")}</p>}
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
<Button type="button" onClick={locate} disabled={isLocating || !stations.length}>
|
||||
<Button type="button" onClick={locate} disabled={isLocating}>
|
||||
{isLocating ? <LoaderCircle className="size-4 animate-spin" /> : <LocateFixed className="size-4" />}
|
||||
{isLocating ? t("location.gpsLocating") : t("location.gpsAllow")}
|
||||
</Button>
|
||||
@@ -120,7 +117,7 @@ export function CurrentLocationControl({ stations }: { stations: LocatedSynopSta
|
||||
)}
|
||||
{!showPrompt && (
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||
<Button type="button" variant="glass" onClick={locate} disabled={isLocating || !stations.length}>
|
||||
<Button type="button" variant="glass" onClick={locate} disabled={isLocating}>
|
||||
{isLocating ? <LoaderCircle className="size-4 animate-spin" /> : <LocateFixed className="size-4" />}
|
||||
{isLocating ? t("location.gpsLocating") : t("location.gpsUse")}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user