Files
var-monorepo/apps/dispatch/app/_components/left/SituationBoard.tsx
2025-07-25 01:11:53 +02:00

248 lines
7.1 KiB
TypeScript

"use client";
import { useLeftMenuStore } from "_store/leftMenuStore";
import { cn } from "@repo/shared-components";
import { ListCollapse, Plane } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { getMissionsAPI } from "_querys/missions";
import { Mission, Station } from "@repo/db";
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
import { FMS_STATUS_COLORS, FMS_STATUS_TEXT_COLORS } from "_helpers/fmsStatusColors";
import { useMapStore } from "_store/mapStore";
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
import { findLeitstelleForPosition } from "_helpers/findLeitstelleinPoint";
export const SituationBoard = () => {
const { setSituationTabOpen, situationTabOpen } = useLeftMenuStore();
const { status, setHideDraftMissions, hideDraftMissions } = useDispatchConnectionStore(
(state) => state,
);
const dispatcherConnected = status === "connected";
const { data: missions } = useQuery({
queryKey: ["missions", "missions-on-stations"],
queryFn: () =>
getMissionsAPI<
Mission & {
MissionsOnStations: (Station & {
Station: Station;
})[];
}
>(
{
state: {
not: "finished",
},
},
{
MissionsOnStations: {
include: {
Station: true,
},
},
},
{
createdAt: "desc",
},
),
});
const filteredMissions = missions?.filter(
(mission) => !hideDraftMissions || mission.state !== "draft",
);
const { data: connectedAircrafts } = useQuery({
queryKey: ["aircrafts"],
queryFn: () => getConnectedAircraftsAPI(),
});
const {
setOpenAircraftMarker,
setOpenMissionMarker,
setMap,
userSettings,
openAircraftMarker,
openMissionMarker,
} = useMapStore((state) => state);
return (
<div className={cn("dropdown dropdown-top", situationTabOpen && "dropdown-open")}>
<div className="indicator">
<button
className="btn btn-soft btn-sm btn-info"
onClick={() => {
setSituationTabOpen(!situationTabOpen);
}}
>
<ListCollapse className="h-4 w-4" />
</button>
</div>
{situationTabOpen && (
<div
tabIndex={0}
className="dropdown-content card bg-base-200 border-1 border-info z-[1100] ml-2 max-h-[300px] min-w-[900px] shadow-md"
>
<div className="card-body flex flex-row gap-4">
<div className="flex-1">
<h2 className="mb-2 inline-flex items-center gap-2 text-lg font-bold">
<ListCollapse /> Einsatzliste{" "}
</h2>
<div>
<div className="form-control mb-2">
<label className="label cursor-pointer">
<input
type="checkbox"
className="checkbox checkbox-sm"
checked={hideDraftMissions}
onChange={() => setHideDraftMissions(!hideDraftMissions)}
/>
<span className="label-text text-sm">vorgeplante Einsätze verbergen</span>
</label>
</div>
</div>
<div className="max-h-[170px] select-none overflow-x-auto overflow-y-auto">
<table className="table-xs table">
{/* head */}
<thead>
<tr>
<th>E-Nr.</th>
<th>Stichwort</th>
<th>Stadt</th>
<th>Stationen</th>
</tr>
</thead>
<tbody>
{filteredMissions?.map(
(mission) =>
(dispatcherConnected || mission.state !== "draft") && (
<tr
className={cn(
"cursor-pointer",
mission.state === "draft" && "missionListItem",
)}
onDoubleClick={() => {
if (userSettings.settingsAutoCloseMapPopup) {
setOpenMissionMarker({
open: [
{
id: mission.id,
tab: "home",
},
],
close: openMissionMarker?.map((m) => m.id) || [],
});
} else {
setOpenMissionMarker({
open: [
{
id: mission.id,
tab: "home",
},
],
close: [],
});
}
setMap({
center: {
lat: mission.addressLat,
lng: mission.addressLng,
},
zoom: 14,
});
}}
key={mission.id}
>
<td>{mission.publicId.replace("ENr.: ", "")}</td>
<td>{mission.missionKeywordAbbreviation}</td>
<td>{mission.addressCity}</td>
<td>
{mission.MissionsOnStations?.map(
(mos) => mos.Station?.bosCallsignShort,
).join(", ")}
</td>
</tr>
),
)}
</tbody>
</table>
</div>
</div>
<div className="mx-2 w-px bg-gray-400" />
<div className="flex-1">
<h2 className="mb-2 inline-flex items-center gap-2 text-lg font-bold">
<Plane /> Stationen
</h2>
<div className="max-h-[200px] select-none overflow-x-auto overflow-y-auto">
<table className="table-xs table">
<thead>
<tr>
<th>BOS Name</th>
<th>Status</th>
<th>LST</th>
</tr>
</thead>
<tbody>
{connectedAircrafts?.map((aircraft) => (
<tr
className="cursor-pointer"
key={aircraft.id}
onDoubleClick={() => {
if (userSettings.settingsAutoCloseMapPopup) {
setOpenAircraftMarker({
open: [
{
id: aircraft.id,
tab: "home",
},
],
close: openAircraftMarker?.map((m) => m.id) || [],
});
} else {
setOpenAircraftMarker({
open: [
{
id: aircraft.id,
tab: "home",
},
],
close: [],
});
}
if (aircraft.posLat === null || aircraft.posLng === null) return;
setMap({
center: {
lat: aircraft.posLat,
lng: aircraft.posLng,
},
zoom: 14,
});
}}
>
<td>{aircraft.Station.bosCallsignShort}</td>
<td
className="font-lg text-center font-semibold"
style={{
color: FMS_STATUS_TEXT_COLORS[aircraft.fmsStatus],
backgroundColor: FMS_STATUS_COLORS[aircraft.fmsStatus],
}}
>
{aircraft.fmsStatus}
</td>
<td className="whitespace-nowrap">
{aircraft.posLng || !aircraft.posLat ? (
<>{findLeitstelleForPosition(aircraft.posLng!, aircraft.posLat!)}</>
) : (
aircraft.Station.bosRadioArea
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
</div>
);
};