This commit is contained in:
PxlLoewe
2025-05-13 21:34:10 -07:00
2 changed files with 210 additions and 45 deletions

View File

@@ -23,11 +23,13 @@ import {
} from "_components/SmartPopup";
import FMSStatusHistory, {
FMSStatusSelector,
MissionTab,
RettungsmittelTab,
} from "./_components/AircraftMarkerTabs";
import { ConnectedAircraft, Station } from "@repo/db";
import { useQuery } from "@tanstack/react-query";
import { getConnectedAircraftsAPI } from "querys/aircrafts";
import { getMissionsAPI } from "querys/missions";
export const FMS_STATUS_COLORS: { [key: string]: string } = {
"0": "rgb(140,10,10)",
@@ -76,22 +78,39 @@ const AircraftPopupContent = ({
[currentTab, aircraft.id, setAircraftTab],
);
const { data: missions } = useQuery({
queryKey: ["missions"],
queryFn: () => getMissionsAPI(),
});
const mission = useMemo(() => {
return missions?.find(
(m) =>
(m.state === "running" || m.state === "draft") &&
m.missionStationIds.includes(aircraft.Station.id.toString()),
);
}, [missions, aircraft.Station.id]);
const renderTabContent = useMemo(() => {
switch (currentTab) {
case "home":
return <FMSStatusHistory />;
return <FMSStatusHistory aircraft={aircraft} />;
case "fms":
return <FMSStatusSelector aircraft={aircraft} />;
case "aircraft":
return <RettungsmittelTab />;
return <RettungsmittelTab aircraft={aircraft} />;
case "mission":
return <div>Mission Content</div>;
return mission ? (
<MissionTab mission={mission} />
) : (
<span className="text-gray-100">No mission available</span>
);
case "chat":
return <div>Chat Content</div>;
default:
return <span className="text-gray-100">Error</span>;
}
}, [currentTab, aircraft]);
}, [currentTab, aircraft, mission]);
const setOpenAircraftMarker = useMapStore(
(state) => state.setOpenAircraftMarker,

View File

@@ -1,38 +1,84 @@
"use client";
import React, { useState } from "react";
import { FMS_STATUS_COLORS, FMS_STATUS_TEXT_COLORS } from "../AircraftMarker";
import { ConnectedAircraft, Prisma, Station } from "@repo/db";
import { ConnectedAircraft, Mission, Prisma, Station } from "@repo/db";
import { toast } from "react-hot-toast";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { editConnectedAircraftAPI } from "querys/aircrafts";
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
import { cn } from "helpers/cn";
import { PersonIcon } from "@radix-ui/react-icons";
import {
BellRing,
CircleGaugeIcon,
Clock,
CompassIcon,
Component,
GaugeIcon,
Hash,
ListCollapse,
LocateFixed,
MapPin,
Mountain,
Navigation,
RadioTower,
SirenIcon,
Sunset,
TextSearch,
} from "lucide-react";
const FMSStatusHistory = () => {
const FMSStatusHistory = ({
aircraft,
}: {
aircraft: ConnectedAircraft & { Station: Station };
}) => {
const dummyData = [
{ status: "3", time: "12:00" },
{ status: "4", time: "12:30" },
{ status: "7", time: "14:54" },
{ status: "8", time: "13:30" },
{ status: "1", time: "13:30" },
{ status: "8", time: "15:30" },
{ status: "1", time: "16:30" },
{ status: "4", time: "17:30" },
{ status: "7", time: "18:54" },
{ status: "8", time: "19:30" },
{ status: "1", time: "20:30" },
{ status: "4", time: "21:30" },
{ status: "7", time: "22:54" },
{ status: "8", time: "23:30" },
{ status: "1", time: "24:30" },
];
const aircraftUser =
typeof aircraft.publicUser === "string"
? JSON.parse(aircraft.publicUser)
: aircraft.publicUser;
return (
<div className="p-4">
<ul className="text-base-content font-semibold">
<li className="flex items-center gap-2 mb-1">
<PersonIcon className="w-5 h-5" /> {aircraftUser.fullName} (
{aircraftUser.publicId})
</li>
</ul>
<div className="divider mt-0 mb-0" />
<ul className="space-y-2">
{dummyData.map((entry, index) => (
<li key={index} className="flex items-center gap-2">
<span
className="font-bold text-base"
style={{
color: FMS_STATUS_TEXT_COLORS[entry.status],
}}
>
{entry.status}
</span>
<span className="text-base-content">{entry.time}</span>
</li>
))}
{dummyData
.reverse()
.slice(0, 6)
.map((entry, index) => (
<li key={index} className="flex items-center gap-2">
<span
className="font-bold text-base"
style={{
color: FMS_STATUS_TEXT_COLORS[entry.status],
}}
>
{entry.status}
</span>
<span className="text-base-content">{entry.time}</span>
</li>
))}
</ul>
</div>
);
@@ -63,35 +109,62 @@ const FMSStatusSelector = ({
});
return (
<div className="flex gap-2 p-4 justify-center items-center min-h-[136px] h-full">
{Array.from({ length: 9 }, (_, i) => (i + 1).toString())
.filter((status) => status !== "5") // Exclude status 5
.map((status) => (
<div className="flex flex-col gap-2 mt-2 p-4 text-base-content">
<div className="flex gap-2 justify-center items-center h-full">
{Array.from({ length: 9 }, (_, i) => (i + 1).toString())
.filter((status) => status !== "5") // Exclude status 5
.map((status) => (
<button
disabled={!dispatcherConnected}
key={status}
className={cn(
"flex justify-center items-center min-w-13 min-h-13 cursor-pointer text-4xl font-bold",
!dispatcherConnected && "cursor-not-allowed",
)}
style={{
backgroundColor:
hoveredStatus === status
? FMS_STATUS_COLORS[status]
: aircraft.fmsStatus === status
? FMS_STATUS_COLORS[status]
: "var(--color-base-200)",
color:
aircraft.fmsStatus === status
? "white"
: hoveredStatus === status
? "white"
: "gray",
}}
onMouseEnter={() => setHoveredStatus(status)}
onMouseLeave={() => setHoveredStatus(null)}
onClick={async () => {
await changeAircraftMutation.mutateAsync({
id: aircraft.id,
update: {
fmsStatus: status,
},
});
toast.success(`Status changed to ${status}`);
}}
>
{status}
</button>
))}
</div>
<div className="flex gap-1 p-2 justify-center items-center">
{["E", "C", "F", "J", "L", "c", "d", "h", "o", "u"].map((status) => (
<button
disabled={!dispatcherConnected}
key={status}
className={cn(
"flex justify-center items-center min-w-13 min-h-13 cursor-pointer text-4xl font-bold",
"flex justify-center items-center min-w-10 min-h-10 cursor-pointer text-lg font-bold",
!dispatcherConnected && "cursor-not-allowed",
)}
style={{
backgroundColor:
hoveredStatus === status
? FMS_STATUS_COLORS[status]
: aircraft.fmsStatus === status
? FMS_STATUS_COLORS[status]
: "var(--color-base-200)",
color:
aircraft.fmsStatus === status
? "white"
: hoveredStatus === status
? "white"
: "gray",
backgroundColor: "var(--color-base-200)",
color: "gray",
}}
onMouseEnter={() => setHoveredStatus(status)}
onMouseLeave={() => setHoveredStatus(null)}
onClick={async () => {
// Handle status change logic here
await changeAircraftMutation.mutateAsync({
id: aircraft.id,
update: {
@@ -104,16 +177,89 @@ const FMSStatusSelector = ({
{status}
</button>
))}
</div>
</div>
);
};
const RettungsmittelTab = () => {
const RettungsmittelTab = ({
aircraft,
}: {
aircraft: ConnectedAircraft & { Station: Station };
}) => {
const station = aircraft.Station;
return (
<div className="flex gap-2 p-4">
<p className="text-base text-base-content">Aktuelle Rufgruppe: LST_01</p>
<div className="p-4 text-base-content">
<ul className="text-base-content font-semibold">
<li className="flex items-center gap-2 mb-1">
<Component size={16} /> Aktuelle Rufgruppe: LST_01
</li>
<li className="flex items-center gap-2 mb-1">
<RadioTower size={16} /> Leitstellenbereich: Florian Berlin
</li>
</ul>
<div className="divider mt-0 mb-0" />
<div className="flex items-center text-sm font-semibold justify-between pr-2 mt-2 mb-2">
<span className="flex items-center gap-2">
<Clock size={16} /> {station.is24h ? "24h Betrieb" : "Tagbetrieb"}
</span>
<span className="flex items-center gap-2">
<Sunset size={16} /> NVG: {station.hasNvg ? "Ja" : "Nein"}
</span>
<span className="flex items-center gap-2">
<Mountain size={16} /> Winch: {station.hasWinch ? "Ja" : "Nein"}
</span>
<span className="flex items-center gap-2">
<TextSearch size={16} /> {station.aircraftRegistration}
</span>
</div>
<div className="divider mt-0 mb-0" />
<div className="flex items-center text-sm font-semibold justify-between pr-2 mt-2">
<span className="flex items-center gap-2">
<CompassIcon size={16} /> HDG: {aircraft.posHeading}°
</span>
<span className="flex items-center gap-2">
<GaugeIcon size={16} /> SPD: {aircraft.posSpeed} kt
</span>
<span className="flex items-center gap-2">
<CircleGaugeIcon size={16} /> ALT: {aircraft.posAlt} ft
</span>
</div>
</div>
);
};
export { FMSStatusSelector, RettungsmittelTab };
const MissionTab = ({ mission }: { mission: Mission }) => {
return (
<div className="p-4 text-base-content">
<ul className="text-base-content font-semibold">
<li className="flex items-center gap-2 mb-1">
<BellRing size={16} /> {mission.missionKeywordCategory}
</li>
<li className="flex items-center gap-2 mb-1">
<ListCollapse size={16} />
{mission.missionKeywordName}
</li>
<li className="flex items-center gap-2 mt-3">
<Hash size={16} />
__{new Date().toISOString().slice(0, 10).replace(/-/g, "")}
{mission.id}
</li>
</ul>
<div className="divider mt-0 mb-0" />
<div className="text-sm font-semibold">
<p className="flex items-center gap-2">
<MapPin size={16} /> {mission.addressLat} {mission.addressLng}
</p>
<p className="flex items-center gap-2">
<Navigation size={16} /> {mission.addressStreet}
</p>
<p className="flex items-center gap-2">
<LocateFixed size={16} /> {mission.addressZip} {mission.addressCity}
</p>
</div>
</div>
);
};
export { FMSStatusSelector, RettungsmittelTab, MissionTab };
export default FMSStatusHistory;