import { getPublicUser, HpgValidationState, MissionSdsLog, NotificationPayload, prisma, User, } from "@repo/db"; import { Router } from "express"; import { io } from "../index"; import { sendAlert } from "modules/mission"; const router: Router = Router(); // Get all missions router.post("/", async (req, res) => { try { const filter = req.body?.filter || {}; const missions = await prisma.mission.findMany({ where: filter, }); res.json(missions); } catch (error) { console.error(error); res.status(500).json({ error: "Failed to fetch missions" }); } }); // Get a single mission by ID router.get("/:id", async (req, res) => { const { id } = req.params; try { const mission = await prisma.mission.findUnique({ where: { id: Number(id) }, }); if (mission) { res.json(mission); } else { res.status(404).json({ error: "Mission not found" }); } } catch (error) { console.error(error); res.status(500).json({ error: "Failed to fetch mission" }); } }); // Create a new mission router.put("/", async (req, res) => { try { const startOfToday = new Date(); startOfToday.setHours(0, 0, 0, 0); const missionsTodayCount = await prisma.mission.count({ where: { createdAt: { gte: startOfToday, }, }, }); const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are zero-based const day = String(date.getDate()).padStart(2, "0"); const publicId = `__${year}${month}${day}${missionsTodayCount ? missionsTodayCount + 1 : 1}`; const newMission = await prisma.mission.create({ data: { ...req.body, publicId, }, }); io.to("dispatchers").emit("new-mission", { newMission }); res.status(201).json(newMission); } catch (error) { res.status(500).json({ error: "Failed to create mission" }); } }); // Update a mission by ID router.patch("/:id", async (req, res) => { const { id } = req.params; try { console.log("Updating mission with ID:", id, req.body); const updatedMission = await prisma.mission.update({ where: { id: Number(id) }, data: req.body, }); io.to("dispatchers").emit("update-mission", updatedMission); res.json(updatedMission); } catch (error) { console.error(error); res.status(500).json({ error: "Failed to update mission" }); } }); // Delete a mission by ID router.delete("/:id", async (req, res) => { const { id } = req.params; try { await prisma.mission.delete({ where: { id: Number(id) }, }); io.to("dispatchers").emit("delete-mission", id); res.status(204).send(); } catch (error) { console.error(error); res.status(500).json({ error: "Failed to delete mission" }); } }); // Send mission router.post("/:id/send-alert", async (req, res) => { const { id } = req.params; const { stationId, vehicleName } = req.body as { stationId?: number; vehicleName?: "RTW" | "POL" | "FW"; }; if (!req.user) { res.status(401).json({ error: "Unauthorized" }); return; } try { if (vehicleName) { const mission = await prisma.mission.findFirst({ where: { id: Number(id), }, select: { missionStationIds: true, }, }); const hpgAircrafts = await prisma.connectedAircraft.findMany({ where: { stationId: { in: mission?.missionStationIds }, logoutTime: null, posH145active: true, }, }); const updateData: any = { missionLog: { push: { type: "alert-log", auto: false, timeStamp: new Date().toISOString(), data: { vehicle: vehicleName, user: getPublicUser(req.user as User, { ignorePrivacy: true }), }, }, }, }; if (vehicleName === "RTW") updateData.hpgAmbulanceState = "DISPATCHED"; if (vehicleName === "FW") updateData.hpgFireEngineState = "DISPATCHED"; if (vehicleName === "POL") updateData.hpgPoliceState = "DISPATCHED"; const newMission = await prisma.mission.update({ where: { id: Number(id) }, data: updateData, }); hpgAircrafts.forEach((aircraft) => { io.to(`desktop:${aircraft.userId}`).emit("hpg-vehicle-update", { missionId: id, ambulanceState: newMission.hpgAmbulanceState, fireEngineState: newMission.hpgFireEngineState, policeState: newMission.hpgPoliceState, }); }); io.to("dispatchers").emit("update-mission", newMission); res.status(200).json({ message: `Rettungsmittel disponiert (${hpgAircrafts.length} Nutzer)`, }); return; } const { connectedAircrafts, mission } = await sendAlert(Number(id), { stationId }, req.user); io.to("dispatchers").emit("update-mission", mission); res.status(200).json({ message: `Einsatz gesendet (${connectedAircrafts.length} Nutzer)`, }); return; } catch (error) { console.error(error); res.status(500).json({ error: "Failed to send mission" }); return; } }); router.post("/send-sds", async (req, res) => { const { sdsMessage, missionId } = req.body as { missionId?: number; sdsMessage: MissionSdsLog; }; io.to(`station:${sdsMessage.data.stationId}`).emit("sds-message", sdsMessage); if (missionId) { const newMission = await prisma.mission.update({ where: { id: Number(missionId), }, data: { missionLog: { push: sdsMessage as any, }, }, }); res.json({ message: "SDS message sent", mission: newMission, }); io.to("dispatchers").emit("update-mission", newMission); } else { res.json({ message: "SDS message sent", }); } }); router.post("/:id/hpg-validation-result", async (req, res) => { try { const missionId = req.params.id; const result = req.body as { state: HpgValidationState; lat: number; lng: number; alertWhenValid?: boolean; userId?: number; }; if (!result) return; const newMission = await prisma.mission.update({ where: { id: Number(missionId) }, data: { // save position of new mission addressLat: result.state === "POSITION_AMANDED" ? result.lat : undefined, addressLng: result.state === "POSITION_AMANDED" ? result.lng : undefined, hpgLocationLat: result.lat, hpgLocationLng: result.lng, hpgValidationState: result.state, }, }); io.to("dispatchers").emit("update-mission", newMission); const noActionRequired = result.state === "VALID"; if (noActionRequired) { io.to(`user:${result.userId}`).emit("notification", { type: "hpg-validation", status: "success", message: `HPG Validierung erfolgreich`, } as NotificationPayload); if (result.alertWhenValid) { if (!req.user) return; sendAlert(Number(missionId), {}, req.user); } } else { io.to(`user:${result.userId}`).emit("notification", { type: "hpg-validation", status: "failed", message: result.state, } as NotificationPayload); } res.json({ message: `HPG Validation result processed`, }); } catch (error) { console.error("Error in HPG validation result:", error); res.status(500).json({ error: "Failed to process HPG validation result" }); return; } }); router.post("/:id/validate-hpg", async (req, res) => { try { const { id } = req.params; const config = req.body as | { alertWhenValid?: boolean; } | undefined; const mission = await prisma.mission.findFirstOrThrow({ where: { id: Number(id), }, }); const activeAircraftinMission = await prisma.connectedAircraft.findFirst({ where: { stationId: { in: mission?.missionStationIds, }, posH145active: true, logoutTime: null, }, include: { Station: true, }, }); const user = await prisma.user.findFirst({ where: { id: activeAircraftinMission?.userId, }, }); const clients = await io.in(`desktop:${activeAircraftinMission?.userId}`).fetchSockets(); if (!clients.length) { res.status(400).json({ error: `Keine Desktop Verbindung für ${user?.publicId} gefunden`, }); return; } const newMission = await prisma.mission.update({ where: { id: Number(id), }, data: { hpgValidationState: "PENDING", }, }); io.to("dispatchers").emit("update-mission", newMission); res.json({ message: "HPG validierung gestartet", }); io.to(`desktop:${activeAircraftinMission?.userId}`).emit("hpg-validation", { missionId: parseInt(id), userId: req.user?.id, alertWhenValid: config?.alertWhenValid || false, }); } catch (error) { console.error(error); res.json({ error: (error as Error).message || "Failed to validate HPG" }); } }); export default router;