Edit Draft Mission

This commit is contained in:
Nicolas
2025-04-28 09:50:58 +02:00
parent e1c3f51809
commit 64fcab59af
5 changed files with 126 additions and 45 deletions

View File

@@ -7,11 +7,18 @@ interface PannelStore {
setOpen: (isOpen: boolean) => void;
missionFormValues?: Partial<MissionOptionalDefaults>;
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
isEditingMission: boolean;
editingMissionId: string | null;
setEditingMission: (isEditing: boolean, missionId: string | null) => void;
}
export const usePannelStore = create<PannelStore>((set) => ({
isOpen: false, // DEBUG, REMOVE LATER FOR PROD
isOpen: false,
setOpen: (isOpen) => set({ isOpen }),
missionFormValues: undefined,
setMissionFormValues: (values) => set({ missionFormValues: values }),
isEditingMission: false,
editingMissionId: null,
setEditingMission: (isEditing, missionId) =>
set({ isEditingMission: isEditing, editingMissionId: missionId }),
}));

View File

@@ -2,6 +2,7 @@ import { useMissionsStore } from "_store/missionsStore";
import { Marker, useMap } from "react-leaflet";
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
import { useMapStore } from "_store/mapStore";
import { usePannelStore } from "_store/pannelStore";
import {
Fragment,
useCallback,
@@ -18,6 +19,7 @@ import {
Minimize2,
Route,
SmartphoneNfc,
PencilLine,
} from "lucide-react";
import {
calculateAnchor,
@@ -35,6 +37,7 @@ export const MISSION_STATUS_COLORS: Record<MissionState, string> = {
draft: "#0092b8",
running: "#155dfc",
finished: "#155dfc",
attention: "rgb(186,105,0)",
};
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 { setEditingMission } = usePannelStore();
const setMissionMarker = useMapStore((state) => state.setOpenMissionMarker);
const currentTab = useMapStore(
(state) =>
@@ -85,6 +89,7 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
(state) => state.setOpenMissionMarker,
);
const { anchor } = useSmartPopup();
const { setMissionFormValues, setOpen } = usePannelStore((state) => state);
return (
<>
@@ -167,8 +172,30 @@ const MissionPopupContent = ({ mission }: { mission: Mission }) => {
>
<SmartphoneNfc className="text-sm" />
</div>
{mission.state === "draft" && (
<div
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="p-2 px-4 flex justify-center items-center cursor-pointer ml-auto"
className={cn(
"p-2 px-4 flex justify-center items-center cursor-pointer",
mission.state !== "draft" && "ml-auto",
)}
style={{
backgroundColor: `${MISSION_STATUS_COLORS[mission.state]}`,
borderBottom:

View File

@@ -28,7 +28,7 @@ import { useSession } from "next-auth/react";
const Einsatzdetails = ({ mission }: { mission: Mission }) => {
const { deleteMission } = useMissionsStore((state) => state);
const { setMissionFormValues } = usePannelStore((state) => state);
const { setMissionFormValues, setOpen } = usePannelStore((state) => state);
return (
<div className="p-4 text-base-content">
<h2 className="flex items-center gap-2 text-lg font-bold mb-3">
@@ -81,6 +81,7 @@ const Einsatzdetails = ({ mission }: { mission: Mission }) => {
hpgLocationLng: undefined,
state: "draft",
});
setOpen(true);
}}
>
<Repeat2 size={18} /> Daten übernehmen

View File

@@ -16,7 +16,10 @@ import { toast } from "react-hot-toast";
import { useMissionsStore } from "_store/missionsStore";
export const MissionForm = () => {
const { isEditingMission, editingMissionId, setEditingMission } =
usePannelStore();
const createMission = useMissionsStore((state) => state.createMission);
const { deleteMission } = useMissionsStore((state) => state);
const session = useSession();
const defaultFormValues = React.useMemo(
() =>
@@ -41,7 +44,7 @@ export const MissionForm = () => {
resolver: zodResolver(MissionOptionalDefaultsSchema),
defaultValues: defaultFormValues,
});
const { missionFormValues } = usePannelStore((state) => state);
const { missionFormValues, setOpen } = usePannelStore((state) => state);
useEffect(() => {
if (session.data?.user.id) {
@@ -290,44 +293,75 @@ export const MissionForm = () => {
<div className="form-control min-h-[140px] max-w-[320px]">
<div className="flex gap-2">
<button
type="submit"
className="btn btn-warning"
onClick={form.handleSubmit(
async (mission: MissionOptionalDefaults) => {
try {
const newMission = await createMission(mission);
toast.success(`Einsatz ${newMission.id} erstellt`);
// TODO: Einsatz alarmieren
} catch (error) {
toast.error(
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
);
}
},
)}
>
<BellRing className="h-4 w-4" /> Alarmieren
</button>
<button
type="submit"
className="btn btn-primary btn-block"
onClick={form.handleSubmit(
async (mission: MissionOptionalDefaults) => {
try {
const newMission = await createMission(mission);
toast.success(`Einsatz ${newMission.id} erstellt`);
form.reset();
} catch (error) {
toast.error(
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
);
}
},
)}
>
<BookmarkPlus className="h-5 w-5" /> Einsatz vorbereiten
</button>
{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
type="submit"
className="btn btn-warning"
onClick={form.handleSubmit(
async (mission: MissionOptionalDefaults) => {
try {
const newMission = await createMission(mission);
toast.success(`Einsatz ${newMission.id} erstellt`);
// TODO: Einsatz alarmieren
setOpen(false);
} catch (error) {
toast.error(
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
);
}
},
)}
>
<BellRing className="h-4 w-4" /> Alarmieren
</button>
<button
type="submit"
className="btn btn-primary btn-block"
onClick={form.handleSubmit(
async (mission: MissionOptionalDefaults) => {
try {
const newMission = await createMission(mission);
toast.success(`Einsatz ${newMission.id} erstellt`);
form.reset();
setOpen(false);
} catch (error) {
toast.error(
`Fehler beim Erstellen des Einsatzes: ${(error as Error).message}`,
);
}
},
)}
>
<BookmarkPlus className="h-5 w-5" /> Einsatz vorbereiten
</button>
</>
)}
</div>
</div>
</form>

View File

@@ -5,22 +5,34 @@ import { Rss, Trash2Icon } from "lucide-react";
export const Pannel = () => {
const { setOpen, setMissionFormValues } = usePannelStore();
const { isEditingMission, editingMissionId, setEditingMission } =
usePannelStore();
return (
<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="flex flex-row justify-between items-center p-4">
<h1 className="text-xl font-bold flex items-center gap-2">
<Rss /> Neuer Einsatz
<Rss /> {isEditingMission ? "Einsatz bearbeiten" : "Neuer Einsatz"}
</h1>
<div>
<button
className="btn btn-ghost btn-sm mr-2 btn-warning"
onClick={() => setMissionFormValues({})}
onClick={() => {
setMissionFormValues({});
setEditingMission(false, null);
}}
>
<Trash2Icon size={18} />
</button>
<button className="btn" onClick={() => setOpen(false)}>
<button
className="btn"
onClick={() => {
setOpen(false);
setEditingMission(false, null);
setMissionFormValues({});
}}
>
Abbrechen
</button>
</div>