Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DavidCevallos15/Crucidrive---APP/llms.txt

Use this file to discover all available pages before exploring further.

useSocket manages a single Socket.io connection per authenticated session. The socket auto-connects when a valid session is present in the Zustand store and disconnects automatically on logout. It exposes typed emit helpers for all client-to-server events — GPS location updates, sector subscriptions, and chat messages — plus a generic onEvent subscriber for server-to-client events.

Typed event interfaces

The hook is fully typed using two interfaces that mirror the server’s event contract:
/** Events the client can emit to the server */
interface ClientEvents {
  join_sector:     (data: { sectorId: string }) => void;
  update_location: (data: {
    sectorId: string;
    coords: { lat: number; lng: number };
    estado: string;
  }) => void;
  join_chat:    (data: { threadId: string }) => void;
  send_message: (data: { threadId: string; content: string }) => void;
}

/** Events the server can emit to the client */
interface ServerEvents {
  location_updated: (data: {
    conductorId: string;
    nombre:      string;
    coords:      { lat: number; lng: number };
    estado:      string;
  }) => void;
  message_received: (data: {
    id:         string;
    thread_id:  string;
    sender_id:  string;
    content:    string;
    created_at: string;
    perfiles:   { nombre: string; rol: string };
  }) => void;
  error_message: (message: string) => void;
}

Return values

PropertyTypeDescription
socketSocket | nullRaw Socket.io socket instance — use for advanced event handling
isConnectedbooleantrue when the socket is currently connected to the server
joinSector(sectorId)(sectorId: string) => voidEmits join_sector — subscribes to GPS updates for a sector
updateLocation(sectorId, coords, estado)(sectorId: string, coords: { lat: number; lng: number }, estado: string) => voidEmits update_location — drivers only
joinChat(threadId)(threadId: string) => voidEmits join_chat — subscribes to a ride’s chat room
sendMessage(threadId, content)(threadId: string, content: string) => voidEmits send_message to a chat thread
onEvent(event, handler)<K extends keyof ServerEvents>(event: K, handler: ServerEvents[K]) => () => voidRegisters a typed server-event listener; returns an unsubscribe function

Connection lifecycle

The hook stores the socket in a useRef so it persists across renders without triggering re-renders. A single useEffect keyed to session?.access_token drives the entire lifecycle:
useEffect(() => {
  const token = session?.access_token;

  if (!token) {
    // No active session — disconnect if a stale socket exists
    if (socketRef.current?.connected) {
      socketRef.current.disconnect();
    }
    return;
  }

  // Create a new authenticated connection
  const socket = io(SOCKET_CONFIG.url, {
    auth: { token },
    reconnection:        SOCKET_CONFIG.reconnection,
    reconnectionAttempts: SOCKET_CONFIG.reconnectionAttempts,
    reconnectionDelay:   SOCKET_CONFIG.reconnectionDelay,
    timeout:             SOCKET_CONFIG.connectionTimeout,
    transports: ['websocket'],
  });

  socketRef.current = socket;

  // Cleanup on unmount or token change
  return () => {
    socket.removeAllListeners();
    socket.disconnect();
    socketRef.current = null;
  };
}, [session?.access_token]);
When a user logs out, useSupabaseAuth.signOut() clears the Zustand session, session?.access_token becomes undefined, and the effect cleanup fires — disconnecting the socket cleanly.

GPS tracking (driver)

const { joinSector, updateLocation } = useSocket();

useEffect(() => {
  // Subscribe to the sector to broadcast presence
  joinSector('playa');
}, []);

// Called on a setInterval every LOCATION_CONFIG.driverUpdateIntervalMs (5 000 ms)
const pushLocation = () => {
  updateLocation(
    'playa',
    { lat: -1.0470, lng: -80.5485 },
    'disponible'
  );
};
updateLocation is validated server-side against the user’s role. If a non-conductor account emits update_location, the server rejects it and returns an error_message event with a descriptive string. Listen for error_message during development to catch this quickly.

Chat usage (passenger)

const { joinChat, sendMessage, onEvent } = useSocket();

useEffect(() => {
  joinChat(threadId);

  // Subscribe to incoming messages
  const unsub = onEvent('message_received', (msg) => {
    setMessages((prev) => [...prev, msg]);
  });

  return unsub; // automatically unregisters the listener on unmount
}, [threadId]);

// Send a message on button press
const handleSend = (text: string) => {
  sendMessage(threadId, text);
};
Always call onEvent inside a useEffect and return the unsubscribe function it provides. Because socketRef.current can be replaced when the session token rotates, returning the cleanup function ensures the old listener is removed before a new one is attached — preventing duplicate message handlers and memory leaks.

Build docs developers (and LLMs) love