import { HpgValidationState, MissionSdsLog, MissionStationLog, NotificationPayload, Prisma, prisma, User, } from "@repo/db"; import { Router } from "express"; import { io } from "../index"; import { sendNtfyMission } from "modules/ntfy"; 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 { 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?: "ambulance" | "police" | "firebrigade"; }; try { if (vehicleName) { const hpgAircrafts = await prisma.connectedAircraft.findMany({ where: { stationId: Number(id), logoutTime: null, posH145active: true, }, }); const newMission = await prisma.mission.update({ where: { id: Number(id), }, data: { hpgAmbulanceState: vehicleName === "ambulance" ? "DISPATCHED" : undefined, hpgFireEngineState: vehicleName === "firebrigade" ? "DISPATCHED" : undefined, hpgPoliceState: vehicleName === "police" ? "DISPATCHED" : undefined, }, }); hpgAircrafts.forEach((aircraft) => { io.to(`desktop:${aircraft.userId}`).emit("hpg-vehicle-update", { missionId: id, vehicleData: { ambulanceState: newMission.hpgAmbulanceState, fireEngineState: newMission.hpgFireEngineState, policeState: newMission.hpgPoliceState, }, }); }); res.status(200).json({ message: `Rettungsmittel disponiert (${hpgAircrafts.length} Nutzer)`, }); io.to("dispatchers").emit("update-mission", newMission); return; } const { connectedAircrafts, mission } = await sendAlert(Number(id), { stationId, }); res.status(200).json({ message: `Einsatz gesendet (${connectedAircrafts.length} Nutzer) `, }); io.to("dispatchers").emit("update-mission", mission); } catch (error) { console.error(error); res.status(500).json({ error: "Failed to send mission" }); } }); router.post("/:id/send-sds", async (req, res) => { const sdsMessage = req.body as MissionSdsLog; const newMission = await prisma.mission.update({ where: { id: Number(req.params.id), }, data: { missionLog: { push: sdsMessage as any, }, }, }); io.to(`station:${sdsMessage.data.stationId}`).emit("sds-message", sdsMessage); res.json({ message: "SDS message sent", mission: newMission, }); io.to("dispatchers").emit("update-mission", newMission); }); 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; } res.json({ message: "HPG validation started", }); io.to(`desktop:${activeAircraftinMission}`).emit( "hpg-validation", { hpgMissionType: mission?.hpgMissionString, lat: mission?.addressLat, lng: mission?.addressLng, }, async (result: { state: HpgValidationState; lat: number; lng: number }) => { console.log("response from user:", result); const newMission = await prisma.mission.update({ where: { id: Number(id) }, data: { // save position of new mission addressLat: result.state === "POSITION_AMANDED" ? result.lat : mission.addressLat, addressLng: result.state === "POSITION_AMANDED" ? result.lng : mission.addressLng, 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:${req.user?.id}`).emit("notification", { type: "hpg-validation", status: "success", message: `HPG Validierung erfolgreich`, } as NotificationPayload); if (config?.alertWhenValid) { sendAlert(Number(id), {}); } } else { io.to(`user:${req.user?.id}`).emit("notification", { type: "hpg-validation", status: "failed", message: `HPG Validation fehlgeschlagen`, } as NotificationPayload); } }, ); // TODO: remove this after testing setTimeout(() => { io.to(`user:${req.user?.id}`).emit("notification", { type: "hpg-validation", status: "success", message: "HPG_BUSY", data: { mission, }, } as NotificationPayload); io.to(`user:${req.user?.id}`).emit("notification", { type: "hpg-validation", status: "failed", message: `HPG Validation fehlgeschlagen`, data: { mission, }, } as NotificationPayload); }, 5000); } catch (error) { console.error(error); res.json({ error: (error as Error).message || "Failed to validate HPG" }); } }); export default router;