Added error fields in mission form

This commit is contained in:
PxlLoewe
2025-06-02 13:02:00 -07:00
parent a92c276bc0
commit 100f4b0a98
7 changed files with 74 additions and 41 deletions

View File

@@ -16,31 +16,37 @@ export const SettingsBtn = () => {
queryKey: ["user", session.data?.user.id], queryKey: ["user", session.data?.user.id],
queryFn: () => getUserAPI(session.data!.user.id), queryFn: () => getUserAPI(session.data!.user.id),
}); });
const testSoundRef = useRef<HTMLAudioElement | null>(null);
const editUserMutation = useMutation({ const editUserMutation = useMutation({
mutationFn: ({ user }: { user: Prisma.UserUpdateInput }) => mutationFn: ({ user }: { user: Prisma.UserUpdateInput }) =>
editUserAPI(session.data!.user.id, user), editUserAPI(session.data!.user.id, user),
}); });
useEffect(() => {
if (typeof window !== "undefined") {
testSoundRef.current = new Audio("/sounds/Melder3.wav");
}
}, []);
const modalRef = useRef<HTMLDialogElement>(null); const modalRef = useRef<HTMLDialogElement>(null);
const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]); const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]);
const [selectedDevice, setSelectedDevice] = useState<string | null>( const [selectedDevice, setSelectedDevice] = useState<string | null>(
user?.settingsMicDevice || null, user?.settingsMicDevice || null,
); );
const [showIndication, setShowInducation] = useState<boolean>(false); const [showIndication, setShowIndication] = useState<boolean>(false);
const [micVol, setMicVol] = useState<number>(1); const [micVol, setMicVol] = useState<number>(1);
const [dmeVolume, setDmeVol] = useState<number>(1); const [dmeVolume, setDmeVol] = useState<number>(1);
const setMic = useAudioStore((state) => state.setMic); const setMic = useAudioStore((state) => state.setMic);
console.log("user", user);
useEffect(() => { useEffect(() => {
if (user) { if (user) {
setSelectedDevice(user.settingsMicDevice); setSelectedDevice(user.settingsMicDevice);
setMic(user.settingsMicDevice, user.settingsMicVolume || 1); setMic(user.settingsMicDevice, user.settingsMicVolume || 1);
setMicVol(user.settingsMicVolume || 1); setMicVol(user.settingsMicVolume || 1);
setDmeVol(user.settingsDmeVolume || 1);
} }
}, [user, setMic]); }, [user, setMic]);
@@ -76,7 +82,7 @@ export const SettingsBtn = () => {
value={selectedDevice ? selectedDevice : ""} value={selectedDevice ? selectedDevice : ""}
onChange={(e) => { onChange={(e) => {
setSelectedDevice(e.target.value); setSelectedDevice(e.target.value);
setShowInducation(true); setShowIndication(true);
}} }}
> >
<option key={0} value={0} disabled> <option key={0} value={0} disabled>
@@ -102,9 +108,7 @@ export const SettingsBtn = () => {
onChange={(e) => { onChange={(e) => {
const value = parseFloat(e.target.value); const value = parseFloat(e.target.value);
setMicVol(value); setMicVol(value);
// Hier kannst du den Lautstärkewert verwenden setShowIndication(true);
setShowInducation(true);
console.log("Lautstärke:", value);
}} }}
value={micVol} value={micVol}
className="range range-xs range-accent w-full" className="range range-xs range-accent w-full"
@@ -119,27 +123,23 @@ export const SettingsBtn = () => {
{showIndication && ( {showIndication && (
<MicVolumeBar deviceId={selectedDevice ? selectedDevice : ""} volumeInput={micVol} /> <MicVolumeBar deviceId={selectedDevice ? selectedDevice : ""} volumeInput={micVol} />
)} )}
{/* <MicVolumeIndication deviceId={selectedDevice ? selectedDevice : ""} volumeInput={40} /> */}
{/* <MicVolumeIndication deviceId={selectedDevice ? selectedDevice : ""} volumeInput={40
} />
{/* FÜGE HIER BITTE DEN MIKROFONAUSSCHLAG EIN WIE IN DER V1 */}
<div className="divider w-full" /> <div className="divider w-full" />
</div> </div>
<p className="flex items-center gap-2 text-base mb-2"> <p className="flex items-center gap-2 text-base mb-2">
<Volume2 size={20} /> Ausgabelautstärke <Volume2 size={20} /> Melder Lautstärke
</p> </p>
<div className="w-full"> <div className="w-full">
<input <input
type="range" type="range"
min={0} min={0}
max={3} max={1}
step={0.01} step={0.01}
onChange={(e) => { onChange={(e) => {
const value = parseFloat(e.target.value); const value = parseFloat(e.target.value);
setDmeVol(value); setDmeVol(value);
// Hier kannst du den Lautstärkewert verwenden if (!testSoundRef.current) return;
setShowInducation(true); testSoundRef.current.volume = value;
console.log("Lautstärke:", value); testSoundRef.current.play();
}} }}
value={dmeVolume} value={dmeVolume}
className="range range-xs range-accent w-full" className="range range-xs range-accent w-full"
@@ -147,8 +147,6 @@ export const SettingsBtn = () => {
<div className="flex justify-between px-2.5 mt-2 text-xs"> <div className="flex justify-between px-2.5 mt-2 text-xs">
<span>0</span> <span>0</span>
<span>100</span> <span>100</span>
<span>200</span>
<span>300</span>
</div> </div>
</div> </div>
@@ -159,6 +157,7 @@ export const SettingsBtn = () => {
onSubmit={() => false} onSubmit={() => false}
onClick={() => { onClick={() => {
modalRef.current?.close(); modalRef.current?.close();
testSoundRef.current?.pause();
}} }}
> >
Schließen Schließen
@@ -168,13 +167,15 @@ export const SettingsBtn = () => {
type="submit" type="submit"
onSubmit={() => false} onSubmit={() => false}
onClick={async () => { onClick={async () => {
await editUserMutation.mutateAsync({ testSoundRef.current?.pause();
const res = await editUserMutation.mutateAsync({
user: { user: {
settingsMicDevice: selectedDevice, settingsMicDevice: selectedDevice,
settingsMicVolume: micVol, settingsMicVolume: micVol,
settingsDmeVolume: dmeVolume, settingsDmeVolume: dmeVolume,
}, },
}); });
console.log("res", res);
setMic(selectedDevice, micVol); setMic(selectedDevice, micVol);
modalRef.current?.close(); modalRef.current?.close();
toast.success("Einstellungen gespeichert"); toast.success("Einstellungen gespeichert");

View File

@@ -108,8 +108,6 @@ export const MissionForm = () => {
}); });
const { missionFormValues, setOpen } = usePannelStore((state) => state); const { missionFormValues, setOpen } = usePannelStore((state) => state);
console.log("MissionForm rendered", form.formState.errors);
const validationRequired = HPGValidationRequired( const validationRequired = HPGValidationRequired(
form.watch("missionStationIds"), form.watch("missionStationIds"),
aircrafts, aircrafts,
@@ -276,7 +274,7 @@ export const MissionForm = () => {
<> <>
<select <select
{...form.register("missionKeywordCategory")} {...form.register("missionKeywordCategory")}
className="select select-primary select-bordered w-full mb-4" className="select select-primary select-bordered w-full"
onChange={(e) => { onChange={(e) => {
const firstKeyword = keywords?.find( const firstKeyword = keywords?.find(
(k) => k.category === form.watch("missionKeywordCategory"), (k) => k.category === form.watch("missionKeywordCategory"),
@@ -300,9 +298,12 @@ export const MissionForm = () => {
</option> </option>
))} ))}
</select> </select>
{form.formState.errors.missionKeywordCategory && (
<p className="text-error text-sm mb-4">Bitte wähle eine Kategorie aus.</p>
)}
<select <select
{...form.register("missionKeywordAbbreviation")} {...form.register("missionKeywordAbbreviation")}
className="select select-primary select-bordered w-full mb-4" className="select select-primary select-bordered w-full"
onChange={(e) => { onChange={(e) => {
const keyword = keywords?.find((k) => k.abreviation === e.target.value); const keyword = keywords?.find((k) => k.abreviation === e.target.value);
form.setValue("missionKeywordName", keyword?.name || (null as any)); form.setValue("missionKeywordName", keyword?.name || (null as any));
@@ -323,7 +324,9 @@ export const MissionForm = () => {
</option> </option>
))} ))}
</select> </select>
{form.formState.errors.missionKeywordAbbreviation && (
<p className="text-error text-sm mb-4">Bitte wähle ein Stichwort aus.</p>
)}
<div className="mb-4"> <div className="mb-4">
<select <select
{...form.register("hpgMissionString")} {...form.register("hpgMissionString")}

View File

@@ -1,8 +1,6 @@
"use client"; "use client";
import { io, Socket } from "socket.io-client"; import { io, Socket } from "socket.io-client";
console.log("ENV:", process.env.NEXT_PUBLIC_DISPATCH_SERVER_URL);
export const dispatchSocket: Socket = io(process.env.NEXT_PUBLIC_DISPATCH_SERVER_URL, { export const dispatchSocket: Socket = io(process.env.NEXT_PUBLIC_DISPATCH_SERVER_URL, {
autoConnect: false, autoConnect: false,
transports: ["websocket"], transports: ["websocket"],

View File

@@ -1,9 +1,18 @@
"use client"; "use client";
import { useQuery } from "@tanstack/react-query";
import { getUserAPI } from "_querys/user";
import { usePilotConnectionStore } from "_store/pilot/connectionStore"; import { usePilotConnectionStore } from "_store/pilot/connectionStore";
import { useDmeStore } from "_store/pilot/dmeStore"; import { useDmeStore } from "_store/pilot/dmeStore";
import { useSession } from "next-auth/react";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
export const useSounds = () => { export const useSounds = () => {
const session = useSession();
const { data: user } = useQuery({
queryKey: ["user", session.data?.user.id],
queryFn: () => getUserAPI(session.data!.user.id),
});
const { page, setPage } = useDmeStore((state) => state); const { page, setPage } = useDmeStore((state) => state);
const mission = usePilotConnectionStore((state) => state.activeMission); const mission = usePilotConnectionStore((state) => state.activeMission);
@@ -24,22 +33,15 @@ export const useSounds = () => {
newMissionSound.current.volume = 0.3; newMissionSound.current.volume = 0.3;
newMissionSound.current.play(); newMissionSound.current.play();
if (mission) { if (mission) {
timeouts.push( timeouts.push(setTimeout(() => setPage({ page: "mission", mission }), 500));
setTimeout(() => setPage({ page: "mission", mission }), 500),
);
} }
} else if (page === "acknowledge") { } else if (page === "acknowledge") {
newMissionSound.current?.pause(); newMissionSound.current?.pause();
if (mission) { if (mission) {
timeouts.push( timeouts.push(setTimeout(() => setPage({ page: "mission", mission }), 500));
setTimeout(() => setPage({ page: "mission", mission }), 500),
);
} else { } else {
timeouts.push( timeouts.push(
setTimeout( setTimeout(() => setPage({ page: "error", error: "Einsatz nicht gebunden" }), 500),
() => setPage({ page: "error", error: "Einsatz nicht gebunden" }),
500,
),
); );
} }
} }

View File

@@ -16,9 +16,9 @@
}, },
"engines": { "engines": {
"node": ">=18", "node": ">=18",
"pnpm": ">=10" "pnpm": ">=10"
}, },
"packageManager": "pnpm@10.11.0", "packageManager": "pnpm@10.11.1",
"workspaces": [ "workspaces": [
"apps/*", "apps/*",
"packages/*" "packages/*"

View File

@@ -33,8 +33,8 @@ model User {
// Settings: // Settings:
settingsNtfyRoom String? @map(name: "settings_ntfy_room") settingsNtfyRoom String? @map(name: "settings_ntfy_room")
settingsMicDevice String? @map(name: "settings_mic_device") settingsMicDevice String? @map(name: "settings_mic_device")
settingsMicVolume Int? @map(name: "settings_mic_volume") settingsMicVolume Float? @map(name: "settings_mic_volume")
settingsDmeVolume Int? @map(name: "settings_dme_volume") settingsDmeVolume Float? @map(name: "settings_dme_volume")
settingsHideLastname Boolean @default(false) @map(name: "settings_hide_lastname") settingsHideLastname Boolean @default(false) @map(name: "settings_hide_lastname")
// email Verification: // email Verification:

View File

@@ -10,7 +10,36 @@
"LIVEKIT_API_KEY", "LIVEKIT_API_KEY",
"LIVEKIT_API_SECRET", "LIVEKIT_API_SECRET",
"AUTH_HUB_SECRET", "AUTH_HUB_SECRET",
"AUTH_DISPATCH_COOKIE_PREFIX" "AUTH_DISPATCH_COOKIE_PREFIX",
"AUTH_HUB_COOKIE_PREFIX",
"AUTH_DISPATCH_URL",
"AUTH_HUB_URL",
"NEXT_PUBLIC_DISPATCH_SERVICE_ID",
"NEXT_PUBLIC_HUB_URL",
"NEXT_PUBLIC_HUB_SERVER_URL",
"NEXT_PUBLIC_DISPATCH_URL",
"NEXT_PUBLIC_DISPATCH_SERVER_URL",
"NEXT_PUBLIC_ESRI_ACCESS_TOKEN",
"NEXT_PUBLIC_OPENAIP_ACCESS",
"NEXT_PUBLIC_LIVEKIT_URL",
"DISPATCH_SERVER_PORT",
"DISPATCH_APP_TOKEN",
"REDIS_HOST",
"REDIS_PORT",
"HUB_SERVER_PORT",
"MOODLE_URL",
"MOODLE_API_TOKEN",
"MOODLE_USER_PASSWORD",
"NEXT_PUBLIC_MOODLE_URL",
"MAIL_SERVER",
"MAIL_PORT",
"MAIL_USER",
"MAIL_PASSWORD",
"DISCORD_OAUTH_CLIENT_ID",
"DISCORD_OAUTH_SECRET",
"DISCORD_BOT_TOKEN",
"DISCORD_REDIRECT_URL",
"NEXT_PUBLIC_DISCORD_URL"
], ],
"ui": "tui", "ui": "tui",
"tasks": { "tasks": {