Added airbase info and spawn menu

This commit is contained in:
Davide Passoni
2024-08-29 15:31:16 +02:00
parent fd15406f5d
commit ebfa7916c6
12 changed files with 272 additions and 61 deletions

View File

@@ -7,12 +7,14 @@ export const EventsContext = createContext({
setMeasureMenuVisible: (e: boolean) => {}, setMeasureMenuVisible: (e: boolean) => {},
setDrawingMenuVisible: (e: boolean) => {}, setDrawingMenuVisible: (e: boolean) => {},
setOptionsMenuVisible: (e: boolean) => {}, setOptionsMenuVisible: (e: boolean) => {},
setAirbaseMenuVisible: (e: boolean) => {},
toggleMainMenuVisible: () => {}, toggleMainMenuVisible: () => {},
toggleSpawnMenuVisible: () => {}, toggleSpawnMenuVisible: () => {},
toggleUnitControlMenuVisible: () => {}, toggleUnitControlMenuVisible: () => {},
toggleMeasureMenuVisible: () => {}, toggleMeasureMenuVisible: () => {},
toggleDrawingMenuVisible: () => {}, toggleDrawingMenuVisible: () => {},
toggleOptionsMenuVisible: () => {}, toggleOptionsMenuVisible: () => {},
toggleAirbaseMenuVisible: () => {},
}); });
export const EventsProvider = EventsContext.Provider; export const EventsProvider = EventsContext.Provider;

View File

