Merge branch 'main' of https://github.com/VAR-Virtual-Air-Rescue/var-monorepo
This commit is contained in:
@@ -23,11 +23,13 @@ import {
|
|||||||
} from "_components/SmartPopup";
|
} from "_components/SmartPopup";
|
||||||
import FMSStatusHistory, {
|
import FMSStatusHistory, {
|
||||||
FMSStatusSelector,
|
FMSStatusSelector,
|
||||||
|
MissionTab,
|
||||||
RettungsmittelTab,
|
RettungsmittelTab,
|
||||||
} from "./_components/AircraftMarkerTabs";
|
} from "./_components/AircraftMarkerTabs";
|
||||||
import { ConnectedAircraft, Station } from "@repo/db";
|
import { ConnectedAircraft, Station } from "@repo/db";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { getConnectedAircraftsAPI } from "querys/aircrafts";
|
import { getConnectedAircraftsAPI } from "querys/aircrafts";
|
||||||
|
import { getMissionsAPI } from "querys/missions";
|
||||||
|
|
||||||
export const FMS_STATUS_COLORS: { [key: string]: string } = {
|
export const FMS_STATUS_COLORS: { [key: string]: string } = {
|
||||||
"0": "rgb(140,10,10)",
|
"0": "rgb(140,10,10)",
|
||||||
@@ -76,22 +78,39 @@ const AircraftPopupContent = ({
|
|||||||
[currentTab, aircraft.id, setAircraftTab],
|
[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(() => {
|
const renderTabContent = useMemo(() => {
|
||||||
switch (currentTab) {
|
switch (currentTab) {
|
||||||
case "home":
|
case "home":
|
||||||
return <FMSStatusHistory />;
|
return <FMSStatusHistory aircraft={aircraft} />;
|
||||||
case "fms":
|
case "fms":
|
||||||
return <FMSStatusSelector aircraft={aircraft} />;
|
return <FMSStatusSelector aircraft={aircraft} />;
|
||||||
case "aircraft":
|
case "aircraft":
|
||||||
return <RettungsmittelTab />;
|
return <RettungsmittelTab aircraft={aircraft} />;
|
||||||
case "mission":
|
case "mission":
|
||||||
return <div>Mission Content</div>;
|
return mission ? (
|
||||||
|
<MissionTab mission={mission} />
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-100">No mission available</span>
|
||||||
|
);
|
||||||
case "chat":
|
case "chat":
|
||||||
return <div>Chat Content</div>;
|
return <div>Chat Content</div>;
|
||||||
default:
|
default:
|
||||||
return <span className="text-gray-100">Error</span>;
|
return <span className="text-gray-100">Error</span>;
|
||||||
}
|
}
|
||||||
}, [currentTab, aircraft]);
|
}, [currentTab, aircraft, mission]);
|
||||||
|
|
||||||
const setOpenAircraftMarker = useMapStore(
|
const setOpenAircraftMarker = useMapStore(
|
||||||
(state) => state.setOpenAircraftMarker,
|
(state) => state.setOpenAircraftMarker,
|
||||||
|
|||||||
@@ -1,38 +1,84 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { FMS_STATUS_COLORS, FMS_STATUS_TEXT_COLORS } from "../AircraftMarker";
|
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 { toast } from "react-hot-toast";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { editConnectedAircraftAPI } from "querys/aircrafts";
|
import { editConnectedAircraftAPI } from "querys/aircrafts";
|
||||||
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
||||||
import { cn } from "helpers/cn";
|
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 = [
|
const dummyData = [
|
||||||
{ status: "3", time: "12:00" },
|
{ status: "3", time: "12:00" },
|
||||||
{ status: "4", time: "12:30" },
|
{ status: "4", time: "12:30" },
|
||||||
{ status: "7", time: "14:54" },
|
{ status: "7", time: "14:54" },
|
||||||
{ status: "8", time: "13:30" },
|
{ status: "8", time: "15:30" },
|
||||||
{ status: "1", time: "13: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 (
|
return (
|
||||||
<div className="p-4">
|
<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">
|
<ul className="space-y-2">
|
||||||
{dummyData.map((entry, index) => (
|
{dummyData
|
||||||
<li key={index} className="flex items-center gap-2">
|
.reverse()
|
||||||
<span
|
.slice(0, 6)
|
||||||
className="font-bold text-base"
|
.map((entry, index) => (
|
||||||
style={{
|
<li key={index} className="flex items-center gap-2">
|
||||||
color: FMS_STATUS_TEXT_COLORS[entry.status],
|
<span
|
||||||
}}
|
className="font-bold text-base"
|
||||||
>
|
style={{
|
||||||
{entry.status}
|
color: FMS_STATUS_TEXT_COLORS[entry.status],
|
||||||
</span>
|
}}
|
||||||
<span className="text-base-content">{entry.time}</span>
|
>
|
||||||
</li>
|
{entry.status}
|
||||||
))}
|
</span>
|
||||||
|
<span className="text-base-content">{entry.time}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -63,35 +109,62 @@ const FMSStatusSelector = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2 p-4 justify-center items-center min-h-[136px] h-full">
|
<div className="flex flex-col gap-2 mt-2 p-4 text-base-content">
|
||||||
{Array.from({ length: 9 }, (_, i) => (i + 1).toString())
|
<div className="flex gap-2 justify-center items-center h-full">
|
||||||
.filter((status) => status !== "5") // Exclude status 5
|
{Array.from({ length: 9 }, (_, i) => (i + 1).toString())
|
||||||
.map((status) => (
|
.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
|
<button
|
||||||
disabled={!dispatcherConnected}
|
disabled={!dispatcherConnected}
|
||||||
key={status}
|
key={status}
|
||||||
className={cn(
|
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",
|
!dispatcherConnected && "cursor-not-allowed",
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor:
|
backgroundColor: "var(--color-base-200)",
|
||||||
hoveredStatus === status
|
color: "gray",
|
||||||
? 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 () => {
|
onClick={async () => {
|
||||||
// Handle status change logic here
|
|
||||||
await changeAircraftMutation.mutateAsync({
|
await changeAircraftMutation.mutateAsync({
|
||||||
id: aircraft.id,
|
id: aircraft.id,
|
||||||
update: {
|
update: {
|
||||||
@@ -104,16 +177,89 @@ const FMSStatusSelector = ({
|
|||||||
{status}
|
{status}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RettungsmittelTab = () => {
|
const RettungsmittelTab = ({
|
||||||
|
aircraft,
|
||||||
|
}: {
|
||||||
|
aircraft: ConnectedAircraft & { Station: Station };
|
||||||
|
}) => {
|
||||||
|
const station = aircraft.Station;
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2 p-4">
|
<div className="p-4 text-base-content">
|
||||||
<p className="text-base text-base-content">Aktuelle Rufgruppe: LST_01</p>
|
<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>
|
</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;
|
export default FMSStatusHistory;
|
||||||
|
|||||||
Reference in New Issue
Block a user