From 169a05ed8fc7b7dd560c9d6b5053fc3ae00dabbc Mon Sep 17 00:00:00 2001
From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com>
Date: Tue, 1 Jul 2025 00:58:26 -0700
Subject: [PATCH 1/2] Fixed Chat height
---
apps/dispatch/app/_components/left/Chat.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/dispatch/app/_components/left/Chat.tsx b/apps/dispatch/app/_components/left/Chat.tsx
index 8ef1cbc4..b3a9a4bf 100644
--- a/apps/dispatch/app/_components/left/Chat.tsx
+++ b/apps/dispatch/app/_components/left/Chat.tsx
@@ -68,7 +68,7 @@ export const Chat = () => {
{chatOpen && (
-
{/* Rettungsmittel Section */}
Rettungsmittel
-
@@ -371,11 +358,12 @@ export const MissionForm = () => {
form.setValue("hpgMissionString", e.target.value);
const [name] = e.target.value.split(":");
const allHpgMissionTypes = keywords?.map((k) => k.hpgMissionTypes).flat();
+ const missionAdditionalInfo = form.watch("missionAdditionalInfo");
if (
- !form.watch("missionAdditionalInfo") ||
+ !missionAdditionalInfo ||
allHpgMissionTypes?.find((t) => {
const [hpgName] = t.split(":");
- return hpgName === form.watch("missionAdditionalInfo");
+ return hpgName === missionAdditionalInfo;
})
) {
form.setValue("missionAdditionalInfo", name || "");
@@ -444,7 +432,7 @@ export const MissionForm = () => {
try {
console.log("Saving mission", mission.addressOSMways);
const newMission = await saveMission(mission);
- toast.success(`Einsatz ${newMission.id} erfolgreich aktualisiert`);
+ toast.success(`Einsatz ${newMission.publicId} aktualisiert`);
setSearchElements([]); // Reset search elements
setEditingMission(null); // Reset editing state
form.reset(); // Reset the form
diff --git a/apps/dispatch/app/_components/Select.tsx b/apps/dispatch/app/_components/Select.tsx
index 60ea8e27..81e38ff4 100644
--- a/apps/dispatch/app/_components/Select.tsx
+++ b/apps/dispatch/app/_components/Select.tsx
@@ -1,16 +1,8 @@
"use client";
-import { FieldValues, Path, RegisterOptions, UseFormReturn } from "react-hook-form";
+import { FieldValues, Path } from "react-hook-form";
import SelectTemplate, { Props as SelectTemplateProps, StylesConfig } from "react-select";
import { cn } from "@repo/shared-components";
import dynamic from "next/dynamic";
-import { CSSProperties } from "react";
-
-interface SelectProps
extends Omit {
- label?: any;
- name: Path;
- form: UseFormReturn | any;
- formOptions?: RegisterOptions;
-}
const customStyles: StylesConfig = {
control: (provided) => ({
@@ -28,7 +20,7 @@ const customStyles: StylesConfig = {
...provided,
backgroundColor: state.isSelected ? "hsl(var(--p))" : "hsl(var(--b1))",
color: "var(--color-primary-content)",
- "&:hover": { backgroundColor: "var(--color-base-200)" }, // DaisyUI secondary color
+ "&:hover": { backgroundColor: "var(--color-base-200)" },
}),
multiValueLabel: (provided) => ({
...provided,
@@ -46,53 +38,55 @@ const customStyles: StylesConfig = {
...provided,
backgroundColor: "var(--color-base-100)",
borderRadius: "0.5rem",
+ zIndex: 9999,
}),
};
-const SelectCom = ({
- name,
- label = name,
+interface SelectProps extends Omit {
+ label?: any;
+ value: any;
+ onChange: (value: any) => void;
+ error?: string;
+}
+
+const SelectCom = ({
+ label,
placeholder = label,
- form,
- formOptions,
+ value,
+ onChange,
+ error,
className,
...inputProps
-}: SelectProps) => {
+}: SelectProps) => {
return (
-
+
{label}
{
- if (Array.isArray(newValue)) {
- form.setValue(name, newValue.map((v: any) => v.value) as any, {
- shouldDirty: true,
- });
+ if ((inputProps as any)?.isMulti) {
+ onChange(Array.isArray(newValue) ? newValue.map((v: any) => v.value) : []);
} else {
- form.setValue(name, newValue.value, {
- shouldDirty: true,
- });
+ onChange(newValue ? newValue.value : null);
}
- form.trigger(name);
- form.Dirty;
}}
value={
(inputProps as any)?.isMulti
- ? (inputProps as any).options?.filter((o: any) => form.watch(name)?.includes(o.value))
- : (inputProps as any).options?.find((o: any) => o.value === form.watch(name))
+ ? (inputProps as any).options?.filter(
+ (o: any) => Array.isArray(value) && value.includes(o.value),
+ )
+ : (inputProps as any).options?.find((o: any) => o.value === value)
}
styles={customStyles as any}
className={cn("w-full placeholder:text-neutral-600", className)}
placeholder={placeholder}
{...inputProps}
/>
- {form.formState.errors[name]?.message && (
- {form.formState.errors[name].message as string}
- )}
+ {error && {error}
}
);
};
-const SelectWrapper =
(props: SelectProps) => ;
+const SelectWrapper = (props: SelectProps) => ;
export const Select = dynamic(() => Promise.resolve(SelectWrapper), {
ssr: false,
diff --git a/apps/dispatch/app/_components/left/Chat.tsx b/apps/dispatch/app/_components/left/Chat.tsx
index b3a9a4bf..79ae6b36 100644
--- a/apps/dispatch/app/_components/left/Chat.tsx
+++ b/apps/dispatch/app/_components/left/Chat.tsx
@@ -140,6 +140,7 @@ export const Chat = () => {
{chat.notification && }
+ {/* So macht man kein overflow handeling, weiß ich. Aber es funktioniert... */}
{chat.messages.map((chatMessage) => {
const isSender = chatMessage.senderId === session.data?.user.id;
return (
diff --git a/apps/dispatch/app/_components/map/BaseMaps.tsx b/apps/dispatch/app/_components/map/BaseMaps.tsx
index 6c377602..3da4b31a 100644
--- a/apps/dispatch/app/_components/map/BaseMaps.tsx
+++ b/apps/dispatch/app/_components/map/BaseMaps.tsx
@@ -1,7 +1,7 @@
"use client";
import { usePannelStore } from "_store/pannelStore";
import { Control, Icon, LatLngExpression } from "leaflet";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useMemo, useRef, useState } from "react";
import {
LayerGroup,
LayersControl,
@@ -73,9 +73,9 @@ const StationsLayer = ({ attribution }: { attribution: Control.Attribution }) =>
queryKey: ["stations"],
queryFn: () => getStationsAPI(),
});
+ console.log("StationsLayer: stations", stations);
const [selectedStations, setSelectedStations] = useState
([]);
- const [stationsWithIcon, setStationsWithIcon] = useState<(Station & { icon?: string })[]>([]); // Zustand für die Stationen mit Icon
const attributionText = "";
const resetSelection = () => {
@@ -94,27 +94,29 @@ const StationsLayer = ({ attribution }: { attribution: Control.Attribution }) =>
}
};
- useEffect(() => {
- // Erstelle die Icons für alle Stationen
+ const [stationsWithIcon, setStationsWithIcon] = useState<(Station & { icon: string })[]>([]);
+ useEffect(() => {
+ if (!stations) {
+ setStationsWithIcon([]);
+ return;
+ }
const fetchIcons = async () => {
- if (!stations) return;
const urls = await Promise.all(
stations.map(async (station) => {
- return createCustomMarker(station.operator);
+ return await createCustomMarker(station.operator);
}),
);
- setStationsWithIcon(stations.map((station, index) => ({ ...station, icon: urls[index] })));
+ setStationsWithIcon(stations.map((station, index) => ({ ...station, icon: urls[index]! })));
};
-
fetchIcons();
}, [stations]);
return (
- {stationsWithIcon.map((station) => {
+ {stationsWithIcon?.map((station) => {
const coordinates: LatLngExpression = [station.latitude, station.longitude];
- const typeLabel = station.bosUse.charAt(0).toUpperCase();
+ const typeLabel = station.bosUse?.charAt(0).toUpperCase();
return (
{
},
});
- const stationsOptions = [
- ...(allStations
- ?.filter((s) => !mission.missionStationIds.includes(s.id))
- ?.map((station) => ({
- label: station.bosCallsign,
- value: station.id,
- type: "station" as const,
- isOnline: !!connectedAircrafts?.find((a) => a.stationId === station.id),
- })) || []),
- ...(!mission.hpgFireEngineState || mission.hpgFireEngineState === "NOT_REQUESTED"
- ? [{ label: "Feuerwehr", value: "FW", type: "vehicle" as const }]
- : []),
- ...(!mission.hpgAmbulanceState || mission.hpgAmbulanceState === "NOT_REQUESTED"
- ? [{ label: "Rettungsdienst", value: "RTW", type: "vehicle" as const }]
- : []),
- ...(!mission.hpgPoliceState || mission.hpgPoliceState === "NOT_REQUESTED"
- ? [{ label: "Polizei", value: "POL", 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);
- });
-
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
const HPGVehicle = ({ state, name }: { state: HpgState; name: string }) => (
@@ -503,70 +471,57 @@ const Rettungsmittel = ({ mission }: { mission: Mission }) => {
const connectedAircraft = connectedAircrafts?.find(
(aircraft) => aircraft.stationId === station.id,
);
+ console.log("connectedAircraft", connectedAircraft);
return (
- {connectedAircraft && (
-
- {connectedAircraft.fmsStatus}
-
- )}
-
-
- {station.bosCallsign}
- {/* {item.min > 0 && (
- <>
-
- Ankunft in ca. {item.min} min
- >
- )} */}
-
+
+ {connectedAircraft?.fmsStatus || "6"}
+
+
+ {station.bosCallsign}
+ {!connectedAircraft && (
+ Kein Benutzer verbunden
+ )}
);
})}
- {mission.hpgAmbulanceState && }
- {mission.hpgFireEngineState && (
+ {mission.hpgAmbulanceState && mission.hpgAmbulanceState !== "NOT_REQUESTED" && (
+
+ )}
+ {mission.hpgFireEngineState && mission.hpgFireEngineState !== "NOT_REQUESTED" && (
)}
- {mission.hpgPoliceState && }
+ {mission.hpgPoliceState && mission.hpgPoliceState !== "NOT_REQUESTED" && (
+
+ )}
{dispatcherConnected && (
{/* TODO: make it a small multiselect */}
-
+ selectedStations={mission.missionStationIds}
+ filterSelected
+ vehicleStates={{
+ hpgAmbulanceState: mission.hpgAmbulanceState || undefined,
+ hpgFireEngineState: mission.hpgFireEngineState || undefined,
+ hpgPoliceState: mission.hpgPoliceState || undefined,
+ }}
+ />