86 lines
2.5 KiB
JavaScript
86 lines
2.5 KiB
JavaScript
import { useEffect, useRef, useCallback, useMemo, useState } from "react";
|
|
import useLocation from "~/hooks/useLocation";
|
|
import { defibsActions, useDefibsState } from "~/stores";
|
|
import { getDefibAvailability } from "~/utils/dae/getDefibAvailability";
|
|
|
|
const RADIUS_METERS = 10_000;
|
|
|
|
/**
|
|
* Shared hook: loads defibs near user and exposes location + loading state.
|
|
* The results live in the zustand store so both Liste and Carte tabs share them.
|
|
* By default, only available (open) defibs are returned; toggle showUnavailable to see all.
|
|
*/
|
|
export default function useNearbyDefibs() {
|
|
const { coords, isLastKnown, lastKnownTimestamp } = useLocation();
|
|
const { nearUserDefibs, loadingNearUser, errorNearUser, showUnavailable } =
|
|
useDefibsState([
|
|
"nearUserDefibs",
|
|
"loadingNearUser",
|
|
"errorNearUser",
|
|
"showUnavailable",
|
|
]);
|
|
|
|
const hasLocation =
|
|
coords && coords.latitude !== null && coords.longitude !== null;
|
|
|
|
// Track whether we've already triggered a load for these coords
|
|
const lastLoadedRef = useRef(null);
|
|
const [noLocation, setNoLocation] = useState(false);
|
|
|
|
const loadDefibs = useCallback(async () => {
|
|
if (!hasLocation) {
|
|
return;
|
|
}
|
|
const key = `${coords.latitude.toFixed(4)},${coords.longitude.toFixed(4)}`;
|
|
if (lastLoadedRef.current === key) {
|
|
return; // skip duplicate loads for same position
|
|
}
|
|
lastLoadedRef.current = key;
|
|
await defibsActions.loadNearUser({
|
|
userLonLat: [coords.longitude, coords.latitude],
|
|
radiusMeters: RADIUS_METERS,
|
|
});
|
|
}, [hasLocation, coords]);
|
|
|
|
useEffect(() => {
|
|
if (hasLocation) {
|
|
setNoLocation(false);
|
|
loadDefibs();
|
|
}
|
|
}, [hasLocation, loadDefibs]);
|
|
|
|
// After a timeout, if we still have no location, set the flag
|
|
useEffect(() => {
|
|
if (hasLocation) {
|
|
return;
|
|
}
|
|
const timer = setTimeout(() => {
|
|
if (!hasLocation) {
|
|
setNoLocation(true);
|
|
}
|
|
}, 8000);
|
|
return () => clearTimeout(timer);
|
|
}, [hasLocation]);
|
|
|
|
const filteredDefibs = useMemo(() => {
|
|
if (showUnavailable) return nearUserDefibs;
|
|
return nearUserDefibs.filter((d) => {
|
|
const { status } = getDefibAvailability(d.horaires_std, d.disponible_24h);
|
|
return status === "open";
|
|
});
|
|
}, [nearUserDefibs, showUnavailable]);
|
|
|
|
return {
|
|
defibs: filteredDefibs,
|
|
allDefibs: nearUserDefibs,
|
|
loading: loadingNearUser,
|
|
error: errorNearUser,
|
|
hasLocation,
|
|
noLocation,
|
|
isLastKnown,
|
|
lastKnownTimestamp,
|
|
coords,
|
|
reload: loadDefibs,
|
|
showUnavailable,
|
|
};
|
|
}
|