210 lines
6.0 KiB
TypeScript
210 lines
6.0 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";
|
|
|
|
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 } = 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="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
{situationTabOpen && (
|
|
<div
|
|
tabIndex={0}
|
|
className="dropdown-content card bg-base-200 shadow-md z-[1100] ml-2 border-1 border-info min-w-[900px] max-h-[300px]"
|
|
>
|
|
<div className="card-body flex flex-row gap-4">
|
|
<div className="flex-1">
|
|
<h2 className="inline-flex items-center gap-2 text-lg font-bold mb-2">
|
|
<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="overflow-x-auto overflow-y-auto max-h-[170px] select-none">
|
|
<table className="table table-xs">
|
|
{/* 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={() => {
|
|
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="w-px bg-gray-400 mx-2" />
|
|
<div className="flex-1">
|
|
<h2 className="inline-flex items-center gap-2 text-lg font-bold mb-2">
|
|
<Plane /> Stationen
|
|
</h2>
|
|
<div className="overflow-x-auto overflow-y-auto max-h-[200px] select-none">
|
|
<table className="table table-xs">
|
|
<thead>
|
|
<tr>
|
|
<th>BOS Name</th>
|
|
<th>Status</th>
|
|
<th>LST</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{connectedAircrafts?.map((station) => (
|
|
<tr
|
|
className="cursor-pointer"
|
|
key={station.id}
|
|
onDoubleClick={() => {
|
|
setOpenAircraftMarker({
|
|
open: [
|
|
{
|
|
id: station.id,
|
|
tab: "home",
|
|
},
|
|
],
|
|
close: [],
|
|
});
|
|
if (station.posLat === null || station.posLng === null) return;
|
|
setMap({
|
|
center: {
|
|
lat: station.posLat,
|
|
lng: station.posLng,
|
|
},
|
|
zoom: 14,
|
|
});
|
|
}}
|
|
>
|
|
<td>{station.Station.bosCallsignShort}</td>
|
|
<td
|
|
className="text-center font-lg font-semibold"
|
|
style={{
|
|
color: FMS_STATUS_TEXT_COLORS[station.fmsStatus],
|
|
backgroundColor: FMS_STATUS_COLORS[station.fmsStatus],
|
|
}}
|
|
>
|
|
{station.fmsStatus}
|
|
</td>
|
|
<td className="whitespace-nowrap">{station.Station.bosRadioArea}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|