sdasdfasfd
This commit is contained in:
@@ -356,6 +356,7 @@ const PropertyDetail = () => {
|
|||||||
const [gpsFixAgeMs, setGpsFixAgeMs] = useState(null);
|
const [gpsFixAgeMs, setGpsFixAgeMs] = useState(null);
|
||||||
const [gpsReady, setGpsReady] = useState(false);
|
const [gpsReady, setGpsReady] = useState(false);
|
||||||
const [warmWatchId, setWarmWatchId] = useState(null);
|
const [warmWatchId, setWarmWatchId] = useState(null);
|
||||||
|
const [warmPrimed, setWarmPrimed] = useState(false);
|
||||||
const [isSnapPreview, setIsSnapPreview] = useState(false);
|
const [isSnapPreview, setIsSnapPreview] = useState(false);
|
||||||
const [showAddMenu, setShowAddMenu] = useState(false);
|
const [showAddMenu, setShowAddMenu] = useState(false);
|
||||||
// Modal picker to ensure options show reliably on mobile
|
// Modal picker to ensure options show reliably on mobile
|
||||||
@@ -381,10 +382,10 @@ const PropertyDetail = () => {
|
|||||||
fetchPropertyDetails();
|
fetchPropertyDetails();
|
||||||
}, [id]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [id]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
// Start a passive GPS watch when the page mounts to warm up the fix
|
// Helper: ensure a passive watch is running
|
||||||
useEffect(() => {
|
const ensureWarmWatch = () => {
|
||||||
if (!navigator.geolocation) return;
|
if (!navigator.geolocation) return;
|
||||||
if (warmWatchId) return; // already running
|
if (warmWatchId) return;
|
||||||
const id = navigator.geolocation.watchPosition(
|
const id = navigator.geolocation.watchPosition(
|
||||||
(pos) => {
|
(pos) => {
|
||||||
const { latitude, longitude, accuracy } = pos.coords;
|
const { latitude, longitude, accuracy } = pos.coords;
|
||||||
@@ -396,13 +397,49 @@ const PropertyDetail = () => {
|
|||||||
{ enableHighAccuracy: true, maximumAge: 1000, timeout: 20000 }
|
{ enableHighAccuracy: true, maximumAge: 1000, timeout: 20000 }
|
||||||
);
|
);
|
||||||
setWarmWatchId(id);
|
setWarmWatchId(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start warm watch on mount
|
||||||
|
useEffect(() => {
|
||||||
|
ensureWarmWatch();
|
||||||
return () => {
|
return () => {
|
||||||
try { if (id) navigator.geolocation.clearWatch(id); } catch {}
|
try { if (warmWatchId) navigator.geolocation.clearWatch(warmWatchId); } catch {}
|
||||||
setWarmWatchId(null);
|
setWarmWatchId(null);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// On first user interaction, trigger a one-time getCurrentPosition to prompt permission on iOS
|
||||||
|
useEffect(() => {
|
||||||
|
if (!navigator.geolocation) return;
|
||||||
|
if (warmPrimed) return;
|
||||||
|
const handler = () => {
|
||||||
|
navigator.geolocation.getCurrentPosition(
|
||||||
|
(pos) => {
|
||||||
|
addSampleAndSmooth(pos.coords.latitude, pos.coords.longitude, pos.coords.accuracy);
|
||||||
|
ensureWarmWatch();
|
||||||
|
setWarmPrimed(true);
|
||||||
|
document.removeEventListener('click', handler);
|
||||||
|
document.removeEventListener('touchstart', handler);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// even on error, try to start warm watch; user may grant later
|
||||||
|
ensureWarmWatch();
|
||||||
|
setWarmPrimed(true);
|
||||||
|
document.removeEventListener('click', handler);
|
||||||
|
document.removeEventListener('touchstart', handler);
|
||||||
|
},
|
||||||
|
{ enableHighAccuracy: true, maximumAge: 1000, timeout: 8000 }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
document.addEventListener('click', handler, { once: true });
|
||||||
|
document.addEventListener('touchstart', handler, { once: true });
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', handler);
|
||||||
|
document.removeEventListener('touchstart', handler);
|
||||||
|
};
|
||||||
|
}, [warmPrimed]);
|
||||||
|
|
||||||
// Load recent history when property is available
|
// Load recent history when property is available
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!property?.id) return;
|
if (!property?.id) return;
|
||||||
@@ -1085,6 +1122,15 @@ const PropertyDetail = () => {
|
|||||||
}}>Pause</button>
|
}}>Pause</button>
|
||||||
)}
|
)}
|
||||||
<button className="btn-secondary" onClick={() => { if (gpsWatchId) { navigator.geolocation.clearWatch(gpsWatchId); setGpsWatchId(null);} setIsTracing(false); clearGpsPoints(); }} disabled={gpsTracePoints.length===0}>Clear</button>
|
<button className="btn-secondary" onClick={() => { if (gpsWatchId) { navigator.geolocation.clearWatch(gpsWatchId); setGpsWatchId(null);} setIsTracing(false); clearGpsPoints(); }} disabled={gpsTracePoints.length===0}>Clear</button>
|
||||||
|
<button className="btn-secondary" onClick={() => {
|
||||||
|
if (!window.confirm('Cancel GPS trace? Unsaved points will be lost.')) return;
|
||||||
|
if (gpsWatchId) { navigator.geolocation.clearWatch(gpsWatchId); setGpsWatchId(null); }
|
||||||
|
setIsTracing(false);
|
||||||
|
setIsGPSTraceMode(false);
|
||||||
|
setIsGPSPointsMode(false);
|
||||||
|
setIsDrawing(false);
|
||||||
|
clearGpsPoints();
|
||||||
|
}}>Cancel</button>
|
||||||
<button className="btn-primary" onClick={completeTracing} disabled={gpsTracePoints.length < 3}>Complete Boundary</button>
|
<button className="btn-primary" onClick={completeTracing} disabled={gpsTracePoints.length < 3}>Complete Boundary</button>
|
||||||
{isSnapPreview && <span className="text-xs text-amber-700 bg-amber-100 px-2 py-1 rounded">Snap to start available</span>}
|
{isSnapPreview && <span className="text-xs text-amber-700 bg-amber-100 px-2 py-1 rounded">Snap to start available</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user