Dispo-Option, die HPG validierung nicht zu nutzen
This commit is contained in:
0
apps/dispatch-server/routes/settings.ts
Normal file
0
apps/dispatch-server/routes/settings.ts
Normal file
@@ -3,16 +3,17 @@ import { useEffect, useRef, useState } from "react";
|
|||||||
import { GearIcon } from "@radix-ui/react-icons";
|
import { GearIcon } from "@radix-ui/react-icons";
|
||||||
import { SettingsIcon, Volume2 } from "lucide-react";
|
import { SettingsIcon, Volume2 } from "lucide-react";
|
||||||
import MicVolumeBar from "_components/MicVolumeIndication";
|
import MicVolumeBar from "_components/MicVolumeIndication";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { editUserAPI, getUserAPI } from "_querys/user";
|
import { editUserAPI, getUserAPI } from "_querys/user";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useAudioStore } from "_store/audioStore";
|
import { useAudioStore } from "_store/audioStore";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { set } from "date-fns";
|
import { Button } from "@repo/shared-components";
|
||||||
|
|
||||||
export const SettingsBtn = () => {
|
export const SettingsBtn = () => {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]);
|
const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]);
|
||||||
const { data: user } = useQuery({
|
const { data: user } = useQuery({
|
||||||
@@ -23,6 +24,10 @@ export const SettingsBtn = () => {
|
|||||||
|
|
||||||
const editUserMutation = useMutation({
|
const editUserMutation = useMutation({
|
||||||
mutationFn: editUserAPI,
|
mutationFn: editUserAPI,
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ["user", session.data?.user.id] });
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,6 +45,7 @@ export const SettingsBtn = () => {
|
|||||||
micVolume: user?.settingsMicVolume || 1,
|
micVolume: user?.settingsMicVolume || 1,
|
||||||
radioVolume: user?.settingsRadioVolume || 0.8,
|
radioVolume: user?.settingsRadioVolume || 0.8,
|
||||||
autoCloseMapPopup: user?.settingsAutoCloseMapPopup || false,
|
autoCloseMapPopup: user?.settingsAutoCloseMapPopup || false,
|
||||||
|
useHPGAsDispatcher: user?.settingsUseHPGAsDispatcher || false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setSettings: setAudioSettings } = useAudioStore((state) => state);
|
const { setSettings: setAudioSettings } = useAudioStore((state) => state);
|
||||||
@@ -57,7 +63,8 @@ export const SettingsBtn = () => {
|
|||||||
micDeviceId: user.settingsMicDevice,
|
micDeviceId: user.settingsMicDevice,
|
||||||
micVolume: user.settingsMicVolume || 1,
|
micVolume: user.settingsMicVolume || 1,
|
||||||
radioVolume: user.settingsRadioVolume || 0.8,
|
radioVolume: user.settingsRadioVolume || 0.8,
|
||||||
autoCloseMapPopup: user.settingsAutoCloseMapPopup || false,
|
autoCloseMapPopup: user.settingsAutoCloseMapPopup,
|
||||||
|
useHPGAsDispatcher: user.settingsUseHPGAsDispatcher,
|
||||||
});
|
});
|
||||||
setUserSettings({
|
setUserSettings({
|
||||||
settingsAutoCloseMapPopup: user.settingsAutoCloseMapPopup || false,
|
settingsAutoCloseMapPopup: user.settingsAutoCloseMapPopup || false,
|
||||||
@@ -198,6 +205,17 @@ export const SettingsBtn = () => {
|
|||||||
/>
|
/>
|
||||||
Popups automatisch schließen
|
Popups automatisch schließen
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 flex w-full items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="toggle"
|
||||||
|
checked={settings.useHPGAsDispatcher}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSettingsPartial({ useHPGAsDispatcher: e.target.checked });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
HPG als Disponent verwenden
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="modal-action flex justify-between">
|
<div className="modal-action flex justify-between">
|
||||||
<button
|
<button
|
||||||
@@ -211,7 +229,7 @@ export const SettingsBtn = () => {
|
|||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<Button
|
||||||
className="btn btn-soft btn-success"
|
className="btn btn-soft btn-success"
|
||||||
type="submit"
|
type="submit"
|
||||||
onSubmit={() => false}
|
onSubmit={() => false}
|
||||||
@@ -224,6 +242,7 @@ export const SettingsBtn = () => {
|
|||||||
settingsMicVolume: settings.micVolume,
|
settingsMicVolume: settings.micVolume,
|
||||||
settingsRadioVolume: settings.radioVolume,
|
settingsRadioVolume: settings.radioVolume,
|
||||||
settingsAutoCloseMapPopup: settings.autoCloseMapPopup,
|
settingsAutoCloseMapPopup: settings.autoCloseMapPopup,
|
||||||
|
settingsUseHPGAsDispatcher: settings.useHPGAsDispatcher,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setAudioSettings({
|
setAudioSettings({
|
||||||
@@ -239,7 +258,7 @@ export const SettingsBtn = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ import { selectRandomHPGMissionSzenery } from "_helpers/selectRandomHPGMission";
|
|||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import { cn } from "@repo/shared-components";
|
import { cn } from "@repo/shared-components";
|
||||||
import { StationsSelect } from "(app)/dispatch/_components/StationSelect";
|
import { StationsSelect } from "(app)/dispatch/_components/StationSelect";
|
||||||
|
import { getUserAPI } from "_querys/user";
|
||||||
|
|
||||||
export const MissionForm = () => {
|
export const MissionForm = () => {
|
||||||
|
const session = useSession();
|
||||||
|
|
||||||
const { editingMissionId, setEditingMission } = usePannelStore();
|
const { editingMissionId, setEditingMission } = usePannelStore();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { setSearchElements, searchElements, setContextMenu } = useMapStore((s) => s);
|
const { setSearchElements, searchElements, setContextMenu } = useMapStore((s) => s);
|
||||||
@@ -44,6 +47,10 @@ export const MissionForm = () => {
|
|||||||
queryFn: () => getConnectedAircraftsAPI(),
|
queryFn: () => getConnectedAircraftsAPI(),
|
||||||
refetchInterval: 10000,
|
refetchInterval: 10000,
|
||||||
});
|
});
|
||||||
|
const { data: user } = useQuery({
|
||||||
|
queryKey: ["user", session.data?.user.id],
|
||||||
|
queryFn: () => getUserAPI(session.data!.user.id),
|
||||||
|
});
|
||||||
|
|
||||||
const createMissionMutation = useMutation({
|
const createMissionMutation = useMutation({
|
||||||
mutationFn: createMissionAPI,
|
mutationFn: createMissionAPI,
|
||||||
@@ -81,7 +88,6 @@ export const MissionForm = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const session = useSession();
|
|
||||||
const defaultFormValues = React.useMemo(
|
const defaultFormValues = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
({
|
({
|
||||||
@@ -124,7 +130,9 @@ export const MissionForm = () => {
|
|||||||
form.watch("missionStationIds"),
|
form.watch("missionStationIds"),
|
||||||
aircrafts,
|
aircrafts,
|
||||||
form.watch("hpgMissionString"),
|
form.watch("hpgMissionString"),
|
||||||
) && !form.watch("hpgMissionString")?.startsWith("kein Szenario");
|
) &&
|
||||||
|
!form.watch("hpgMissionString")?.startsWith("kein Szenario") &&
|
||||||
|
user?.settingsUseHPGAsDispatcher;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session.data?.user.id) {
|
if (session.data?.user.id) {
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ import { useEffect, useRef, useState } from "react";
|
|||||||
import { GearIcon } from "@radix-ui/react-icons";
|
import { GearIcon } from "@radix-ui/react-icons";
|
||||||
import { Bell, SettingsIcon, Volume2 } from "lucide-react";
|
import { Bell, SettingsIcon, Volume2 } from "lucide-react";
|
||||||
import MicVolumeBar from "_components/MicVolumeIndication";
|
import MicVolumeBar from "_components/MicVolumeIndication";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { editUserAPI, getUserAPI } from "_querys/user";
|
import { editUserAPI, getUserAPI } from "_querys/user";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useAudioStore } from "_store/audioStore";
|
import { useAudioStore } from "_store/audioStore";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { Button } from "@repo/shared-components";
|
||||||
|
|
||||||
export const SettingsBtn = () => {
|
export const SettingsBtn = () => {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]);
|
const [inputDevices, setInputDevices] = useState<MediaDeviceInfo[]>([]);
|
||||||
const { data: user } = useQuery({
|
const { data: user } = useQuery({
|
||||||
@@ -22,6 +24,10 @@ export const SettingsBtn = () => {
|
|||||||
|
|
||||||
const editUserMutation = useMutation({
|
const editUserMutation = useMutation({
|
||||||
mutationFn: editUserAPI,
|
mutationFn: editUserAPI,
|
||||||
|
mutationKey: ["user", session.data?.user.id],
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ["user", session.data?.user.id] });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -248,7 +254,7 @@ export const SettingsBtn = () => {
|
|||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<Button
|
||||||
className="btn btn-soft btn-success"
|
className="btn btn-soft btn-success"
|
||||||
type="submit"
|
type="submit"
|
||||||
onSubmit={() => false}
|
onSubmit={() => false}
|
||||||
@@ -275,7 +281,7 @@ export const SettingsBtn = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const Map = dynamic(() => import("_components/map/Map"), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const PilotPage = () => {
|
const PilotPage = () => {
|
||||||
const { connectedAircraft, status } = usePilotConnectionStore((state) => state);
|
const { connectedAircraft, status, } = usePilotConnectionStore((state) => state);
|
||||||
const { latestMission } = useDmeStore((state) => state);
|
const { latestMission } = useDmeStore((state) => state);
|
||||||
// Query will be cached anyway, due to this, displayed Markers are in sync with own Aircraft connection-warning
|
// Query will be cached anyway, due to this, displayed Markers are in sync with own Aircraft connection-warning
|
||||||
const { data: aircrafts } = useQuery({
|
const { data: aircrafts } = useQuery({
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default () => {
|
|||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h1 className="text-5xl">logging out...</h1>
|
<h1 className="text-5xl">ausloggen...</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { ReactNode, useEffect, useState } from "react";
|
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { dispatchSocket } from "(app)/dispatch/socket";
|
import { dispatchSocket } from "(app)/dispatch/socket";
|
||||||
import { NotificationPayload } from "@repo/db";
|
import { NotificationPayload } from "@repo/db";
|
||||||
import { HPGnotificationToast } from "_components/customToasts/HPGnotification";
|
import { HPGnotificationToast } from "_components/customToasts/HPGnotification";
|
||||||
@@ -15,6 +15,7 @@ import { MissionAutoCloseToast } from "_components/customToasts/MissionAutoClose
|
|||||||
|
|
||||||
export function QueryProvider({ children }: { children: ReactNode }) {
|
export function QueryProvider({ children }: { children: ReactNode }) {
|
||||||
const mapStore = useMapStore((s) => s);
|
const mapStore = useMapStore((s) => s);
|
||||||
|
const notificationSound = useRef<HTMLAudioElement | null>(null);
|
||||||
|
|
||||||
const [queryClient] = useState(
|
const [queryClient] = useState(
|
||||||
() =>
|
() =>
|
||||||
@@ -30,6 +31,9 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
notificationSound.current = new Audio("/sounds/notification.mp3");
|
||||||
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const invalidateMission = () => {
|
const invalidateMission = () => {
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
@@ -59,8 +63,18 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleNotification = (notification: NotificationPayload) => {
|
const handleNotification = (notification: NotificationPayload) => {
|
||||||
|
const playNotificationSound = () => {
|
||||||
|
if (notificationSound.current) {
|
||||||
|
notificationSound.current.currentTime = 0;
|
||||||
|
notificationSound.current
|
||||||
|
.play()
|
||||||
|
.catch((e) => console.error("Notification sound error:", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (notification.type) {
|
switch (notification.type) {
|
||||||
case "hpg-validation":
|
case "hpg-validation":
|
||||||
|
playNotificationSound();
|
||||||
toast.custom(
|
toast.custom(
|
||||||
(t) => <HPGnotificationToast event={notification} mapStore={mapStore} t={t} />,
|
(t) => <HPGnotificationToast event={notification} mapStore={mapStore} t={t} />,
|
||||||
{
|
{
|
||||||
@@ -70,6 +84,7 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case "admin-message":
|
case "admin-message":
|
||||||
|
playNotificationSound();
|
||||||
toast.custom((t) => <AdminMessageToast event={notification} t={t} />, {
|
toast.custom((t) => <AdminMessageToast event={notification} t={t} />, {
|
||||||
duration: 999999,
|
duration: 999999,
|
||||||
});
|
});
|
||||||
@@ -81,6 +96,7 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "mission-auto-close":
|
case "mission-auto-close":
|
||||||
|
playNotificationSound();
|
||||||
toast.custom(
|
toast.custom(
|
||||||
(t) => <MissionAutoCloseToast event={notification} t={t} mapStore={mapStore} />,
|
(t) => <MissionAutoCloseToast event={notification} t={t} mapStore={mapStore} />,
|
||||||
{
|
{
|
||||||
@@ -90,6 +106,7 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|||||||
break;
|
break;
|
||||||
case "mission-closed":
|
case "mission-closed":
|
||||||
toast("Dein aktueller Einsatz wurde geschlossen.");
|
toast("Dein aktueller Einsatz wurde geschlossen.");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
toast("unbekanntes Notification-Event");
|
toast("unbekanntes Notification-Event");
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { BaseNotification } from "_components/customToasts/BaseNotification"
|
||||||
|
import { TriangleAlert } from "lucide-react"
|
||||||
|
import toast, { Toast } from "react-hot-toast"
|
||||||
|
|
||||||
|
|
||||||
|
export const HPGnotValidatedToast = ({_toast}: {_toast: Toast}) => {
|
||||||
|
return <BaseNotification icon={<TriangleAlert />} className="flex flex-row">
|
||||||
|
<div className="flex-1">
|
||||||
|
<h1 className="font-bold text-red-600">Einsatz nicht HPG-validiert</h1>
|
||||||
|
<p className="text-sm">Vergleiche die Position des Einsatzes mit der HPG-Position in Hubschrauber</p>
|
||||||
|
</div>
|
||||||
|
<div className="ml-11">
|
||||||
|
<button className="btn" onClick={() => toast.dismiss(_toast.id)}>
|
||||||
|
schließen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</BaseNotification>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showToast = () => {
|
||||||
|
toast.custom((t) => {
|
||||||
|
return (<HPGnotValidatedToast _toast={t} />);
|
||||||
|
}, {duration: 1000 * 60 * 10}); // 10 minutes
|
||||||
|
}
|
||||||
@@ -14,11 +14,14 @@ export const changeDispatcherAPI = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getConnectedDispatcherAPI = async (filter?: Prisma.ConnectedDispatcherWhereInput) => {
|
export const getConnectedDispatcherAPI = async (filter?: Prisma.ConnectedDispatcherWhereInput) => {
|
||||||
const res = await axios.get<ConnectedDispatcher[]>("/api/dispatcher", {
|
const res = await axios.get<(ConnectedDispatcher & { settingsUseHPGAsDispatcher: boolean })[]>(
|
||||||
params: {
|
"/api/dispatcher",
|
||||||
filter: JSON.stringify(filter),
|
{
|
||||||
|
params: {
|
||||||
|
filter: JSON.stringify(filter),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error("Failed to fetch Connected Dispatcher");
|
throw new Error("Failed to fetch Connected Dispatcher");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { dispatchSocket } from "../../(app)/dispatch/socket";
|
import { dispatchSocket } from "../../(app)/dispatch/socket";
|
||||||
import { ConnectedAircraft, Mission, MissionSdsLog, Station, User } from "@repo/db";
|
import { ConnectedAircraft, Mission, MissionSdsLog, Station, User } from "@repo/db";
|
||||||
|
import { showToast } from "../../_components/customToasts/HPGnotValidated";
|
||||||
import { pilotSocket } from "(app)/pilot/socket";
|
import { pilotSocket } from "(app)/pilot/socket";
|
||||||
import { useDmeStore } from "_store/pilot/dmeStore";
|
import { useDmeStore } from "_store/pilot/dmeStore";
|
||||||
import { useMrtStore } from "_store/pilot/MrtStore";
|
import { useMrtStore } from "_store/pilot/MrtStore";
|
||||||
@@ -132,6 +133,12 @@ pilotSocket.on("mission-alert", (data: Mission & { Stations: Station[] }) => {
|
|||||||
useDmeStore.getState().setPage({
|
useDmeStore.getState().setPage({
|
||||||
page: "new-mission",
|
page: "new-mission",
|
||||||
});
|
});
|
||||||
|
if (
|
||||||
|
data.hpgValidationState === "NOT_VALIDATED" &&
|
||||||
|
usePilotConnectionStore.getState().connectedAircraft?.posH145active
|
||||||
|
) {
|
||||||
|
showToast();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pilotSocket.on("sds-message", (sdsMessage: MissionSdsLog) => {
|
pilotSocket.on("sds-message", (sdsMessage: MissionSdsLog) => {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export async function GET(request: Request): Promise<NextResponse> {
|
|||||||
...d,
|
...d,
|
||||||
user: undefined,
|
user: undefined,
|
||||||
publicUser: getPublicUser(d.user),
|
publicUser: getPublicUser(d.user),
|
||||||
|
settingsUseHPGAsDispatcher: d.user.settingsUseHPGAsDispatcher,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -78,6 +78,15 @@ export const ConnectedDispatcher = () => {
|
|||||||
<div>{asPublicUser(d.publicUser).fullName}</div>
|
<div>{asPublicUser(d.publicUser).fullName}</div>
|
||||||
<div className="text-xs font-semibold uppercase opacity-60">{d.zone}</div>
|
<div className="text-xs font-semibold uppercase opacity-60">{d.zone}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mr-2 flex flex-col justify-center">
|
||||||
|
{d.settingsUseHPGAsDispatcher ? (
|
||||||
|
<span className="badge badge-sm badge-success badge-outline">HPG aktiv</span>
|
||||||
|
) : (
|
||||||
|
<span className="badge badge-sm badge-info badge-outline">
|
||||||
|
HPG deaktiviert
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{(() => {
|
{(() => {
|
||||||
const badges = (d.publicUser as unknown as PublicUser).badges
|
const badges = (d.publicUser as unknown as PublicUser).badges
|
||||||
|
|||||||
BIN
apps/dispatch/public/sounds/notification.mp3
Normal file
BIN
apps/dispatch/public/sounds/notification.mp3
Normal file
Binary file not shown.
@@ -1,16 +1,16 @@
|
|||||||
'use client';
|
"use client";
|
||||||
import { signOut } from 'next-auth/react';
|
import { signOut } from "next-auth/react";
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
signOut({
|
signOut({
|
||||||
callbackUrl: '/login',
|
callbackUrl: "/login",
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h1 className="text-5xl">logging out...</h1>
|
<h1 className="text-5xl">ausloggen...</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "settings_use_hpg_as_dispatcher" BOOLEAN NOT NULL DEFAULT false;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ALTER COLUMN "settings_use_hpg_as_dispatcher" SET DEFAULT true;
|
||||||
@@ -38,15 +38,16 @@ model User {
|
|||||||
changelogAck Boolean @default(false)
|
changelogAck Boolean @default(false)
|
||||||
|
|
||||||
// Settings:
|
// Settings:
|
||||||
pathSelected Boolean @default(false)
|
pathSelected Boolean @default(false)
|
||||||
migratedFromV1 Boolean @default(false)
|
migratedFromV1 Boolean @default(false)
|
||||||
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 Float? @map(name: "settings_mic_volume")
|
settingsMicVolume Float? @map(name: "settings_mic_volume")
|
||||||
settingsDmeVolume Float? @map(name: "settings_dme_volume")
|
settingsDmeVolume Float? @map(name: "settings_dme_volume")
|
||||||
settingsRadioVolume Float? @map(name: "settings_funk_volume")
|
settingsRadioVolume Float? @map(name: "settings_funk_volume")
|
||||||
settingsHideLastname Boolean @default(false) @map(name: "settings_hide_lastname")
|
settingsHideLastname Boolean @default(false) @map(name: "settings_hide_lastname")
|
||||||
settingsAutoCloseMapPopup Boolean @default(false) @map(name: "settings_auto_close_map_popup")
|
settingsAutoCloseMapPopup Boolean @default(false) @map(name: "settings_auto_close_map_popup")
|
||||||
|
settingsUseHPGAsDispatcher Boolean @default(true) @map(name: "settings_use_hpg_as_dispatcher")
|
||||||
|
|
||||||
// email Verification:
|
// email Verification:
|
||||||
emailVerificationToken String? @map(name: "email_verification_token")
|
emailVerificationToken String? @map(name: "email_verification_token")
|
||||||
|
|||||||
Reference in New Issue
Block a user