diff --git a/apps/dispatch-server/routes/aircraft.ts b/apps/dispatch-server/routes/aircraft.ts
index fa665438..c3ff5d44 100644
--- a/apps/dispatch-server/routes/aircraft.ts
+++ b/apps/dispatch-server/routes/aircraft.ts
@@ -2,7 +2,6 @@ import {
AdminMessage,
getPublicUser,
MissionLog,
- MissionSdsStatusLog,
NotificationPayload,
Prisma,
prisma,
@@ -131,44 +130,6 @@ router.patch("/:id", async (req, res) => {
}
});
-router.post("/:id/send-sds-message", async (req, res) => {
- const { id } = req.params;
- const { sdsMessage } = req.body as { sdsMessage: MissionSdsStatusLog };
-
- if (!sdsMessage.data.stationId || !id) {
- res.status(400).json({ error: "Missing aircraftId or stationId" });
- return;
- }
-
- await prisma.mission.updateMany({
- where: {
- state: "running",
- missionStationIds: {
- has: sdsMessage.data.stationId,
- },
- },
- data: {
- missionLog: {
- push: sdsMessage as unknown as Prisma.InputJsonValue,
- },
- },
- });
-
- io.to(
- sdsMessage.data.direction === "to-lst" ? "dispatchers" : `station:${sdsMessage.data.stationId}`,
- ).emit(sdsMessage.data.direction === "to-lst" ? "notification" : "sds-status", {
- type: "station-status",
- status: sdsMessage.data.status,
- message: "SDS Status Message",
- data: {
- aircraftId: parseInt(id),
- stationId: sdsMessage.data.stationId,
- },
- } as NotificationPayload);
-
- res.sendStatus(204);
-});
-
// Kick a connectedAircraft by ID
router.delete("/:id", async (req, res) => {
const { id } = req.params;
diff --git a/apps/dispatch/Dockerfile b/apps/dispatch/Dockerfile
index 1236c9d6..315d8d76 100644
--- a/apps/dispatch/Dockerfile
+++ b/apps/dispatch/Dockerfile
@@ -1,12 +1,12 @@
FROM node:22-alpine AS base
-ARG NEXT_PUBLIC_DISPATCH_URL="http://localhost:3001"
-ARG NEXT_PUBLIC_DISPATCH_SERVER_URL="http://localhost:4001"
-ARG NEXT_PUBLIC_HUB_URL="http://localhost:3002"
-ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID="1"
-ARG NEXT_PUBLIC_LIVEKIT_URL="http://localhost:7880"
-ARG NEXT_PUBLIC_DISCORD_URL="https://discord.com"
-ARG NEXT_PUBLIC_OPENAIP_ACCESS=""
+ARG NEXT_PUBLIC_DISPATCH_URL
+ARG NEXT_PUBLIC_DISPATCH_SERVER_URL
+ARG NEXT_PUBLIC_HUB_URL
+ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID
+ARG NEXT_PUBLIC_LIVEKIT_URL
+ARG NEXT_PUBLIC_DISCORD_URL
+ARG NEXT_PUBLIC_OPENAIP_ACCESS
ENV NEXT_PUBLIC_DISPATCH_SERVER_URL=$NEXT_PUBLIC_DISPATCH_SERVER_URL
ENV NEXT_PUBLIC_DISPATCH_URL=$NEXT_PUBLIC_DISPATCH_URL
@@ -16,13 +16,13 @@ ENV NEXT_PUBLIC_LIVEKIT_URL=$NEXT_PUBLIC_LIVEKIT_URL
ENV NEXT_PUBLIC_OPENAIP_ACCESS=$NEXT_PUBLIC_OPENAIP_ACCESS
ENV NEXT_PUBLIC_DISCORD_URL=$NEXT_PUBLIC_DISCORD_URL
-FROM base AS builder
-
ENV PNPM_HOME="/usr/local/pnpm"
ENV PATH="${PNPM_HOME}:${PATH}"
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm add -g turbo@^2.5
+
+FROM base AS builder
RUN apk update
RUN apk add --no-cache libc6-compat
@@ -31,20 +31,12 @@ WORKDIR /usr/app
RUN echo "NEXT_PUBLIC_HUB_URL is: $NEXT_PUBLIC_HUB_URL"
RUN echo "NEXT_PUBLIC_DISPATCH_SERVICE_ID is: $NEXT_PUBLIC_DISPATCH_SERVICE_ID"
RUN echo "NEXT_PUBLIC_DISPATCH_SERVER_URL is: $NEXT_PUBLIC_DISPATCH_SERVER_URL"
-RUN echo "NEXT_PUBLIC_LIVEKIT_URL is: $NEXT_PUBLIC_LIVEKIT_URL"
COPY . .
RUN turbo prune dispatch --docker
FROM base AS installer
-
-ENV PNPM_HOME="/usr/local/pnpm"
-ENV PATH="${PNPM_HOME}:${PATH}"
-RUN corepack enable && corepack prepare pnpm@latest --activate
-
-RUN pnpm add -g turbo@^2.5
-
RUN apk update
RUN apk add --no-cache libc6-compat
@@ -58,22 +50,19 @@ COPY --from=builder /usr/app/out/full/ .
RUN turbo run build
-FROM node:22-alpine AS runner
+FROM base AS runner
WORKDIR /usr/app
# Don't run production as root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
+USER nextjs
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
-COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/standalone ./
-COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/static ./apps/dispatch/.next/static
-COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/public ./apps/dispatch/public
-
-USER nextjs
+COPY --from=installer --chown=nextjs:nodejs /usr/app/ ./
# Expose the application port
-EXPOSE 3000
+EXPOSE 3001
-CMD ["node", "apps/dispatch/server.js"]
\ No newline at end of file
+CMD ["pnpm", "--dir", "apps/dispatch", "run", "start"]
\ No newline at end of file
diff --git a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx
index 039d7ac2..f1450f19 100644
--- a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx
+++ b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx
@@ -14,7 +14,7 @@ export const ConnectionBtn = () => {
const connection = useDispatchConnectionStore((state) => state);
const [form, setForm] = useState({
logoffTime: "",
- selectedZone: "VAR_LST_RD_01",
+ selectedZone: "LST_01",
ghostMode: false,
});
const changeDispatcherMutation = useMutation({
diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx
deleted file mode 100644
index 169b7d24..00000000
--- a/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { useEffect } from "react"; // ...existing code...
-import { useMrtStore } from "_store/pilot/MrtStore";
-import Image from "next/image";
-import DAY_BASE_IMG from "./images/Base_NoScreen_Day.png";
-import NIGHT_BASE_IMG from "./images/Base_NoScreen_Night.png";
-
-export const MrtBase = () => {
- const { nightMode, setNightMode, page } = useMrtStore((state) => state);
-
- useEffect(() => {
- const checkNightMode = () => {
- const currentHour = new Date().getHours();
- setNightMode(currentHour >= 22 || currentHour < 8);
- };
-
- checkNightMode(); // Initial check
- const intervalId = setInterval(checkNightMode, 60000); // Check every minute
-
- return () => clearInterval(intervalId); // Cleanup on unmount
- }, [setNightMode]); // ...existing code...
-
- return (
-
- );
-};
diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png
new file mode 100644
index 00000000..a9c552b1
Binary files /dev/null and b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png differ
diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png
new file mode 100644
index 00000000..a0e80ae6
Binary files /dev/null and b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png differ
diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx
index 0fda6281..5d271921 100644
--- a/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx
+++ b/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx
@@ -1,9 +1,22 @@
import { CSSProperties } from "react";
+import MrtImage from "./MRT.png";
+import MrtMessageImage from "./MRT_MESSAGE.png";
+import { useButtons } from "./useButtons";
+import { useSounds } from "./useSounds";
import "./mrt.css";
-import { MrtBase } from "./Base";
-import { MrtDisplay } from "./MrtDisplay";
-import { MrtButtons } from "./MrtButtons";
-import { MrtPopups } from "./MrtPopups";
+import Image from "next/image";
+import { useMrtStore } from "_store/pilot/MrtStore";
+
+const MRT_BUTTON_STYLES: CSSProperties = {
+ cursor: "pointer",
+ zIndex: "9999",
+ backgroundColor: "transparent",
+ border: "none",
+};
+const MRT_DISPLAYLINE_STYLES: CSSProperties = {
+ color: "white",
+ zIndex: 1,
+};
export interface DisplayLineProps {
lineStyle?: CSSProperties;
@@ -14,7 +27,45 @@ export interface DisplayLineProps {
textSize: "1" | "2" | "3" | "4";
}
+const DisplayLine = ({
+ style = {},
+ textLeft,
+ textMid,
+ textRight,
+ textSize,
+ lineStyle,
+}: DisplayLineProps) => {
+ const INNER_TEXT_PARTS: CSSProperties = {
+ fontFamily: "Melder",
+ flex: "1",
+ flexBasis: "auto",
+ overflowWrap: "break-word",
+ ...lineStyle,
+ };
+
+ return (
+
+ {textLeft}
+ {textMid}
+ {textRight}
+
+ );
+};
+
export const Mrt = () => {
+ useSounds();
+ const { handleButton } = useButtons();
+ const { lines, page } = useMrtStore((state) => state);
+
return (
{
maxHeight: "100%",
maxWidth: "100%",
color: "white",
- gridTemplateColumns:
- "9.75% 4.23% 8.59% 7.30% 1.16% 7.30% 1.23% 7.16% 1.09% 7.30% 3.68% 4.23% 5.59% 6.07% 1.91% 6.07% 1.84% 6.21% 9.28%",
- gridTemplateRows:
- "21.55% 11.83% 3.55% 2.50% 9.46% 2.76% 0.66% 4.99% 6.83% 3.55% 1.97% 9.99% 4.20% 11.04% 5.12%",
+ gridTemplateColumns: "21.83% 4.43% 24.42% 18.08% 5.93% 1.98% 6.00% 1.69% 6.00% 9.35%",
+ gridTemplateRows: "21.58% 11.87% 3.55% 5.00% 6.84% 0.53% 3.03% 11.84% 3.55% 11.84% 20.39%",
}}
>
-
-
-
-
+ {page !== "sds" && (
+
+ )}
+ {page === "sds" && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {lines[0] && (
+
+ )}
+ {lines[1] && (
+
+ )}
+ {lines[2] && (
+
+ )}
+ {lines[3] && (
+
+ )}
);
};
diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx
deleted file mode 100644
index a7942466..00000000
--- a/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import { CSSProperties, useRef } from "react";
-import { useButtons } from "./useButtons";
-
-const MRT_BUTTON_STYLES: CSSProperties = {
- cursor: "pointer",
- zIndex: "9999",
- backgroundColor: "transparent",
- border: "none",
-};
-
-interface MrtButtonProps {
- onClick: () => void;
- onHold?: () => void;
- style: CSSProperties;
-}
-
-const MrtButton = ({ onClick, onHold, style }: MrtButtonProps) => {
- const timeoutRef = useRef(null);
-
- const handleMouseDown = () => {
- if (!onHold) return;
- timeoutRef.current = setTimeout(handleTimeoutExpired, 500);
- };
-
- const handleTimeoutExpired = () => {
- timeoutRef.current = null;
- if (onHold) {
- onHold();
- }
- };
-
- const handleMouseUp = () => {
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- onClick();
- }
- };
-
- return (
-