mobileapp / src /store /useLocationStore.ts
Antaram Dev Bot
feat: complete ANTARAM.ORG ride-sharing app frontend
5c876be
/**
* Device location state store.
*
* Tracks the user's current GPS location and its human-readable address.
* Updated periodically by a foreground location service.
*/
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
// ─── State Shape ─────────────────────────────────────────────────────────────
interface LocationState {
/** Current GPS coordinates (null when location is unavailable) */
currentLocation: { lat: number; lng: number } | null;
/** Reverse-geocoded address string for the current location */
locationAddress: string | null;
/** Most recent location error, if any */
locationError: string | null;
/** Whether location services are currently tracking */
isTracking: boolean;
}
// ─── Actions ─────────────────────────────────────────────────────────────────
interface LocationActions {
/** Update the current GPS coordinates */
setLocation: (lat: number, lng: number) => void;
/** Update the reverse-geocoded address */
setAddress: (address: string | null) => void;
/** Set a location error */
setError: (error: string | null) => void;
/** Clear all location state (e.g., on logout) */
clearLocation: () => void;
/** Toggle the tracking flag */
setTracking: (value: boolean) => void;
}
// ─── Store ───────────────────────────────────────────────────────────────────
export const useLocationStore = create<LocationState & LocationActions>()(
immer((set) => ({
// Initial state
currentLocation: null,
locationAddress: null,
locationError: null,
isTracking: false,
// Actions
setLocation: (lat, lng) =>
set((state) => {
state.currentLocation = { lat, lng };
state.locationError = null;
}),
setAddress: (address) =>
set((state) => {
state.locationAddress = address;
}),
setError: (error) =>
set((state) => {
state.locationError = error;
}),
clearLocation: () =>
set((state) => {
state.currentLocation = null;
state.locationAddress = null;
state.locationError = null;
state.isTracking = false;
}),
setTracking: (value) =>
set((state) => {
state.isTracking = value;
}),
})),
);
// ─── Selectors ───────────────────────────────────────────────────────────────
export const selectHasLocation = (state: LocationState) =>
state.currentLocation !== null;
export const selectFormattedLocation = (state: LocationState) => {
if (!state.currentLocation) return null;
const { lat, lng } = state.currentLocation;
return {
lat,
lng,
address: state.locationAddress ?? `${lat.toFixed(6)}, ${lng.toFixed(6)}`,
};
};