@@ -12,7 +12,6 @@ export class Airbase extends CustomMarker {
runways: [], runways: [],
}; };
#coalition: string = ""; #coalition: string = "";
#hasChartDataBeenSet: boolean = false;
#properties: string[] = []; #properties: string[] = [];
#parkings: string[] = []; #parkings: string[] = [];
@@ -22,10 +21,6 @@ export class Airbase extends CustomMarker {
this.#name = options.name; this.#name = options.name;
} }
chartDataHasBeenSet() {
return this.#hasChartDataBeenSet;
}
createIcon() { createIcon() {
var icon = new DivIcon({ var icon = new DivIcon({
className: "leaflet-airbase-marker", className: "leaflet-airbase-marker",
@@ -43,10 +38,10 @@ export class Airbase extends CustomMarker {
el.appendChild(img); el.appendChild(img);
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);
el.addEventListener("mouseover", (ev) => { el.addEventListener("mouseover", (ev) => {
document.dispatchEvent(new CustomEvent("airbaseMouseover", { detail: this })); document.dispatchEvent(new CustomEvent("airbasemouseover", { detail: this }));
}); });
el.addEventListener("mouseout", (ev) => { el.addEventListener("mouseout", (ev) => {
document.dispatchEvent(new CustomEvent("airbaseMouseout", { detail: this })); document.dispatchEvent(new CustomEvent("airbasemouseout", { detail: this }));
}); });
el.dataset.coalition = this.#coalition; el.dataset.coalition = this.#coalition;
} }
@@ -73,7 +68,6 @@ export class Airbase extends CustomMarker {
} }
setChartData(chartData: AirbaseChartData) { setChartData(chartData: AirbaseChartData) {
this.#hasChartDataBeenSet = true;
this.#chartData = chartData; this.#chartData = chartData;
} }

View File

@@ -87,7 +87,7 @@ export class MissionManager {
position: new LatLng(airbase.latitude, airbase.longitude), position: new LatLng(airbase.latitude, airbase.longitude),
name: airbase.callsign, name: airbase.callsign,
}).addTo(getApp().getMap()); }).addTo(getApp().getMap());
this.#airbases[airbase.callsign].on("contextmenu", (e) => this.#onAirbaseClick(e)); this.#airbases[airbase.callsign].on("click", (e) => this.#onAirbaseClick(e));
this.#loadAirbaseChartData(airbase.callsign); this.#loadAirbaseChartData(airbase.callsign);
} }
@@ -316,7 +316,9 @@ export class MissionManager {
if (requestRefresh) getApp().getServerManager().refreshAll(); if (requestRefresh) getApp().getServerManager().refreshAll();
} }
#onAirbaseClick(e: any) {} #onAirbaseClick(ev: any) {
document.dispatchEvent(new CustomEvent("airbaseclick", { detail: ev.target }));
}
#loadAirbaseChartData(callsign: string) { #loadAirbaseChartData(callsign: string) {
if (!this.#theatre) { if (!this.#theatre) {
@@ -324,7 +326,7 @@ export class MissionManager {
} }
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open("GET", `api/airbases/${this.#theatre.toLowerCase()}/${callsign}`, true); xhr.open("GET", window.location.href.split("?")[0].replace("vite/", "") + `api/airbases/${this.#theatre.toLowerCase()}/${callsign}`, true);
xhr.responseType = "json"; xhr.responseType = "json";
xhr.onload = () => { xhr.onload = () => {
var status = xhr.status; var status = xhr.status;

View File

@@ -142,8 +142,6 @@ export class ServerManager {
setAddress(address: string) { setAddress(address: string) {
this.#REST_ADDRESS = `${address.replace("vite/", "").replace("vite", "")}olympus`; this.#REST_ADDRESS = `${address.replace("vite/", "").replace("vite", "")}olympus`;
// TODO: TEMPORARY FOR DEBUGGING
// this.#REST_ADDRESS = `https://refugees.dcsolympus.com/olympus`;
console.log(`Setting REST address to ${this.#REST_ADDRESS}`); console.log(`Setting REST address to ${this.#REST_ADDRESS}`);
} }

View File

@@ -8,6 +8,7 @@ export const StateContext = createContext({
measureMenuVisible: false, measureMenuVisible: false,
drawingMenuVisible: false, drawingMenuVisible: false,
optionsMenuVisible: false, optionsMenuVisible: false,
airbaseMenuVisible: false,
mapHiddenTypes: MAP_HIDDEN_TYPES_DEFAULTS, mapHiddenTypes: MAP_HIDDEN_TYPES_DEFAULTS,
mapOptions: MAP_OPTIONS_DEFAULTS, mapOptions: MAP_OPTIONS_DEFAULTS,
mapSources: [] as string[], mapSources: [] as string[],

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowCircleDown } from "@fortawesome/free-solid-svg-icons"; import { faArrowCircleDown } from "@fortawesome/free-solid-svg-icons";
export function OlAccordion(props: { title: string; children?: JSX.Element | JSX.Element[]; showArrows?: boolean }) { export function OlAccordion(props: { title: string; children?: JSX.Element | JSX.Element[]; showArrows?: boolean; className?: string }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [scrolledUp, setScrolledUp] = useState(true); const [scrolledUp, setScrolledUp] = useState(true);
const [scrolledDown, setScrolledDown] = useState(false); const [scrolledDown, setScrolledDown] = useState(false);
@@ -31,6 +31,7 @@ export function OlAccordion(props: { title: string; children?: JSX.Element | JSX
type="button" type="button"
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
className={` className={`
${props.className ?? ""}
flex w-full items-center justify-between gap-3 border-gray-200 py-2 flex w-full items-center justify-between gap-3 border-gray-200 py-2
text-gray-700 text-gray-700
dark:border-gray-700 dark:text-white dark:border-gray-700 dark:text-white

View File

@@ -0,0 +1,141 @@
import React, { useState } from "react";
import { Menu } from "./components/menu";
import { OlCheckbox } from "../components/olcheckbox";
import { OlRangeSlider } from "../components/olrangeslider";
import { OlNumberInput } from "../components/olnumberinput";
import { Coalition, MapOptions } from "../../types/types";
import { getApp } from "../../olympusapp";
import { Airbase } from "../../mission/airbase";
import { FaArrowLeft, FaCompass } from "react-icons/fa6";
import { getUnitsByLabel } from "../../other/utils";
import { UnitBlueprint } from "../../interfaces";
import { IDLE } from "../../constants/constants";
import { OlSearchBar } from "../components/olsearchbar";
import { OlAccordion } from "../components/olaccordion";
import { OlUnitEntryList } from "../components/olunitlistentry";
import { olButtonsVisibilityAircraft, olButtonsVisibilityHelicopter } from "../components/olicons";
import { UnitSpawnMenu } from "./unitspawnmenu";
export function AirbaseMenu(props: { open: boolean; onClose: () => void; airbase: Airbase | null; children?: JSX.Element | JSX.Element[] }) {
const [blueprint, setBlueprint] = useState(null as null | UnitBlueprint);
const [filterString, setFilterString] = useState("");
const [filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits] = getUnitsByLabel(filterString);
return (
<Menu title={props.airbase?.getName() ?? "No airbase selected"} open={props.open} onClose={props.onClose} showBackButton={false} canBeHidden={true}>
<div
className={`
flex flex-col gap-2 font-normal text-gray-800
dark:text-white
`}
>
<div
data-coalition={props.airbase?.getCoalition()}
className={`
flex flex-col content-center justify-between gap-2 border-l-4
bg-olympus-200/30 py-3 pl-4 pr-5
data-[coalition='blue']:border-blue-500
data-[coalition='neutral']:border-gray-500
data-[coalition='red']:border-red-500
`}
>
<div className="flex w-full justify-between">
<span className="text-gray-400">ICAO name</span>
<span>{props.airbase?.getChartData().ICAO !== "" ? props.airbase?.getChartData().ICAO : "N/A"}</span>
</div>
<div className="flex w-full justify-between">
<span className="text-gray-400">TACAN</span>
<span>{props.airbase?.getChartData().TACAN !== "" ? props.airbase?.getChartData().TACAN : "None"}</span>
</div>
<div className="flex w-full justify-between">
<span className="text-gray-400">Elevation</span>
<span>{props.airbase?.getChartData().elevation !== "" ? props.airbase?.getChartData().elevation : "N/A"}ft</span>
</div>
<OlAccordion title={`Runways`} className="!p-0 !text-gray-400">
<div className="flex flex-col gap-2">
{props.airbase?.getChartData().runways.map((runway) => {
return (
<>
{Object.keys(runway.headings[0]).map((runwayName) => {
return (
<div className="flex w-full justify-between">
<span>
{" "}
<span className="text-gray-400">RWY</span> {runwayName}
</span>
<span
className={`
flex gap-1 rounded-full bg-olympus-200/30 px-2
py-1
`}
>
<FaCompass className={`my-auto text-gray-400`} /> {runway.headings[0][runwayName].magHeading}°{" "}
<span className={`text-gray-400`}>ILS</span>{" "}
{runway.headings[0][runwayName].ILS !== "" ? runway.headings[0][runwayName].ILS + "MHz" : "None"}
</span>
</div>
);
})}
</>
);
})}
</div>
</OlAccordion>
</div>
<div className="mt-5 flex gap-2 px-5 text-white bold">
{blueprint && (
<FaArrowLeft
className={`
my-auto h-8 w-8 cursor-pointer rounded-md p-2
dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-white
`}
onClick={() => setBlueprint(null)}
/>
)}
<span className="my-auto">Spawn units at airbase</span>
</div>
<>
{blueprint === null && (
<div className="p-5">
<OlSearchBar onChange={(value) => setFilterString(value)} text={filterString} />
<OlAccordion title={`Aircraft`}>
<div
className={`
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
`}
>
{Object.entries(filteredAircraft).map((entry) => {
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityAircraft} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
})}
</div>
</OlAccordion>
<OlAccordion title={`Helicopters`}>
<div
className={`
flex max-h-80 flex-col gap-1 overflow-y-scroll no-scrollbar
`}
>
{Object.entries(filteredHelicopters).map((entry) => {
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityHelicopter} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
})}
</div>
</OlAccordion>
</div>
)}
{!(blueprint === null) && (
<UnitSpawnMenu
blueprint={blueprint}
spawnAtLocation={false}
airbase={props.airbase}
coalition={(props.airbase?.getCoalition() ?? "blue") as Coalition}
/>
)}
</>
</div>
</Menu>
);
}

View File

@@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { OlStateButton } from "../components/olstatebutton"; import { OlStateButton } from "../components/olstatebutton";
import { faGamepad, faRuler, faPencil, faEllipsisV, faCog, faQuestionCircle, faPlusSquare, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"; import { faGamepad, faRuler, faPencil, faEllipsisV, faCog, faQuestionCircle, faPlusSquare, faMagnifyingGlass, faPlaneDeparture } from "@fortawesome/free-solid-svg-icons";
import { EventsConsumer } from "../../eventscontext"; import { EventsConsumer } from "../../eventscontext";
import { StateConsumer } from "../../statecontext"; import { StateConsumer } from "../../statecontext";
import { IDLE } from "../../constants/constants"; import { IDLE } from "../../constants/constants";
@@ -52,6 +52,12 @@ export function SideBar() {
icon={faPencil} icon={faPencil}
tooltip="Hide/show drawing menu" tooltip="Hide/show drawing menu"
></OlStateButton> ></OlStateButton>
<OlStateButton
onClick={events.toggleAirbaseMenuVisible}
checked={appState.airbaseMenuVisible}
icon={faPlaneDeparture}
tooltip="Hide/show airbase menu"
></OlStateButton>
</div> </div>
</div> </div>
<div className="flex w-16 flex-wrap content-end justify-center p-4"> <div className="flex w-16 flex-wrap content-end justify-center p-4">

View File

@@ -1,7 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Menu } from "./components/menu"; import { Menu } from "./components/menu";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { OlSearchBar } from "../components/olsearchbar"; import { OlSearchBar } from "../components/olsearchbar";
import { OlAccordion } from "../components/olaccordion"; import { OlAccordion } from "../components/olaccordion";
import { getApp } from "../../olympusapp"; import { getApp } from "../../olympusapp";
@@ -18,8 +16,6 @@ import {
import { IDLE, SPAWN_UNIT } from "../../constants/constants"; import { IDLE, SPAWN_UNIT } from "../../constants/constants";
import { getUnitsByLabel } from "../../other/utils"; import { getUnitsByLabel } from "../../other/utils";
library.add(faPlus);
export function SpawnMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) { export function SpawnMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
const [blueprint, setBlueprint] = useState(null as null | UnitBlueprint); const [blueprint, setBlueprint] = useState(null as null | UnitBlueprint);
const [filterString, setFilterString] = useState(""); const [filterString, setFilterString] = useState("");
@@ -107,7 +103,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
</div> </div>
)} )}
{!(blueprint === null) && <UnitSpawnMenu blueprint={blueprint} />} {!(blueprint === null) && <UnitSpawnMenu blueprint={blueprint} spawnAtLocation={true} />}
</> </>
</Menu> </Menu>
); );

View File

@@ -11,8 +11,9 @@ import { getApp } from "../../olympusapp";
import { IDLE, SPAWN_UNIT } from "../../constants/constants"; import { IDLE, SPAWN_UNIT } from "../../constants/constants";
import { ftToM, getUnitCategoryByBlueprint } from "../../other/utils"; import { ftToM, getUnitCategoryByBlueprint } from "../../other/utils";
import { LatLng } from "leaflet"; import { LatLng } from "leaflet";
import { Airbase } from "../../mission/airbase";
export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) { export function UnitSpawnMenu(props: { blueprint: UnitBlueprint; spawnAtLocation: boolean; airbase?: Airbase | null; coalition?: Coalition }) {
/* Compute the min and max values depending on the unit type */ /* Compute the min and max values depending on the unit type */
const minNumber = 1; const minNumber = 1;
const maxNumber = 4; const maxNumber = 4;
@@ -30,31 +31,60 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
/* When the menu is opened show the unit preview on the map as a cursor */ /* When the menu is opened show the unit preview on the map as a cursor */
useEffect(() => { useEffect(() => {
if (props.blueprint !== null) { if (props.coalition && props.coalition !== spawnCoalition) {
getApp() setSpawnCoalition(props.coalition);
?.getMap() }
?.setState(SPAWN_UNIT, { if (props.spawnAtLocation) {
spawnRequestTable: { if (props.blueprint !== null) {
category: getUnitCategoryByBlueprint(props.blueprint), getApp()
unit: { ?.getMap()
unitType: props.blueprint.name, ?.setState(SPAWN_UNIT, {
location: new LatLng(0, 0), // This will be filled when the user clicks on the map to spawn the unit spawnRequestTable: {
skill: "High", category: getUnitCategoryByBlueprint(props.blueprint),
liveryID: "", unit: {
altitude: ftToM(spawnAltitude), unitType: props.blueprint.name,
loadout: location: new LatLng(0, 0), // This will be filled when the user clicks on the map to spawn the unit
props.blueprint.loadouts?.find((loadout) => { skill: "High",
return loadout.name === spawnLoadoutName; liveryID: "",
})?.code ?? "", altitude: ftToM(spawnAltitude),
loadout:
props.blueprint.loadouts?.find((loadout) => {
return loadout.name === spawnLoadoutName;
})?.code ?? "",
},
coalition: spawnCoalition,
}, },
coalition: spawnCoalition, });
}, } else {
}); if (getApp()?.getMap()?.getState() === SPAWN_UNIT) getApp().getMap().setState(IDLE);
} else { }
if (getApp()?.getMap()?.getState() === SPAWN_UNIT) getApp().getMap().setState(IDLE);
} }
}); });
function spawnAtAirbase() {
getApp()
.getUnitsManager()
.spawnUnits(
getUnitCategoryByBlueprint(props.blueprint),
[
{
unitType: props.blueprint.name,
location: new LatLng(0, 0), // Not relevant spawning at airbase
skill: "High",
liveryID: "",
altitude: 0,
loadout:
props.blueprint.loadouts?.find((loadout) => {
return loadout.name === spawnLoadoutName;
})?.code ?? "",
},
],
props.coalition,
false,
props.airbase?.getName()
);
}
/* Get a list of all the roles */ /* Get a list of all the roles */
const roles: string[] = []; const roles: string[] = [];
(props.blueprint as UnitBlueprint).loadouts?.forEach((loadout) => { (props.blueprint as UnitBlueprint).loadouts?.forEach((loadout) => {
@@ -87,14 +117,16 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
inline-flex w-full flex-row content-center justify-between inline-flex w-full flex-row content-center justify-between
`} `}
> >
<OlCoalitionToggle {!props.coalition && (
coalition={spawnCoalition} <OlCoalitionToggle
onClick={() => { coalition={spawnCoalition}
spawnCoalition === "blue" && setSpawnCoalition("neutral"); onClick={() => {
spawnCoalition === "neutral" && setSpawnCoalition("red"); spawnCoalition === "blue" && setSpawnCoalition("neutral");
spawnCoalition === "red" && setSpawnCoalition("blue"); spawnCoalition === "neutral" && setSpawnCoalition("red");
}} spawnCoalition === "red" && setSpawnCoalition("blue");
/> }}
/>
)}
<OlNumberInput <OlNumberInput
value={spawnNumber} value={spawnNumber}
min={minNumber} min={minNumber}
@@ -203,14 +235,14 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
</OlDropdown> </OlDropdown>
</div> </div>
</div> </div>
<div {spawnLoadout && spawnLoadout.items.length > 0 && (
className={` <div
flex h-fit flex-col gap-1 p-4 className={`
dark:bg-olympus-200/30 flex h-fit flex-col gap-1 p-4
`} dark:bg-olympus-200/30
> `}
{spawnLoadout && >
spawnLoadout.items.map((item) => { {spawnLoadout.items.map((item) => {
return ( return (
<div className="flex content-center gap-2"> <div className="flex content-center gap-2">
<div <div
@@ -233,7 +265,25 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
</div> </div>
); );
})} })}
</div> </div>
)}
{!props.spawnAtLocation && (
<button
type="button"
className={`
m-2 rounded-lg bg-blue-700 px-5 py-2.5 text-sm font-medium
text-white
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
focus:outline-none focus:ring-4 focus:ring-blue-300
hover:bg-blue-800
`}
onClick={() => {
spawnAtAirbase();
}}
>
Spawn
</button>
)}
</div> </div>
); );
} }

View File

@@ -18,16 +18,19 @@ import { sha256 } from "js-sha256";
import { MiniMapPanel } from "./panels/minimappanel"; import { MiniMapPanel } from "./panels/minimappanel";
import { UnitMouseControlBar } from "./panels/unitmousecontrolbar"; import { UnitMouseControlBar } from "./panels/unitmousecontrolbar";
import { DrawingMenu } from "./panels/drawingmenu"; import { DrawingMenu } from "./panels/drawingmenu";
import { ControlsPanel } from "./panels/controls"; import { ControlsPanel } from "./panels/controlspanel";
import { MapContextMenu } from "./contextmenus/mapcontextmenu"; import { MapContextMenu } from "./contextmenus/mapcontextmenu";
import { AirbaseMenu } from "./panels/airbasemenu";
import { Airbase } from "../mission/airbase";
export type OlympusState = { export type OlympusUIState = {
mainMenuVisible: boolean; mainMenuVisible: boolean;
spawnMenuVisible: boolean; spawnMenuVisible: boolean;
unitControlMenuVisible: boolean; unitControlMenuVisible: boolean;
measureMenuVisible: boolean; measureMenuVisible: boolean;
drawingMenuVisible: boolean; drawingMenuVisible: boolean;
optionsMenuVisible: boolean; optionsMenuVisible: boolean;
airbaseMenuVisible: boolean;
mapHiddenTypes: MapHiddenTypes; mapHiddenTypes: MapHiddenTypes;
mapOptions: MapOptions; mapOptions: MapOptions;
}; };
@@ -40,6 +43,7 @@ export function UI() {
const [measureMenuVisible, setMeasureMenuVisible] = useState(false); const [measureMenuVisible, setMeasureMenuVisible] = useState(false);
const [drawingMenuVisible, setDrawingMenuVisible] = useState(false); const [drawingMenuVisible, setDrawingMenuVisible] = useState(false);
const [optionsMenuVisible, setOptionsMenuVisible] = useState(false); const [optionsMenuVisible, setOptionsMenuVisible] = useState(false);
const [airbaseMenuVisible, setAirbaseMenuVisible] = useState(false);
const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS); const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS);
const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS); const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
const [checkingPassword, setCheckingPassword] = useState(false); const [checkingPassword, setCheckingPassword] = useState(false);
@@ -48,6 +52,7 @@ export function UI() {
const [mapSources, setMapSources] = useState([] as string[]); const [mapSources, setMapSources] = useState([] as string[]);
const [activeMapSource, setActiveMapSource] = useState(""); const [activeMapSource, setActiveMapSource] = useState("");
const [mapState, setMapState] = useState(IDLE); const [mapState, setMapState] = useState(IDLE);
const [airbase, setAirbase] = useState(null as null | Airbase);
useEffect(() => { useEffect(() => {
document.addEventListener("hiddenTypesChanged", (ev) => { document.addEventListener("hiddenTypesChanged", (ev) => {
@@ -75,6 +80,13 @@ export function UI() {
setMapSources(sources); setMapSources(sources);
setActiveMapSource(sources[0]); setActiveMapSource(sources[0]);
}); });
document.addEventListener("airbaseclick", (ev) => {
hideAllMenus();
getApp().getMap().setState(IDLE);
setAirbase((ev as CustomEvent).detail);
setAirbaseMenuVisible(true);
});
}, []); }, []);
function hideAllMenus() { function hideAllMenus() {
@@ -84,6 +96,7 @@ export function UI() {
setMeasureMenuVisible(false); setMeasureMenuVisible(false);
setDrawingMenuVisible(false); setDrawingMenuVisible(false);
setOptionsMenuVisible(false); setOptionsMenuVisible(false);
setAirbaseMenuVisible(false);
} }
function checkPassword(password: string) { function checkPassword(password: string) {
@@ -139,6 +152,7 @@ export function UI() {
measureMenuVisible: measureMenuVisible, measureMenuVisible: measureMenuVisible,
drawingMenuVisible: drawingMenuVisible, drawingMenuVisible: drawingMenuVisible,
optionsMenuVisible: optionsMenuVisible, optionsMenuVisible: optionsMenuVisible,
airbaseMenuVisible: airbaseMenuVisible,
mapOptions: mapOptions, mapOptions: mapOptions,
mapHiddenTypes: mapHiddenTypes, mapHiddenTypes: mapHiddenTypes,
mapSources: mapSources, mapSources: mapSources,
@@ -154,6 +168,7 @@ export function UI() {
setDrawingMenuVisible: setDrawingMenuVisible, setDrawingMenuVisible: setDrawingMenuVisible,
setMeasureMenuVisible: setMeasureMenuVisible, setMeasureMenuVisible: setMeasureMenuVisible,
setOptionsMenuVisible: setOptionsMenuVisible, setOptionsMenuVisible: setOptionsMenuVisible,
setAirbaseMenuVisible: setAirbaseMenuVisible,
toggleMainMenuVisible: () => { toggleMainMenuVisible: () => {
hideAllMenus(); hideAllMenus();
setMainMenuVisible(!mainMenuVisible); setMainMenuVisible(!mainMenuVisible);
@@ -178,6 +193,10 @@ export function UI() {
hideAllMenus(); hideAllMenus();
setOptionsMenuVisible(!optionsMenuVisible); setOptionsMenuVisible(!optionsMenuVisible);
}, },
toggleAirbaseMenuVisible: () => {
hideAllMenus();
setAirbaseMenuVisible(!airbaseMenuVisible);
},
}} }}
> >
<Header /> <Header />
@@ -211,6 +230,7 @@ export function UI() {
<Options open={optionsMenuVisible} onClose={() => setOptionsMenuVisible(false)} options={mapOptions} /> <Options open={optionsMenuVisible} onClose={() => setOptionsMenuVisible(false)} options={mapOptions} />
<UnitControlMenu open={unitControlMenuVisible} onClose={() => setUnitControlMenuVisible(false)} /> <UnitControlMenu open={unitControlMenuVisible} onClose={() => setUnitControlMenuVisible(false)} />
<DrawingMenu open={drawingMenuVisible} onClose={() => setDrawingMenuVisible(false)} /> <DrawingMenu open={drawingMenuVisible} onClose={() => setDrawingMenuVisible(false)} />
<AirbaseMenu open={airbaseMenuVisible} onClose={() => setAirbaseMenuVisible(false)} airbase={airbase}/>
<MiniMapPanel /> <MiniMapPanel />
<ControlsPanel /> <ControlsPanel />