added mission fields
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Prisma } from "@repo/db";
|
import { Mission, Prisma } from "@repo/db";
|
||||||
import { MissionOptionalDefaults } from "@repo/db/zod";
|
import { MissionOptionalDefaults } from "@repo/db/zod";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
@@ -6,29 +6,29 @@ interface MissionStore {
|
|||||||
missions: MissionOptionalDefaults[];
|
missions: MissionOptionalDefaults[];
|
||||||
setMissions: (missions: MissionOptionalDefaults[]) => void;
|
setMissions: (missions: MissionOptionalDefaults[]) => void;
|
||||||
getMissions: () => Promise<undefined>;
|
getMissions: () => Promise<undefined>;
|
||||||
|
createMission: (mission: MissionOptionalDefaults) => Promise<Mission>;
|
||||||
setMission: (mission: MissionOptionalDefaults) => void;
|
setMission: (mission: MissionOptionalDefaults) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMissionsStore = create<MissionStore>((set) => ({
|
export const useMissionsStore = create<MissionStore>((set) => ({
|
||||||
missions: [
|
missions: [],
|
||||||
{
|
|
||||||
state: "draft",
|
|
||||||
id: "01250325",
|
|
||||||
addressLat: 52.520008,
|
|
||||||
addressLng: 13.404954,
|
|
||||||
addressStreet: "Alexanderplatz",
|
|
||||||
addressCity: "Berlin",
|
|
||||||
addressZip: "10178",
|
|
||||||
missionAdditionalInfo: "Additional info",
|
|
||||||
missionCategory: "AB_Atmung",
|
|
||||||
missionKeyword: "Zunehmende Beschwerden",
|
|
||||||
missionSummary: "AB1_0",
|
|
||||||
missionPatientInfo: "M/10",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
setMissions: (missions) => set({ missions }),
|
setMissions: (missions) => set({ missions }),
|
||||||
|
createMission: async (mission) => {
|
||||||
|
const res = await fetch("/api/mission", {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(mission),
|
||||||
|
});
|
||||||
|
if (!res.ok) return undefined;
|
||||||
|
const data = await res.json();
|
||||||
|
set((state) => ({ missions: [...state.missions, data] }));
|
||||||
|
return data;
|
||||||
|
},
|
||||||
getMissions: async () => {
|
getMissions: async () => {
|
||||||
const res = await fetch("/api/mission", {
|
const res = await fetch("/api/mission", {
|
||||||
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
@@ -62,3 +62,10 @@ export const useMissionsStore = create<MissionStore>((set) => ({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
useMissionsStore
|
||||||
|
.getState()
|
||||||
|
.getMissions()
|
||||||
|
.then(() => {
|
||||||
|
console.log("Missions loaded");
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
import { Prisma, prisma } from "@repo/db";
|
import { Prisma, prisma } from "@repo/db";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
export const GET = (req: NextRequest) => {
|
export const POST = async (req: NextRequest) => {
|
||||||
const filter = req.nextUrl.searchParams.get("filter") as
|
console.log(req.body);
|
||||||
| Prisma.MissionWhereInput
|
const body = await req.json();
|
||||||
| undefined;
|
console.log(body);
|
||||||
|
|
||||||
const missions = prisma.mission.findMany({
|
const missions = await prisma.mission.findMany({
|
||||||
where: filter,
|
where: (body.filter as Prisma.MissionWhereInput) || {},
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json(missions);
|
return NextResponse.json(missions);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PUT = async (req: NextRequest) => {
|
||||||
|
const body = await req.json();
|
||||||
|
|
||||||
|
const newMission = await prisma.mission.create({
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(newMission);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { MissionSchema } from "@repo/db/zod";
|
|
||||||
import { BellRing, BookmarkPlus, Trash2 } from "lucide-react";
|
import { BellRing, BookmarkPlus, Trash2 } from "lucide-react";
|
||||||
import { Select } from "_components/Select";
|
import { Select } from "_components/Select";
|
||||||
|
import { Keyword, Station } from "@repo/db";
|
||||||
|
import { getKeywords, getStations } from "dispatch/_components/pannel/action";
|
||||||
|
import { MissionCreateInputSchema } from "@repo/db/zod";
|
||||||
|
|
||||||
const clearBtn = () => {
|
const clearBtn = () => {
|
||||||
return (
|
return (
|
||||||
@@ -15,59 +17,35 @@ const clearBtn = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const missionFormSchema = MissionSchema.pick({
|
export const MissionForm = () => {
|
||||||
addressLat: true,
|
type MissionFormValues = z.infer<typeof MissionCreateInputSchema>;
|
||||||
addressLng: true,
|
|
||||||
addressStreet: true,
|
|
||||||
addressCity: true,
|
|
||||||
addressZip: true,
|
|
||||||
missionCategory: true,
|
|
||||||
missionKeyword: true,
|
|
||||||
missionAdditionalInfo: true,
|
|
||||||
missionPatientInfo: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
type MissionFormValues = z.infer<typeof missionFormSchema>;
|
|
||||||
|
|
||||||
const dummyRettungsmittel = [
|
|
||||||
"RTW",
|
|
||||||
"Feuerwehr",
|
|
||||||
"Polizei",
|
|
||||||
"Christoph 31",
|
|
||||||
"Christoph 100",
|
|
||||||
"Christoph Berlin",
|
|
||||||
"Christophorus 1",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const MissionForm: React.FC = () => {
|
|
||||||
const [missionCategory, setMissionCategory] = useState<"PRIMÄR" | "SEKUNDÄR">(
|
|
||||||
"PRIMÄR",
|
|
||||||
);
|
|
||||||
const [missionKeyword, setMissionKeyword] = useState<
|
|
||||||
"AB_ATMUNG" | "C_BLUTUNG"
|
|
||||||
>("AB_ATMUNG");
|
|
||||||
const [missionType, setMissionType] = useState<"typ1" | "typ2" | "typ3">(
|
|
||||||
"typ1",
|
|
||||||
);
|
|
||||||
const [selectedRettungsmittel, setSelectedRettungsmittel] = useState<
|
|
||||||
{ label: string; value: string }[]
|
|
||||||
>([]);
|
|
||||||
const form = useForm<MissionFormValues>({
|
const form = useForm<MissionFormValues>({
|
||||||
resolver: zodResolver(missionFormSchema),
|
resolver: zodResolver(MissionCreateInputSchema),
|
||||||
defaultValues: {
|
defaultValues: {},
|
||||||
addressLat: 0,
|
|
||||||
addressLng: 0,
|
|
||||||
missionCategory: "PRIMÄR",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [stations, setStations] = useState<Station[]>([]);
|
||||||
|
const [keywords, setKeywords] = useState<Keyword[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("useEffect");
|
||||||
|
getKeywords().then((data) => {
|
||||||
|
setKeywords(data);
|
||||||
|
});
|
||||||
|
getStations().then((data) => {
|
||||||
|
setStations(data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const onSubmit = (data: MissionFormValues) => {
|
const onSubmit = (data: MissionFormValues) => {
|
||||||
console.log({
|
console.log({
|
||||||
...data,
|
...data,
|
||||||
rettungsmittel: selectedRettungsmittel.map((item) => item.value),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(form.formState.errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
{/* Koorinaten Section */}
|
{/* Koorinaten Section */}
|
||||||
@@ -78,13 +56,13 @@ export const MissionForm: React.FC = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
{...form.register("addressLat")}
|
{...form.register("addressLat")}
|
||||||
className="input input-sm input-neutral input-bordered w-full"
|
className="input input-sm input-neutral input-bordered w-full"
|
||||||
readOnly
|
disabled
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
{...form.register("addressLng")}
|
{...form.register("addressLng")}
|
||||||
className="input input-sm input-neutral input-bordered w-full"
|
className="input input-sm input-neutral input-bordered w-full"
|
||||||
readOnly
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,9 +106,9 @@ export const MissionForm: React.FC = () => {
|
|||||||
label={""}
|
label={""}
|
||||||
isMulti
|
isMulti
|
||||||
form={form}
|
form={form}
|
||||||
options={dummyRettungsmittel.map((key, val) => ({
|
options={stations.map((s) => ({
|
||||||
label: key,
|
label: s.bosCallsign,
|
||||||
value: val,
|
value: s.id,
|
||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -139,30 +117,32 @@ export const MissionForm: React.FC = () => {
|
|||||||
<div className="form-control">
|
<div className="form-control">
|
||||||
<h2 className="text-lg font-bold mb-2">Einsatzdaten</h2>
|
<h2 className="text-lg font-bold mb-2">Einsatzdaten</h2>
|
||||||
<select
|
<select
|
||||||
{...form.register("missionCategory")}
|
{...form.register("type")}
|
||||||
className="select select-primary select-bordered w-full mb-4"
|
className="select select-primary select-bordered w-full mb-4"
|
||||||
onChange={(e) =>
|
|
||||||
setMissionCategory(e.target.value as "PRIMÄR" | "SEKUNDÄR")
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<option value="PRIMÄR">PRIMÄR</option>
|
<option value="primär">PRIMÄR</option>
|
||||||
<option value="SEKUNDÄR">SEKUNDÄR</option>
|
<option value="sekundär">SEKUNDÄR</option>
|
||||||
</select>
|
</select>
|
||||||
|
{form.watch("type") === "primär" && (
|
||||||
|
<>
|
||||||
<select
|
<select
|
||||||
{...form.register("missionKeyword")}
|
{...form.register("missionKeyword")}
|
||||||
className="select select-primary select-bordered w-full mb-4"
|
className="select select-primary select-bordered w-full mb-4"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setMissionKeyword(e.target.value as "AB_ATMUNG" | "C_BLUTUNG")
|
form.setValue("missionKeyword", e.target.value as string)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option value="AB_ATMUNG">AB_ATMUNG</option>
|
{keywords.map((keyword) => (
|
||||||
<option value="C_BLUTUNG">C_BLUTUNG</option>
|
<option key={keyword.id} value={keyword.name}>
|
||||||
|
{keyword.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
<select
|
<select
|
||||||
/* {...form.register("missionKeyword")} */
|
/* {...form.register("missionKeyword")} */
|
||||||
className="select select-primary select-bordered w-full mb-4"
|
className="select select-primary select-bordered w-full mb-4"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setMissionType(e.target.value as "typ1" | "typ2" | "typ3")
|
form.setValue("missionKeyword", e.target.value as string)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option defaultChecked disabled value="">
|
<option defaultChecked disabled value="">
|
||||||
@@ -172,12 +152,14 @@ export const MissionForm: React.FC = () => {
|
|||||||
<option value="typ2">typ2</option>
|
<option value="typ2">typ2</option>
|
||||||
<option value="typ3">typ3</option>
|
<option value="typ3">typ3</option>
|
||||||
</select>
|
</select>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<textarea
|
<textarea
|
||||||
{...form.register("missionAdditionalInfo")}
|
{...form.register("missionAdditionalInfo")}
|
||||||
placeholder="Einsatzinformationen"
|
placeholder="Einsatzinformationen"
|
||||||
className="textarea textarea-primary textarea-bordered w-full mb-4"
|
className="textarea textarea-primary textarea-bordered w-full mb-4"
|
||||||
/>
|
/>
|
||||||
{missionCategory === "SEKUNDÄR" && (
|
{form.watch("type") === "sekundär" && (
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Zielkrankenhaus"
|
placeholder="Zielkrankenhaus"
|
||||||
|
|||||||
15
apps/dispatch/app/dispatch/_components/pannel/action.ts
Normal file
15
apps/dispatch/app/dispatch/_components/pannel/action.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { prisma } from "@repo/db";
|
||||||
|
|
||||||
|
export const getKeywords = async () => {
|
||||||
|
const keywords = prisma.keyword.findMany();
|
||||||
|
|
||||||
|
return keywords;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStations = async () => {
|
||||||
|
const stations = await prisma.station.findMany();
|
||||||
|
console.log(stations);
|
||||||
|
return stations;
|
||||||
|
};
|
||||||
Binary file not shown.
24
packages/database/prisma/json/MissionVehicleLog.ts
Normal file
24
packages/database/prisma/json/MissionVehicleLog.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Station, User } from "../../generated/client";
|
||||||
|
|
||||||
|
export interface MissionStationLog {
|
||||||
|
type: "station-log";
|
||||||
|
auto: true;
|
||||||
|
data: {
|
||||||
|
stationId: string;
|
||||||
|
oldFMSstatus: string;
|
||||||
|
newFMSstatus: string;
|
||||||
|
station: Station;
|
||||||
|
user: User;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MissionMessageLog {
|
||||||
|
type: "message-log";
|
||||||
|
auto: false;
|
||||||
|
data: {
|
||||||
|
message: string;
|
||||||
|
user: User;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MissionLog = MissionStationLog | MissionMessageLog;
|
||||||
8
packages/database/prisma/json/OSMway.ts
Normal file
8
packages/database/prisma/json/OSMway.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface MissionVehicleLog {
|
||||||
|
wayID: string;
|
||||||
|
tags: string[];
|
||||||
|
nodes: {
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -17,6 +17,6 @@ model Keyword {
|
|||||||
abreviation String
|
abreviation String
|
||||||
name String
|
name String
|
||||||
description String?
|
description String?
|
||||||
hpgMissionsType String[]
|
hpgMissionTypes String[]
|
||||||
// relations:
|
// relations:
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,55 @@
|
|||||||
model Mission {
|
model Mission {
|
||||||
id String @id @default(uuid())
|
id Int @id @default(autoincrement())
|
||||||
|
type missionType @default(primär)
|
||||||
state MissionState @default(draft)
|
state MissionState @default(draft)
|
||||||
addressLat Float
|
addressLat Float
|
||||||
addressLng Float
|
addressLng Float
|
||||||
addressStreet String
|
addressStreet String?
|
||||||
addressCity String
|
addressCity String?
|
||||||
addressZip String
|
addressZip String?
|
||||||
missionCategory String
|
addressOSMways Json[] @default([])
|
||||||
missionKeyword String
|
missionCategory String?
|
||||||
missionSummary String
|
missionKeyword String?
|
||||||
|
missionSummary String?
|
||||||
missionPatientInfo String
|
missionPatientInfo String
|
||||||
missionAdditionalInfo String
|
missionAdditionalInfo String
|
||||||
|
missionStationIds String[]
|
||||||
|
missionLog Json[] @default([])
|
||||||
hpgAmbulanceState HpgState? @default(ready)
|
hpgAmbulanceState HpgState? @default(ready)
|
||||||
hpgFireEngineState HpgState? @default(ready)
|
hpgFireEngineState HpgState? @default(ready)
|
||||||
hpgPoliceState HpgState? @default(ready)
|
hpgPoliceState HpgState? @default(ready)
|
||||||
hpgLocationLat Float? @default(0)
|
hpgLocationLat Float? @default(0)
|
||||||
hpgLocationLng Float? @default(0)
|
hpgLocationLng Float? @default(0)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
createdUserId String
|
||||||
|
|
||||||
|
// relations:
|
||||||
|
/**
|
||||||
|
* /**
|
||||||
|
* /**
|
||||||
|
* /**
|
||||||
|
* /**
|
||||||
|
* /**
|
||||||
|
* createdUser User @relation(fields: [createdUserId], references: [id])
|
||||||
|
*/
|
||||||
|
MissionsOnStations MissionsOnStations[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model MissionsOnStations {
|
||||||
|
missionId Int
|
||||||
|
stationId Int
|
||||||
|
|
||||||
|
// relations:
|
||||||
|
Mission Mission @relation(fields: [missionId], references: [id])
|
||||||
|
Station Station @relation(fields: [stationId], references: [id])
|
||||||
|
|
||||||
|
@@id([missionId, stationId])
|
||||||
|
}
|
||||||
|
|
||||||
|
enum missionType {
|
||||||
|
primär
|
||||||
|
sekundär
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MissionState {
|
enum MissionState {
|
||||||
|
|||||||
@@ -32,4 +32,6 @@ model Station {
|
|||||||
longitude Float
|
longitude Float
|
||||||
atcCallsign String
|
atcCallsign String
|
||||||
hideRangeRings Boolean
|
hideRangeRings Boolean
|
||||||
|
|
||||||
|
MissionsOnStations MissionsOnStations[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ model User {
|
|||||||
EventAppointment EventAppointment[]
|
EventAppointment EventAppointment[]
|
||||||
SentMessages ChatMessage[] @relation("SentMessages")
|
SentMessages ChatMessage[] @relation("SentMessages")
|
||||||
ReceivedMessages ChatMessage[] @relation("ReceivedMessages")
|
ReceivedMessages ChatMessage[] @relation("ReceivedMessages")
|
||||||
|
/**
|
||||||
|
* Missions Mission[]
|
||||||
|
*/
|
||||||
|
|
||||||
@@map(name: "users")
|
@@map(name: "users")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const config = [
|
|||||||
turbo: turboPlugin,
|
turbo: turboPlugin,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"turbo/no-undeclared-env-vars": ["error", { allowList: true }],
|
"turbo/no-undeclared-env-vars": ["error", { allowList: [] }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user