aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/hooks/useSocket.tsx
blob: ee710b86199146329dafb0afdd227a4788cc823a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"use client";

import { useState, useEffect, useCallback, createContext, useContext, ReactNode } from "react";
import io, { Socket } from "socket.io-client";
import { toast } from "sonner";

interface LocationType {
  latitude: number;
  longitude: number;
  accuracy: number;
  timestamp: number;
}

interface SocketContextType {
  socket: Socket | null;
  isConnected: boolean;
  location: LocationType | null;
  startSharing: (token: string) => void;
  stopSharing: () => void;
  joinLocationView: (token: string) => void;
  updateLocation: (location: LocationType) => void;
}

const SocketContext = createContext<SocketContextType>({
  socket: null,
  isConnected: false,
  location: null,
  startSharing: () => {},
  stopSharing: () => {},
  joinLocationView: () => {},
  updateLocation: () => {},
});

export const SocketProvider = ({ children }: { children: ReactNode }) => {
  const [socket, setSocket] = useState<Socket | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [location, setLocation] = useState<LocationType | null>(null);

  useEffect(() => {
    // Initialize socket connection
    const socketInstance = io(process.env.NEXT_PUBLIC_SOCKET_URL || "http://localhost:3001", {
      transports: ["websocket"],
      autoConnect: true,
    });

    socketInstance.on("connect", () => {
      setIsConnected(true);
      console.log("Connected to socket server");
    });

    socketInstance.on("disconnect", () => {
      setIsConnected(false);
      console.log("Disconnected from socket server");
    });

    socketInstance.on("location-update", (data: LocationType) => {
      setLocation(data);
    });

    socketInstance.on("error", (error: string) => {
      toast.error(error);
    });

    setSocket(socketInstance);

    return () => {
      socketInstance.disconnect();
    };
  }, []);

  const startSharing = useCallback((token: string) => {
    if (socket && isConnected) {
      socket.emit("start-sharing", { token });
      toast.success("Started sharing your location");
    } else {
      toast.error("Socket connection not available");
    }
  }, [socket, isConnected]);

  const stopSharing = useCallback(() => {
    if (socket && isConnected) {
      socket.emit("stop-sharing");
      toast.success("Stopped sharing your location");
    }
  }, [socket, isConnected]);

  const joinLocationView = useCallback((token: string) => {
    if (socket && isConnected) {
      socket.emit("join-location", { token });
    } else {
      // If socket isn't connected yet, we'll attempt to connect when it becomes available
      const checkInterval = setInterval(() => {
        if (socket && isConnected) {
          socket.emit("join-location", { token });
          clearInterval(checkInterval);
        }
      }, 1000);

      // Clean up interval after 10 seconds if still not connected
      setTimeout(() => clearInterval(checkInterval), 10000);
    }
  }, [socket, isConnected]);

  const updateLocation = useCallback((locationData: LocationType) => {
    if (socket && isConnected) {
      socket.emit("update-location", locationData);
    }
  }, [socket, isConnected]);

  return (
    <SocketContext.Provider
      value={{
        socket,
        isConnected,
        location,
        startSharing,
        stopSharing,
        joinLocationView,
        updateLocation,
      }}
    >
      {children}
    </SocketContext.Provider>
  );
};

export const useSocket = () => useContext(SocketContext);