mobileapp / src /store /useRideStore.ts
Antaram Dev Bot
feat: complete ANTARAM.ORG ride-sharing app frontend
5c876be
/**
* Active ride & match state store.
*
* Tracks the currently active ride and match (if any), plus
* the search/loading state for ride matching.
*/
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import type { Ride } from '../types/ride';
import type { Match } from '../types/match';
// ─── State Shape ─────────────────────────────────────────────────────────────
interface RideState {
/** The ride the user is currently involved in (as rider or passenger) */
activeRide: Ride | null;
/** The current match for the active ride */
activeMatch: Match | null;
/** Whether the app is currently searching for ride matches */
isSearching: boolean;
/** Error message from the last failed operation */
error: string | null;
}
// ─── Actions ─────────────────────────────────────────────────────────────────
interface RideActions {
/** Set the active ride */
setActiveRide: (ride: Ride | null) => void;
/** Set the active match */
setActiveMatch: (match: Match | null) => void;
/** Toggle the searching state */
setSearching: (value: boolean) => void;
/** Set an error message */
setError: (error: string | null) => void;
/** Clear the active ride, match, and search state */
clearActiveRide: () => void;
/** Update ride status (convenience) */
updateRideStatus: (status: Ride['status']) => void;
/** Update match status (convenience) */
updateMatchStatus: (status: Match['status']) => void;
}
// ─── Store ───────────────────────────────────────────────────────────────────
export const useRideStore = create<RideState & RideActions>()(
immer((set) => ({
// Initial state
activeRide: null,
activeMatch: null,
isSearching: false,
error: null,
// Actions
setActiveRide: (ride) =>
set((state) => {
state.activeRide = ride;
}),
setActiveMatch: (match) =>
set((state) => {
state.activeMatch = match;
}),
setSearching: (value) =>
set((state) => {
state.isSearching = value;
if (value) {
state.error = null;
}
}),
setError: (error) =>
set((state) => {
state.error = error;
}),
clearActiveRide: () =>
set((state) => {
state.activeRide = null;
state.activeMatch = null;
state.isSearching = false;
state.error = null;
}),
updateRideStatus: (status) =>
set((state) => {
if (state.activeRide) {
state.activeRide.status = status;
}
}),
updateMatchStatus: (status) =>
set((state) => {
if (state.activeMatch) {
state.activeMatch.status = status;
}
}),
})),
);
// ─── Selectors ───────────────────────────────────────────────────────────────
export const selectHasActiveRide = (state: RideState) =>
state.activeRide !== null && state.activeMatch !== null;
export const selectRideId = (state: RideState) => state.activeRide?.id ?? null;
export const selectMatchId = (state: RideState) =>
state.activeMatch?.id ?? null;
export const selectRideType = (state: RideState) =>
state.activeRide?.type ?? null;