feat: Implement connected user API and integrate chat and report components
- Added API routes for fetching connected users, keywords, missions, and stations. - Created a new QueryProvider component for managing query states and socket events. - Introduced connection stores for dispatch and pilot, managing socket connections and states. - Updated Prisma schema for connected aircraft model. - Enhanced UI with toast notifications for status updates and chat interactions. - Implemented query functions for fetching connected users and keywords with error handling.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import { socket } from "../dispatch/socket";
|
||||
import { dispatchSocket } from "../../dispatch/socket";
|
||||
|
||||
interface ConnectionStore {
|
||||
status: "connected" | "disconnected" | "connecting" | "error";
|
||||
@@ -20,11 +20,11 @@ export const useDispatchConnectionStore = create<ConnectionStore>((set) => ({
|
||||
connect: async (uid, selectedZone, logoffTime) =>
|
||||
new Promise((resolve) => {
|
||||
set({ status: "connecting", message: "" });
|
||||
socket.auth = { uid };
|
||||
dispatchSocket.auth = { uid };
|
||||
set({ selectedZone });
|
||||
socket.connect();
|
||||
socket.once("connect", () => {
|
||||
socket.emit("connect-dispatch", {
|
||||
dispatchSocket.connect();
|
||||
dispatchSocket.once("connect", () => {
|
||||
dispatchSocket.emit("connect-dispatch", {
|
||||
logoffTime,
|
||||
selectedZone,
|
||||
});
|
||||
@@ -32,26 +32,26 @@ export const useDispatchConnectionStore = create<ConnectionStore>((set) => ({
|
||||
});
|
||||
}),
|
||||
disconnect: () => {
|
||||
socket.disconnect();
|
||||
dispatchSocket.disconnect();
|
||||
},
|
||||
}));
|
||||
|
||||
socket.on("connect", () => {
|
||||
dispatchSocket.on("connect", () => {
|
||||
useDispatchConnectionStore.setState({ status: "connected", message: "" });
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
dispatchSocket.on("connect_error", (err) => {
|
||||
useDispatchConnectionStore.setState({
|
||||
status: "error",
|
||||
message: err.message,
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
dispatchSocket.on("disconnect", () => {
|
||||
useDispatchConnectionStore.setState({ status: "disconnected", message: "" });
|
||||
});
|
||||
|
||||
socket.on("force-disconnect", (reason: string) => {
|
||||
dispatchSocket.on("force-disconnect", (reason: string) => {
|
||||
console.log("force-disconnect", reason);
|
||||
useDispatchConnectionStore.setState({
|
||||
status: "disconnected",
|
||||
@@ -1,6 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { ChatMessage } from "@repo/db";
|
||||
import { socket } from "dispatch/socket";
|
||||
import { dispatchSocket } from "dispatch/socket";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
|
||||
interface ChatStore {
|
||||
reportTabOpen: boolean;
|
||||
@@ -33,7 +34,7 @@ export const useLeftMenuStore = create<ChatStore>((set, get) => ({
|
||||
chats: {},
|
||||
sendMessage: (userId: string, message: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
socket.emit(
|
||||
dispatchSocket.emit(
|
||||
"send-message",
|
||||
{ userId, message },
|
||||
({ error }: { error?: string }) => {
|
||||
@@ -96,7 +97,16 @@ export const useLeftMenuStore = create<ChatStore>((set, get) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
socket.on(
|
||||
dispatchSocket.on(
|
||||
"chat-message",
|
||||
({ userId, message }: { userId: string; message: ChatMessage }) => {
|
||||
const store = useLeftMenuStore.getState();
|
||||
console.log("chat-message", userId, message);
|
||||
// Update the chat store with the new message
|
||||
store.addMessage(userId, message);
|
||||
},
|
||||
);
|
||||
pilotSocket.on(
|
||||
"chat-message",
|
||||
({ userId, message }: { userId: string; message: ChatMessage }) => {
|
||||
const store = useLeftMenuStore.getState();
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import { Mission, Prisma } from "@repo/db";
|
||||
import { MissionOptionalDefaults } from "@repo/db/zod";
|
||||
import { serverApi } from "helpers/axios";
|
||||
import { create } from "zustand";
|
||||
import { toast } from "react-hot-toast";
|
||||
import axios from "axios";
|
||||
|
||||
interface MissionStore {
|
||||
missions: Mission[];
|
||||
setMissions: (missions: Mission[]) => void;
|
||||
getMissions: () => Promise<undefined>;
|
||||
createMission: (mission: MissionOptionalDefaults) => Promise<Mission>;
|
||||
deleteMission: (id: number) => Promise<void>;
|
||||
editMission: (id: number, mission: Partial<Mission>) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useMissionsStore = create<MissionStore>((set) => ({
|
||||
missions: [],
|
||||
setMissions: (missions) => set({ missions }),
|
||||
createMission: async (mission) => {
|
||||
const { data } = await serverApi.put<Mission>("/mission", mission);
|
||||
|
||||
set((state) => ({ missions: [...state.missions, data] }));
|
||||
return data;
|
||||
},
|
||||
editMission: async (id, mission) => {
|
||||
const { data, status } = await serverApi.patch<Mission>(
|
||||
`/mission/${id}`,
|
||||
mission,
|
||||
);
|
||||
if (status.toString().startsWith("2") && data) {
|
||||
set((state) => ({
|
||||
missions: state.missions.map((m) => (m.id === id ? data : m)),
|
||||
}));
|
||||
toast.success("Mission updated successfully");
|
||||
} else {
|
||||
toast.error("Failed to update mission");
|
||||
}
|
||||
},
|
||||
deleteMission: async (id) => {
|
||||
serverApi
|
||||
.delete(`/mission/${id}`)
|
||||
.then((res) => {
|
||||
if (res.status.toString().startsWith("2")) {
|
||||
set((state) => ({
|
||||
missions: state.missions.filter((mission) => mission.id !== id),
|
||||
}));
|
||||
toast.success("Mission deleted successfully");
|
||||
} else {
|
||||
toast.error("Failed to delete mission");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error("Failed to delete mission");
|
||||
});
|
||||
},
|
||||
getMissions: async () => {
|
||||
const { data } = await serverApi.post<Mission[]>("/mission", {
|
||||
filter: {
|
||||
OR: [{ state: "draft" }, { state: "running" }],
|
||||
} as Prisma.MissionWhereInput,
|
||||
});
|
||||
set({ missions: data });
|
||||
return undefined;
|
||||
},
|
||||
}));
|
||||
|
||||
useMissionsStore
|
||||
.getState()
|
||||
.getMissions()
|
||||
.then(() => {
|
||||
console.log("Missions loaded");
|
||||
});
|
||||
63
apps/dispatch/app/_store/pilot/connectionStore.ts
Normal file
63
apps/dispatch/app/_store/pilot/connectionStore.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { create } from "zustand";
|
||||
import { dispatchSocket } from "../../dispatch/socket";
|
||||
import { Station } from "@repo/db";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
|
||||
interface ConnectionStore {
|
||||
status: "connected" | "disconnected" | "connecting" | "error";
|
||||
message: string;
|
||||
selectedStation: Station | null;
|
||||
connect: (
|
||||
uid: string,
|
||||
stationId: string,
|
||||
logoffTime: string,
|
||||
station: Station,
|
||||
) => Promise<void>;
|
||||
disconnect: () => void;
|
||||
}
|
||||
|
||||
export const useDispatchConnectionStore = create<ConnectionStore>((set) => ({
|
||||
status: "disconnected",
|
||||
message: "",
|
||||
selectedStation: null,
|
||||
connect: async (uid, stationId, logoffTime, station) =>
|
||||
new Promise((resolve) => {
|
||||
set({ status: "connecting", message: "", selectedStation: station });
|
||||
dispatchSocket.auth = { uid };
|
||||
dispatchSocket.connect();
|
||||
dispatchSocket.once("connect", () => {
|
||||
dispatchSocket.emit("connect-pilot", {
|
||||
logoffTime,
|
||||
stationId,
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
}),
|
||||
disconnect: () => {
|
||||
dispatchSocket.disconnect();
|
||||
},
|
||||
}));
|
||||
|
||||
dispatchSocket.on("connect", () => {
|
||||
pilotSocket.disconnect();
|
||||
useDispatchConnectionStore.setState({ status: "connected", message: "" });
|
||||
});
|
||||
|
||||
dispatchSocket.on("connect_error", (err) => {
|
||||
useDispatchConnectionStore.setState({
|
||||
status: "error",
|
||||
message: err.message,
|
||||
});
|
||||
});
|
||||
|
||||
dispatchSocket.on("disconnect", () => {
|
||||
useDispatchConnectionStore.setState({ status: "disconnected", message: "" });
|
||||
});
|
||||
|
||||
dispatchSocket.on("force-disconnect", (reason: string) => {
|
||||
console.log("force-disconnect", reason);
|
||||
useDispatchConnectionStore.setState({
|
||||
status: "disconnected",
|
||||
message: reason,
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { socket } from "../dispatch/socket";
|
||||
|
||||
export const stationStore = create((set) => {
|
||||
export const useStationStore = create((set) => {
|
||||
return {
|
||||
stations: [],
|
||||
setStations: (stations: any) => set({ stations }),
|
||||
|
||||
Reference in New Issue
Block a user