136 lines
3.8 KiB
TypeScript
136 lines
3.8 KiB
TypeScript
|
import React, { useEffect, useState } from "react";
|
|||
|
import {
|
|||
|
IonPage,
|
|||
|
IonContent,
|
|||
|
IonSpinner,
|
|||
|
IonText,
|
|||
|
IonButton,
|
|||
|
} from "@ionic/react";
|
|||
|
import { GEO_ACCESS_API } from "../api_endpoints";
|
|||
|
|
|||
|
const MAX_ACCEPTABLE_ACCURACY = 100; // metri
|
|||
|
|
|||
|
const LocationAccessChecker: React.FC<{
|
|||
|
onAccessChecked?: (granted: boolean) => void;
|
|||
|
}> = ({ onAccessChecked }) => {
|
|||
|
const [loading, setLoading] = useState(true);
|
|||
|
const [accessGranted, setAccessGranted] = useState<boolean | null>(null);
|
|||
|
const [error, setError] = useState<string | null>(null);
|
|||
|
const [accuracy, setAccuracy] = useState<number | null>(null);
|
|||
|
|
|||
|
useEffect(() => {
|
|||
|
const checkLocationAccess = async () => {
|
|||
|
if (!navigator.geolocation) {
|
|||
|
setError("Geolocation non supportata dal browser");
|
|||
|
setAccessGranted(false);
|
|||
|
setLoading(false);
|
|||
|
onAccessChecked?.(false);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
navigator.geolocation.getCurrentPosition(
|
|||
|
async (position) => {
|
|||
|
const latitude = position.coords.latitude;
|
|||
|
const longitude = position.coords.longitude;
|
|||
|
const positionAccuracy = position.coords.accuracy;
|
|||
|
|
|||
|
console.log("Lat:", latitude);
|
|||
|
console.log("Lng:", longitude);
|
|||
|
console.log("Accuracy (m):", positionAccuracy);
|
|||
|
setAccuracy(positionAccuracy);
|
|||
|
|
|||
|
if (positionAccuracy > MAX_ACCEPTABLE_ACCURACY) {
|
|||
|
setError(
|
|||
|
`Precisione troppo bassa: ${positionAccuracy.toFixed(1)} metri`
|
|||
|
);
|
|||
|
setAccessGranted(false);
|
|||
|
setLoading(false);
|
|||
|
onAccessChecked?.(false);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const coordinates = {
|
|||
|
coords: [latitude, longitude],
|
|||
|
};
|
|||
|
|
|||
|
try {
|
|||
|
const response = await fetch(GEO_ACCESS_API, {
|
|||
|
method: "POST",
|
|||
|
headers: { "Content-Type": "application/json" },
|
|||
|
body: JSON.stringify(coordinates),
|
|||
|
});
|
|||
|
|
|||
|
if (!response.ok) {
|
|||
|
throw new Error("Errore nella risposta dal server");
|
|||
|
}
|
|||
|
|
|||
|
const data = await response.json();
|
|||
|
|
|||
|
if (data.success === true) {
|
|||
|
setAccessGranted(true);
|
|||
|
onAccessChecked?.(true);
|
|||
|
} else {
|
|||
|
setAccessGranted(false);
|
|||
|
onAccessChecked?.(false);
|
|||
|
}
|
|||
|
} catch (e) {
|
|||
|
setError("Errore di rete o server");
|
|||
|
setAccessGranted(false);
|
|||
|
onAccessChecked?.(false);
|
|||
|
} finally {
|
|||
|
setLoading(false);
|
|||
|
}
|
|||
|
},
|
|||
|
(err) => {
|
|||
|
setError(`Errore geolocalizzazione: ${err.message}`);
|
|||
|
setAccessGranted(false);
|
|||
|
setLoading(false);
|
|||
|
onAccessChecked?.(false);
|
|||
|
},
|
|||
|
{
|
|||
|
enableHighAccuracy: true,
|
|||
|
timeout: 10000,
|
|||
|
maximumAge: 60000,
|
|||
|
}
|
|||
|
);
|
|||
|
};
|
|||
|
|
|||
|
checkLocationAccess();
|
|||
|
}, [onAccessChecked]);
|
|||
|
|
|||
|
if (loading) {
|
|||
|
return (
|
|||
|
<IonPage>
|
|||
|
<IonContent className="ion-padding" fullscreen>
|
|||
|
<IonSpinner name="crescent" />
|
|||
|
<IonText>Verifica posizione in corso...</IonText>
|
|||
|
</IonContent>
|
|||
|
</IonPage>
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (accessGranted === false) {
|
|||
|
return (
|
|||
|
<IonPage>
|
|||
|
<IonContent className="ion-padding" fullscreen>
|
|||
|
<IonText color="danger">
|
|||
|
<h2>Accesso non consentito</h2>
|
|||
|
<p>La tua posizione non permette l’uso dell’app.</p>
|
|||
|
{error && <p>Errore: {error}</p>}
|
|||
|
{accuracy !== null && (
|
|||
|
<p>Precisione posizione: {accuracy.toFixed(1)} metri</p>
|
|||
|
)}
|
|||
|
</IonText>
|
|||
|
<IonButton onClick={() => window.location.reload()}>
|
|||
|
Riprova
|
|||
|
</IonButton>
|
|||
|
</IonContent>
|
|||
|
</IonPage>
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return null; // accesso consentito, niente da mostrare
|
|||
|
};
|
|||
|
|
|||
|
export default LocationAccessChecker;
|