Edit Draft Mission
This commit is contained in:
@@ -7,11 +7,18 @@ interface PannelStore {
|
|||||||
setOpen: (isOpen: boolean) => void;
|
setOpen: (isOpen: boolean) => void;
|
||||||
missionFormValues?: Partial<MissionOptionalDefaults>;
|
missionFormValues?: Partial<MissionOptionalDefaults>;
|
||||||
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
||||||
|
isEditingMission: boolean;
|
||||||
|
editingMissionId: string | null;
|
||||||
|
setEditingMission: (isEditing: boolean, missionId: string | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePannelStore = create<PannelStore>((set) => ({
|
export const usePannelStore = create<PannelStore>((set) => ({
|
||||||
isOpen: false, // DEBUG, REMOVE LATER FOR PROD
|
isOpen: false,
|
||||||
setOpen: (isOpen) => set({ isOpen }),
|
setOpen: (isOpen) => set({ isOpen }),
|
||||||
missionFormValues: undefined,
|
missionFormValues: undefined,
|
||||||
setMissionFormValues: (values) => set({ missionFormValues: values }),
|
setMissionFormValues: (values) => set({ missionFormValues: values }),
|
||||||
|
isEditingMission: false,
|
||||||
|
editingMissionId: null,
|
||||||
|
setEditingMission: (isEditing, missionId) =>
|
||||||
|
set({ isEditingMission: isEditing, editingMissionId: missionId }),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMissionsStore } from "_store/missionsStore";
|
|||||||
import { Marker, useMap } from "react-leaflet";
|
import { Marker, useMap } from "react-leaflet";
|
||||||
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
import {
|
import {
|
||||||
Fragment,
|
Fragment,
|
||||||
useCallback,
|
useCallback,
|
||||||
@@ -18,6 +19,7 @@ import {
|
|||||||
Minimize2,
|
Minimize2,
|
||||||
Route,
|
Route,
|
||||||
SmartphoneNfc,
|
SmartphoneNfc,
|
||||||
|
PencilLine,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
calculateAnchor,
|
calculateAnchor,
|
||||||
@@ -35,6 +37,7 @@ export const MISSION_STATUS_COLORS: Record<MissionState, string> = {
|
|||||||
draft: "#0092b8",
|
draft: "#0092b8",
|
||||||
running: "#155dfc",
|
running: "#155dfc",
|
||||||
finished: "#155dfc",
|
finished: "#155dfc",
|
||||||
|
attention: "rgb(186,105,0)",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MISSION_STATUS_TEXT_COLORS: Record<MissionState, string> = {
|
export const MISSION_STATUS_TEXT_COLORS: Record<MissionState, string> = {
|
||||||
@@ -44,6 +47,7 @@ export const MISSION_STATUS_TEXT_COLORS: Record<MissionState, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
||||||
|
const { setEditingMission } = usePannelStore();
|
||||||
const setMissionMarker = useMapStore((state) => state.setOpenMissionMarker);
|
const setMissionMarker = useMapStore((state) => state.setOpenMissionMarker);
|
||||||
const currentTab = useMapStore(
|
const currentTab = useMapStore(
|
||||||
(state) =>
|
(state) =>
|
||||||
@@ -85,6 +89,7 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
|||||||
(state) => state.setOpenMissionMarker,
|
(state) => state.setOpenMissionMarker,
|
||||||
);
|
);
|
||||||
const { anchor } = useSmartPopup();
|
const { anchor } = useSmartPopup();
|
||||||
|
const { setMissionFormValues, setOpen } = usePannelStore((state) => state);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -167,8 +172,30 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
|
|||||||
>
|
>
|
||||||
<SmartphoneNfc className="text-sm" />
|
<SmartphoneNfc className="text-sm" />
|
||||||
</div>
|
</div>
|
||||||
|
{mission.state === "draft" && (
|
||||||
<div
|
<div
|
||||||
className="p-2 px-4 flex justify-center items-center cursor-pointer ml-auto"
|
className="p-2 px-4 flex justify-center items-center cursor-pointer ml-auto"
|
||||||
|
style={{
|
||||||
|
backgroundColor: `${MISSION_STATUS_COLORS["attention"]}`,
|
||||||
|
borderBottom: "5px solid transparent",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setMissionFormValues({
|
||||||
|
...mission,
|
||||||
|
state: "draft",
|
||||||
|
});
|
||||||
|
setEditingMission(true, mission.id);
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PencilLine className="text-sm" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"p-2 px-4 flex justify-center items-center cursor-pointer",
|
||||||
|
mission.state !== "draft" && "ml-auto",
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
|
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
|
||||||
borderBottom:
|
borderBottom:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { useSession } from "next-auth/react";
|
|||||||
|
|
||||||
const Einsatzdetails = ({ mission }: { mission: Mission }) => {
|
const Einsatzdetails = ({ mission }: { mission: Mission }) => {
|
||||||
const { deleteMission } = useMissionsStore((state) => state);
|
const { deleteMission } = useMissionsStore((state) => state);
|
||||||
const { setMissionFormValues } = usePannelStore((state) => state);
|
const { setMissionFormValues, setOpen } = usePannelStore((state) => state);
|
||||||
return (
|
return (
|
||||||
<div className="p-4 text-base-content">
|
<div className="p-4 text-base-content">
|
||||||
<h2 className="flex items-center gap-2 text-lg font-bold mb-3">
|
<h2 className="flex items-center gap-2 text-lg font-bold mb-3">
|
||||||
@@ -81,6 +81,7 @@ const Einsatzdetails = ({ mission }: { mission: Mission }) => {
|
|||||||
hpgLocationLng: undefined,
|
hpgLocationLng: undefined,
|
||||||
state: "draft",
|
state: "draft",
|
||||||
});
|
});
|
||||||
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Repeat2 size={18} /> Daten übernehmen
|
<Repeat2 size={18} /> Daten übernehmen
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import { toast } from "react-hot-toast";
|
|||||||
import { useMissionsStore } from "_store/missionsStore";
|
import { useMissionsStore } from "_store/missionsStore";
|
||||||
|
|
||||||
export const MissionForm = () => {
|
export const MissionForm = () => {
|
||||||
|
const { isEditingMission, editingMissionId, setEditingMission } =
|
||||||
|
usePannelStore();
|
||||||
const createMission = useMissionsStore((state) => state.createMission);
|
const createMission = useMissionsStore((state) => state.createMission);
|
||||||
|
const { deleteMission } = useMissionsStore((state) => state);
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const defaultFormValues = React.useMemo(
|
const defaultFormValues = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -41,7 +44,7 @@ export const MissionForm = () => {
|
|||||||
resolver: zodResolver(MissionOptionalDefaultsSchema),
|
resolver: zodResolver(MissionOptionalDefaultsSchema),
|
||||||
defaultValues: defaultFormValues,
|
defaultValues: defaultFormValues,
|
||||||
});
|
});
|
||||||
const { missionFormValues } = usePannelStore((state) => state);
|
const { missionFormValues, setOpen } = usePannelStore((state) => state);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session.data?.user.id) {
|
if (session.data?.user.id) {
|
||||||
@@ -290,6 +293,33 @@ export const MissionForm = () => {
|
|||||||
|
|
||||||
<div className="form-control min-h-[140px] max-w-[320px]">
|
<div className="form-control min-h-[140px] max-w-[320px]">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
{isEditingMission && editingMissionId ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary btn-block"
|
||||||
|
onClick={form.handleSubmit(
|
||||||
|
async (mission: MissionOptionalDefaults) => {
|
||||||
|
try {
|
||||||
|
deleteMission(editingMissionId);
|
||||||
|
const newMission = await createMission(mission);
|
||||||
|
toast.success(
|
||||||
|
`Einsatz ${newMission.id} erfolgreich aktualisiert`,
|
||||||
|
);
|
||||||
|
setEditingMission(false, null); // Reset editing state
|
||||||
|
form.reset(); // Reset the form
|
||||||
|
setOpen(false);
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(
|
||||||
|
`Fehler beim Aktualisieren des Einsatzes: ${(error as Error).message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
Änderungen speichern
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-warning"
|
className="btn btn-warning"
|
||||||
@@ -299,6 +329,7 @@ export const MissionForm = () => {
|
|||||||
const newMission = await createMission(mission);
|
const newMission = await createMission(mission);
|
||||||
toast.success(`Einsatz ${newMission.id} erstellt`);
|
toast.success(`Einsatz ${newMission.id} erstellt`);
|
||||||
// TODO: Einsatz alarmieren
|
// TODO: Einsatz alarmieren
|
||||||
|
setOpen(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(
|
toast.error(
|
||||||
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
|
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
|
||||||
@@ -318,6 +349,7 @@ export const MissionForm = () => {
|
|||||||
const newMission = await createMission(mission);
|
const newMission = await createMission(mission);
|
||||||
toast.success(`Einsatz ${newMission.id} erstellt`);
|
toast.success(`Einsatz ${newMission.id} erstellt`);
|
||||||
form.reset();
|
form.reset();
|
||||||
|
setOpen(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(
|
toast.error(
|
||||||
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
|
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
|
||||||
@@ -328,6 +360,8 @@ export const MissionForm = () => {
|
|||||||
>
|
>
|
||||||
<BookmarkPlus className="h-5 w-5" /> Einsatz vorbereiten
|
<BookmarkPlus className="h-5 w-5" /> Einsatz vorbereiten
|
||||||
</button>
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -5,22 +5,34 @@ import { Rss, Trash2Icon } from "lucide-react";
|
|||||||
|
|
||||||
export const Pannel = () => {
|
export const Pannel = () => {
|
||||||
const { setOpen, setMissionFormValues } = usePannelStore();
|
const { setOpen, setMissionFormValues } = usePannelStore();
|
||||||
|
const { isEditingMission, editingMissionId, setEditingMission } =
|
||||||
|
usePannelStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("flex-1 max-w-[600px] z-9999999")}>
|
<div className={cn("flex-1 max-w-[600px] z-9999999")}>
|
||||||
<div className="bg-base-100 min-h-screen h-full max-h-screen w-full overflow-auto">
|
<div className="bg-base-100 min-h-screen h-full max-h-screen w-full overflow-auto">
|
||||||
<div className="flex flex-row justify-between items-center p-4">
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
<h1 className="text-xl font-bold flex items-center gap-2">
|
<h1 className="text-xl font-bold flex items-center gap-2">
|
||||||
<Rss /> Neuer Einsatz
|
<Rss /> {isEditingMission ? "Einsatz bearbeiten" : "Neuer Einsatz"}
|
||||||
</h1>
|
</h1>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className="btn btn-ghost btn-sm mr-2 btn-warning"
|
className="btn btn-ghost btn-sm mr-2 btn-warning"
|
||||||
onClick={() => setMissionFormValues({})}
|
onClick={() => {
|
||||||
|
setMissionFormValues({});
|
||||||
|
setEditingMission(false, null);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Trash2Icon size={18} />
|
<Trash2Icon size={18} />
|
||||||
</button>
|
</button>
|
||||||
<button className="btn" onClick={() => setOpen(false)}>
|
<button
|
||||||
|
className="btn"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
|
setEditingMission(false, null);
|
||||||
|
setMissionFormValues({});
|
||||||
|
}}
|
||||||
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user