Mission Popup WIP
This commit is contained in:
@@ -58,6 +58,13 @@ interface MapStore {
|
|||||||
aircraftId: string,
|
aircraftId: string,
|
||||||
tab: MapStore["aircraftTabs"][string],
|
tab: MapStore["aircraftTabs"][string],
|
||||||
) => void;
|
) => void;
|
||||||
|
missionTabs: {
|
||||||
|
[missionId: string]: "home" | "details" | "chat";
|
||||||
|
};
|
||||||
|
setMissionTab: (
|
||||||
|
missionId: string,
|
||||||
|
tab: MapStore["missionTabs"][string],
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMapStore = create<MapStore>((set, get) => ({
|
export const useMapStore = create<MapStore>((set, get) => ({
|
||||||
@@ -106,4 +113,12 @@ export const useMapStore = create<MapStore>((set, get) => ({
|
|||||||
[aircraftId]: tab,
|
[aircraftId]: tab,
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
missionTabs: {},
|
||||||
|
setMissionTab: (missionId, tab) =>
|
||||||
|
set((state) => ({
|
||||||
|
missionTabs: {
|
||||||
|
...state.missionTabs,
|
||||||
|
[missionId]: tab,
|
||||||
|
},
|
||||||
|
})),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { create } from "zustand";
|
|||||||
interface MissionStore {
|
interface MissionStore {
|
||||||
missions: MissionOptionalDefaults[];
|
missions: MissionOptionalDefaults[];
|
||||||
setMissions: (missions: MissionOptionalDefaults[]) => void;
|
setMissions: (missions: MissionOptionalDefaults[]) => void;
|
||||||
|
setMission: (mission: MissionOptionalDefaults) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMissionsStore = create<MissionStore>((set) => ({
|
export const useMissionsStore = create<MissionStore>((set) => ({
|
||||||
@@ -24,4 +25,17 @@ export const useMissionsStore = create<MissionStore>((set) => ({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
setMissions: (missions) => set({ missions }),
|
setMissions: (missions) => set({ missions }),
|
||||||
|
setMission: (mission) =>
|
||||||
|
set((state) => {
|
||||||
|
const existingMissionIndex = state.missions.findIndex(
|
||||||
|
(m) => m.id === mission.id,
|
||||||
|
);
|
||||||
|
if (existingMissionIndex !== -1) {
|
||||||
|
const updatedMissions = [...state.missions];
|
||||||
|
updatedMissions[existingMissionIndex] = mission;
|
||||||
|
return { missions: updatedMissions };
|
||||||
|
} else {
|
||||||
|
return { missions: [...state.missions, mission] };
|
||||||
|
}
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -2,11 +2,19 @@ import { useMissionsStore } from "_store/missionsStore";
|
|||||||
import { Marker, Popup, useMap } from "react-leaflet";
|
import { Marker, Popup, useMap } from "react-leaflet";
|
||||||
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { Fragment, useCallback, useEffect, useRef, useState } from "react";
|
import {
|
||||||
|
Fragment,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { cn } from "helpers/cn";
|
import { cn } from "helpers/cn";
|
||||||
import { Cross, House, Minimize2, Route } from "lucide-react";
|
import { Cross, House, Minimize2, Route } from "lucide-react";
|
||||||
import { SmartPopup, useConflict, useSmartPopup } from "_components/SmartPopup";
|
import { SmartPopup, useConflict, useSmartPopup } from "_components/SmartPopup";
|
||||||
import { Mission, MissionState } from "@repo/db";
|
import { Mission, MissionState } from "@repo/db";
|
||||||
|
import FMSStatusHistory from "./_components/MissionMarkerTabs";
|
||||||
|
|
||||||
export const MISSION_STATUS_COLORS: Record<MissionState, string> = {
|
export const MISSION_STATUS_COLORS: Record<MissionState, string> = {
|
||||||
draft: "#0092b8",
|
draft: "#0092b8",
|
||||||
@@ -21,10 +29,38 @@ export const MISSION_STATUS_TEXT_COLORS: Record<MissionState, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
||||||
|
const setMissionTab = useMapStore((state) => state.setMissionTab);
|
||||||
|
const currentTab = useMapStore(
|
||||||
|
(state) => state.missionTabs[mission.id] || "home",
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = useCallback(
|
||||||
|
(tab: "home" | "details" | "chat") => {
|
||||||
|
if (currentTab !== tab) {
|
||||||
|
setMissionTab(mission.id, tab);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[currentTab, mission.id, setMissionTab],
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderTabContent = useMemo(() => {
|
||||||
|
switch (currentTab) {
|
||||||
|
case "home":
|
||||||
|
return <FMSStatusHistory />;
|
||||||
|
case "details":
|
||||||
|
return <div>Details Content</div>;
|
||||||
|
case "chat":
|
||||||
|
return <div>Chat Content</div>;
|
||||||
|
default:
|
||||||
|
return <span className="text-gray-100">Error</span>;
|
||||||
|
}
|
||||||
|
}, [currentTab]);
|
||||||
|
|
||||||
const setOpenMissionMarker = useMapStore(
|
const setOpenMissionMarker = useMapStore(
|
||||||
(state) => state.setOpenMissionMarker,
|
(state) => state.setOpenMissionMarker,
|
||||||
);
|
);
|
||||||
const { anchor } = useSmartPopup();
|
const { anchor } = useSmartPopup();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@@ -36,7 +72,7 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Minimize2 className="text-white " size={15} />
|
<Minimize2 className="text-white" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -68,40 +104,47 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="p-2 flex justify-center items-center"
|
className="p-2 px-3 flex justify-center items-center cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${MISSION_STATUS_TEXT_COLORS[mission.state]}`,
|
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
|
||||||
|
borderBottom:
|
||||||
|
currentTab === "home"
|
||||||
|
? `5px solid ${MISSION_STATUS_TEXT_COLORS[mission.state]}`
|
||||||
|
: "5px solid transparent",
|
||||||
}}
|
}}
|
||||||
|
onClick={() => handleTabChange("home")}
|
||||||
>
|
>
|
||||||
<House className="text-sm" />
|
<House className="text-sm" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="p-2 flex justify-center items-center"
|
className="p-2 px-4 flex justify-center items-center cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${MISSION_STATUS_TEXT_COLORS[mission.state]}`,
|
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
|
||||||
|
borderBottom:
|
||||||
|
currentTab === "details"
|
||||||
|
? `5px solid ${MISSION_STATUS_TEXT_COLORS[mission.state]}`
|
||||||
|
: "5px solid transparent",
|
||||||
}}
|
}}
|
||||||
|
onClick={() => handleTabChange("details")}
|
||||||
>
|
>
|
||||||
<Route className="text-sm" />
|
<Route className="text-sm" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex justify-center items-center text-2xl p-2"
|
className="p-2 px-4 flex justify-center items-center cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${MISSION_STATUS_TEXT_COLORS[mission.state]}`,
|
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
|
||||||
color: `${MISSION_STATUS_TEXT_COLORS[mission.state]}`,
|
borderBottom:
|
||||||
|
currentTab === "chat"
|
||||||
|
? `5px solid ${MISSION_STATUS_TEXT_COLORS[mission.state]}`
|
||||||
|
: "5px solid transparent",
|
||||||
}}
|
}}
|
||||||
|
onClick={() => handleTabChange("chat")}
|
||||||
>
|
>
|
||||||
{mission.state}
|
<Cross className="text-sm" />
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="p-2 flex-1 flex justify-center items-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: `${MISSION_STATUS_TEXT_COLORS[mission.state]}`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="text-sm text-white">Einsatz 250411</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>{renderTabContent}</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -231,9 +274,11 @@ const MissionMarker = ({ mission }: { mission: Mission }) => {
|
|||||||
closeOnClick={false}
|
closeOnClick={false}
|
||||||
autoPan={false}
|
autoPan={false}
|
||||||
wrapperClassName="relative"
|
wrapperClassName="relative"
|
||||||
className="w-[300px] h-[150px]"
|
className="w-[502px]"
|
||||||
>
|
>
|
||||||
|
<div style={{ height: "auto", maxHeight: "90vh", overflowY: "auto" }}>
|
||||||
<MissionPopupContent mission={mission} />
|
<MissionPopupContent mission={mission} />
|
||||||
|
</div>
|
||||||
</SmartPopup>
|
</SmartPopup>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
"use client";
|
||||||
|
import React from "react";
|
||||||
|
import { FMS_STATUS_TEXT_COLORS } from "../AircraftMarker";
|
||||||
|
|
||||||
|
const FMSStatusHistory = () => {
|
||||||
|
const dummyData = [
|
||||||
|
{ status: "3", time: "12:00", unit: "RTW", unitshort: "RTW" },
|
||||||
|
{ status: "3", time: "12:01", unit: "Christoph 31", unitshort: "CHX31" },
|
||||||
|
{ status: "4", time: "12:09", unit: "RTW", unitshort: "RTW" },
|
||||||
|
{ status: "4", time: "12:11", unit: "Christoph 31", unitshort: "CHX31" },
|
||||||
|
{ status: "7", time: "12:34", unit: "RTW", unitshort: "RTW" },
|
||||||
|
{ status: "1", time: "12:38", unit: "Christoph 31", unitshort: "CHX31" },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{[
|
||||||
|
...new Map(dummyData.map((entry) => [entry.unit, entry])).values(),
|
||||||
|
].map((entry, index, array) => (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div 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.unitshort}</span>
|
||||||
|
</div>
|
||||||
|
{index < array.length - 1 && <span className="mx-1">|</span>}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="divider m-0" />
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{dummyData.map((entry, index) => (
|
||||||
|
<li key={index} className="flex items-center gap-2">
|
||||||
|
<span className="text-base-content">{entry.time}</span>
|
||||||
|
<span
|
||||||
|
className="font-bold text-base"
|
||||||
|
style={{
|
||||||
|
color: FMS_STATUS_TEXT_COLORS[entry.status],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{entry.status}
|
||||||
|
</span>
|
||||||
|
<span className="text-base-content">{entry.unit}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FMSStatusHistory;
|
||||||
Reference in New Issue
Block a user