172 lines
5.8 KiB
TypeScript
172 lines
5.8 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
import { HpgState } from "@repo/db";
|
|
import { cn } from "@repo/shared-components";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { Select } from "_components/Select";
|
|
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
|
import { getStationsAPI } from "_querys/stations";
|
|
import { Ambulance, FireExtinguisher, Radio, Siren } from "lucide-react";
|
|
import { useEffect, useState } from "react";
|
|
|
|
type MissionStationsSelectProps = {
|
|
selectedStations?: number[];
|
|
className?: string;
|
|
menuPlacement?: "top" | "bottom" | "auto"; // Added menuPlacement prop for better control
|
|
onChange?: (value: {
|
|
selectedStationIds: number[];
|
|
hpgAmbulanceState?: HpgState;
|
|
hpgFireEngineState?: HpgState;
|
|
hpgPoliceState?: HpgState;
|
|
}) => void;
|
|
vehicleStates: {
|
|
hpgAmbulanceState?: HpgState;
|
|
hpgFireEngineState?: HpgState;
|
|
hpgPoliceState?: HpgState;
|
|
};
|
|
filterSelected?: boolean; // If true, filter out selected stations from the options
|
|
isMulti?: boolean;
|
|
};
|
|
|
|
export function StationsSelect({
|
|
onChange,
|
|
selectedStations,
|
|
vehicleStates,
|
|
className = "",
|
|
isMulti = true,
|
|
menuPlacement = "bottom",
|
|
filterSelected = false,
|
|
}: MissionStationsSelectProps) {
|
|
const { data: connectedAircrafts } = useQuery({
|
|
queryKey: ["aircrafts"],
|
|
queryFn: () => getConnectedAircraftsAPI(),
|
|
});
|
|
const { data: stations } = useQuery({
|
|
queryKey: ["stations"],
|
|
queryFn: () => getStationsAPI(),
|
|
});
|
|
|
|
const [value, setValue] = useState<string[]>(selectedStations?.map((id) => String(id)) || []);
|
|
|
|
useEffect(() => {
|
|
setValue([
|
|
...(selectedStations || []).map((id) => String(id)),
|
|
...(vehicleStates.hpgAmbulanceState !== HpgState.NOT_REQUESTED || undefined ? ["RTW"] : []),
|
|
...(vehicleStates.hpgFireEngineState !== HpgState.NOT_REQUESTED || undefined ? ["FW"] : []),
|
|
...(vehicleStates.hpgPoliceState !== HpgState.NOT_REQUESTED || undefined ? ["POL"] : []),
|
|
]);
|
|
}, [selectedStations, vehicleStates]);
|
|
|
|
// Helper to check if a station is a vehicle and its state is NOT_REQUESTED
|
|
const stationsOptions = [
|
|
...(stations?.map((station) => ({
|
|
label: station.bosCallsign,
|
|
value: String(station.id),
|
|
type: "station" as const,
|
|
isOnline: !!connectedAircrafts?.find((a) => a.stationId === station.id),
|
|
})) || []),
|
|
|
|
{ label: "Feuerwehr", value: "FW", type: "vehicle" as const },
|
|
{ label: "Polizei", value: "POL", type: "vehicle" as const },
|
|
{ label: "RTW", value: "RTW", type: "vehicle" as const },
|
|
]
|
|
.sort((a, b) => {
|
|
// 1. Vehicles first
|
|
if (a.type === "vehicle" && b.type !== "vehicle") return -1;
|
|
if (a.type !== "vehicle" && b.type === "vehicle") return 1;
|
|
|
|
// 2. Online stations before offline stations
|
|
if (a.type === "station" && b.type === "station") {
|
|
if (a.isOnline && !b.isOnline) return -1;
|
|
if (!a.isOnline && b.isOnline) return 1;
|
|
}
|
|
|
|
// 3. Otherwise, sort alphabetically by label
|
|
return a.label.localeCompare(b.label);
|
|
})
|
|
.filter((s) => {
|
|
if (!filterSelected) return true; // If filterSelected is false, include all stations
|
|
// Filter out selected stations if filterSelectedStations is true
|
|
if (s.type === "station") {
|
|
return !selectedStations?.map(String)?.includes(s.value);
|
|
}
|
|
// If the station is a vehicle, we need to check its state
|
|
if (s.type === "vehicle") {
|
|
if (s.value === "FW" && vehicleStates.hpgFireEngineState !== HpgState.NOT_REQUESTED)
|
|
return false;
|
|
if (s.value === "POL" && vehicleStates.hpgPoliceState !== HpgState.NOT_REQUESTED)
|
|
return false;
|
|
if (s.value === "RTW" && vehicleStates.hpgAmbulanceState !== HpgState.NOT_REQUESTED)
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
return (
|
|
<Select
|
|
className={className}
|
|
menuPlacement={menuPlacement}
|
|
isMulti={isMulti}
|
|
onChange={(v) => {
|
|
setValue(v);
|
|
if (!isMulti) {
|
|
const singleValue = v as string;
|
|
const isVehicle = ["RTW", "FW", "POL"].includes(singleValue);
|
|
|
|
const hpgAmbulanceState =
|
|
singleValue === "RTW" ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
const hpgFireEngineState =
|
|
singleValue === "FW" ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
const hpgPoliceState =
|
|
singleValue === "POL" ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
|
|
onChange?.({
|
|
selectedStationIds: isVehicle ? [] : [Number(singleValue)],
|
|
hpgAmbulanceState,
|
|
hpgFireEngineState,
|
|
hpgPoliceState,
|
|
});
|
|
return;
|
|
}
|
|
const hpgAmbulanceState = v.includes("RTW") ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
const hpgFireEngineState = v.includes("FW") ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
const hpgPoliceState = v.includes("POL") ? HpgState.DISPATCHED : HpgState.NOT_REQUESTED;
|
|
|
|
onChange?.({
|
|
selectedStationIds: v
|
|
.filter((id: string) => !["FW", "POL", "RTW"].includes(id))
|
|
.map(Number),
|
|
hpgAmbulanceState,
|
|
hpgFireEngineState,
|
|
hpgPoliceState,
|
|
});
|
|
}}
|
|
value={value}
|
|
label=""
|
|
placeholder={
|
|
isMulti ? "Wähle ein oder mehrere Rettungsmittel aus" : "Wähle ein Rettungsmittel aus"
|
|
}
|
|
formatOptionLabel={(option: any) => option.component}
|
|
options={stationsOptions.map((s) => ({
|
|
label: s.label,
|
|
component: (
|
|
<div
|
|
className={cn(s.type === "vehicle" && isMulti && "tooltip tooltip-right")}
|
|
data-tip={
|
|
"Wenn kein Pilot mit HPG-Script im Einsatz ist, bleibt dieses Fahrzeug im Status 4."
|
|
}
|
|
>
|
|
<span className="flex items-center gap-2">
|
|
{s.type === "station" && s.isOnline && <Radio className="text-success" size={15} />}
|
|
{s.type === "vehicle" && s.value === "FW" && <FireExtinguisher size={15} />}
|
|
{s.type === "vehicle" && s.value === "POL" && <Siren size={15} />}
|
|
{s.type === "vehicle" && s.value === "RTW" && <Ambulance size={15} />}
|
|
{s.label}
|
|
</span>
|
|
</div>
|
|
),
|
|
value: s.value,
|
|
}))}
|
|
/>
|
|
);
|
|
}
|