Added autoFocus on Sds and MissionLog

This commit is contained in:
PxlLoewe
2025-06-09 23:43:51 -07:00
parent b4b7b4def2
commit 66a65ab9a4
9 changed files with 72 additions and 59 deletions

View File

@@ -14,32 +14,5 @@ export const handleConnectDesktop = (socket: Socket, io: Server) => () => {
socket.on("ptt", async (data: PTTData) => {
socket.to(`user:${user.id}`).emit("ptt", data);
const connectedAircraft = await prisma.connectedAircraft.findFirst({
where: {
userId: user.id,
logoutTime: null,
},
include: {
Station: true,
},
});
const connectedDispatcher = await prisma.connectedDispatcher.findFirst({
where: {
userId: user.id,
logoutTime: null,
},
});
const otherPttData = {
publicUser: getPublicUser(user),
source:
connectedAircraft?.Station.bosCallsignShort || connectedDispatcher
? "Leitstelle"
: user.publicId,
};
if (data.shouldTransmit) {
socket.to("dispatchers").emit("other-ptt", otherPttData);
socket.to("pilots").emit("other-ptt", otherPttData);
}
});
};

View File

@@ -112,22 +112,6 @@ export const handleConnectPilot =
connectedAircraftEntry,
);
// Add a listener for station-specific events
socket.on("ptt", async ({ shouldTransmit, channel }) => {
if (shouldTransmit) {
io.to("dispatchers").emit("other-ptt", {
publicUser: getPublicUser(user),
channel,
source: Station?.bosCallsignShort,
});
io.to("piots").emit("other-ptt", {
publicUser: getPublicUser(user),
channel,
source: Station?.bosCallsignShort,
});
}
});
socket.on("disconnect", async () => {
await prisma.connectedAircraft
.update({

View File

@@ -12,7 +12,11 @@ import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
export const SituationBoard = () => {
const { setSituationTabOpen, situationTabOpen } = useLeftMenuStore();
const dispatcherConnected = useDispatchConnectionStore((state) => state.status === "connected");
const { status, setHideDraftMissions, hideDraftMissions } = useDispatchConnectionStore(
(state) => state,
);
const dispatcherConnected = status === "connected";
const { data: missions } = useQuery({
queryKey: ["missions", "missions-on-stations"],
queryFn: () =>
@@ -34,6 +38,11 @@ export const SituationBoard = () => {
},
),
});
const filteredMissions = missions?.filter(
(mission) => !hideDraftMissions || mission.state !== "draft",
);
const { data: connectedAircrafts } = useQuery({
queryKey: ["aircrafts"],
queryFn: () => getConnectedAircraftsAPI(),
@@ -60,8 +69,21 @@ export const SituationBoard = () => {
<div className="card-body flex flex-row gap-4">
<div className="flex-1">
<h2 className="inline-flex items-center gap-2 text-lg font-bold mb-2">
<ListCollapse /> Einsatzliste
<ListCollapse /> Einsatzliste{" "}
</h2>
<div>
<div className="form-control mb-2">
<label className="label cursor-pointer">
<input
type="checkbox"
className="checkbox checkbox-sm"
checked={hideDraftMissions}
onChange={() => setHideDraftMissions(!hideDraftMissions)}
/>
<span className="label-text text-sm">vorgeplante Einsätze verbergen</span>
</label>
</div>
</div>
<div className="overflow-x-auto">
<table className="table table-xs">
{/* head */}
@@ -74,8 +96,7 @@ export const SituationBoard = () => {
</tr>
</thead>
<tbody>
{/* row 1 */}
{missions?.map(
{filteredMissions?.map(
(mission) =>
(dispatcherConnected || mission.state !== "draft") && (
<tr

View File

@@ -365,7 +365,9 @@ const MissionMarker = ({ mission }: { mission: Mission }) => {
};
export const MissionLayer = () => {
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
const dispatchState = useDispatchConnectionStore((s) => s);
const dispatcherConnected = dispatchState.status === "connected";
const { data: missions = [] } = useQuery({
queryKey: ["missions"],
queryFn: () =>
@@ -377,10 +379,15 @@ export const MissionLayer = () => {
const filteredMissions = useMemo(() => {
if (!dispatcherConnected) {
return missions.filter((m: Mission) => m.state === "running");
return missions.filter((m: Mission) => {
m.state === "running";
});
}
if (dispatchState.hideDraftMissions) {
return missions.filter((m: Mission) => m.state !== "draft");
}
return missions;
}, [missions, dispatcherConnected]);
}, [missions, dispatcherConnected, dispatchState.hideDraftMissions]);
// IDEA: Add Marker to Map Layer / LayerGroup
return (

View File

@@ -334,6 +334,7 @@ const SDSTab = ({
const [isChatOpen, setIsChatOpen] = useState(false);
const [note, setNote] = useState("");
const queryClient = useQueryClient();
const textInputRef = React.useRef<HTMLInputElement>(null);
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
@@ -352,13 +353,23 @@ const SDSTab = ({
},
});
const log =
(mission?.missionLog as unknown as MissionLog[])
?.slice()
.reverse()
.filter(
(entry) => entry.type === "sds-log" && entry.data.stationId === aircraft.Station.id,
) || [];
const log = useMemo(
() =>
(mission?.missionLog as unknown as MissionLog[])
?.slice()
.reverse()
.filter(
(entry) => entry.type === "sds-log" && entry.data.stationId === aircraft.Station.id,
) || [],
[mission?.missionLog, aircraft.Station.id],
);
useEffect(() => {
const interval = setInterval(() => {
textInputRef.current?.focus();
}, 100);
return () => clearInterval(interval);
});
return (
<div className="p-4">
@@ -377,11 +388,13 @@ const SDSTab = ({
) : (
<div className="flex items-center gap-2 w-full">
<input
autoFocus
type="text"
placeholder=""
className="input input-sm text-base-content flex-1"
value={note}
onChange={(e) => setNote(e.target.value)}
ref={textInputRef}
/>
<button
className="btn btn-sm btn-primary btn-outline"

View File

@@ -591,6 +591,7 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
const [isAddingNote, setIsAddingNote] = useState(false);
const [note, setNote] = useState("");
const queryClient = useQueryClient();
const textInputRef = React.useRef<HTMLInputElement>(null);
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
@@ -603,6 +604,13 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
},
});
useEffect(() => {
const interval = setInterval(() => {
textInputRef.current?.focus();
}, 100);
return () => clearInterval(interval);
});
if (!session.data?.user) return null;
return (
<div className="p-4">
@@ -626,6 +634,7 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
className="input input-sm text-base-content flex-1"
value={note}
onChange={(e) => setNote(e.target.value)}
ref={textInputRef}
/>
<button
className="btn btn-sm btn-primary btn-outline"

View File

@@ -5,6 +5,8 @@ import { ConnectedDispatcher } from "@repo/db";
interface ConnectionStore {
status: "connected" | "disconnected" | "connecting" | "error";
hideDraftMissions: boolean;
setHideDraftMissions: (hide: boolean) => void;
connectedDispatcher: ConnectedDispatcher | null;
message: string;
selectedZone: string;
@@ -15,6 +17,8 @@ interface ConnectionStore {
export const useDispatchConnectionStore = create<ConnectionStore>((set) => ({
status: "disconnected",
hideDraftMissions: false,
setHideDraftMissions: (hide) => set({ hideDraftMissions: hide }),
connectedDispatcher: null,
message: "",
selectedZone: "LST_01",

View File

@@ -9,6 +9,7 @@ import { useAudioStore } from "_store/audioStore";
interface ConnectionStore {
status: "connected" | "disconnected" | "connecting" | "error";
message: string;
logoffTime: string;
selectedStation: Station | null;
connectedAircraft: ConnectedAircraft | null;
@@ -34,6 +35,7 @@ export const usePilotConnectionStore = create<ConnectionStore>((set) => ({
selectedStation: null,
connectedAircraft: null,
activeMission: null,
connect: async (uid, stationId, logoffTime, station, user) =>
new Promise((resolve) => {
set({

View File

@@ -1,4 +1,4 @@
import { BADGES, PublicUser } from "@repo/db";
import { asPublicUser, BADGES, PublicUser } from "@repo/db";
import { useQuery } from "@tanstack/react-query";
import { Badge } from "_components/Badge/Badge";
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
@@ -70,7 +70,7 @@ export const ConnectedDispatcher = () => {
)}
</div>
<div>
<div>{(d.publicUser as unknown as PublicUser)?.firstname}</div>
<div>{asPublicUser(d.publicUser).fullName}</div>
<div className="text-xs uppercase font-semibold opacity-60">{d.zone}</div>
</div>
<div>