grocery-app/frontend/src/hooks/useLocationMapDraftActions.js

124 lines
4.5 KiB
JavaScript

import { useCallback } from "react";
import {
createBlankLocationMap,
createLocationMapFromZones,
publishLocationMapDraft,
saveLocationMapDraft,
} from "../api/locationMaps";
import getApiErrorMessage from "../lib/getApiErrorMessage";
import { getObjectKey, prepareObjectsForSave } from "../lib/locationMapUtils";
export default function useLocationMapDraftActions({
activeHouseholdId,
beginSaving,
endSaving,
hasUnsavedChanges,
locationId,
mapDraft,
objects,
selectedObjectKey,
setEditorTool,
setMapState,
setMode,
setPreviewDraft,
syncMapDraftFromState,
toast,
}) {
const selectedObjectIndex = selectedObjectKey
? objects.findIndex((object) => getObjectKey(object) === selectedObjectKey)
: -1;
const applyDraftResponse = useCallback((response, nextMode = "edit", nextPreviewDraft = true, options = {}) => {
setMapState(response.data);
setMode(nextMode);
setPreviewDraft(nextPreviewDraft);
syncMapDraftFromState(response.data, nextMode, nextPreviewDraft, options);
}, [setMapState, setMode, setPreviewDraft, syncMapDraftFromState]);
const handleCreateBlank = useCallback(async () => {
if (!activeHouseholdId || !locationId) return;
beginSaving("create-blank");
try {
const response = await createBlankLocationMap(activeHouseholdId, locationId, mapDraft);
applyDraftResponse(response);
setEditorTool("edit");
toast.success("Created map", "Blank draft map created");
} catch (error) {
toast.error("Create map failed", getApiErrorMessage(error, "Failed to create map"));
} finally {
endSaving();
}
}, [activeHouseholdId, applyDraftResponse, beginSaving, endSaving, locationId, mapDraft, setEditorTool, toast]);
const handleCreateFromZones = useCallback(async () => {
if (!activeHouseholdId || !locationId) return;
beginSaving("create-zones");
try {
const response = await createLocationMapFromZones(activeHouseholdId, locationId, mapDraft);
applyDraftResponse(response);
setEditorTool("edit");
toast.success("Created starter map", "Zones were added as editable rectangles");
} catch (error) {
toast.error("Create map failed", getApiErrorMessage(error, "Failed to create map from zones"));
} finally {
endSaving();
}
}, [activeHouseholdId, applyDraftResponse, beginSaving, endSaving, locationId, mapDraft, setEditorTool, toast]);
const handleSaveDraft = useCallback(async () => {
if (!activeHouseholdId || !locationId) return;
beginSaving("save");
try {
const response = await saveLocationMapDraft(activeHouseholdId, locationId, {
map: mapDraft,
objects: prepareObjectsForSave(objects),
});
applyDraftResponse(response, "edit", true, { preserveSelectedIndex: selectedObjectIndex });
toast.success("Saved draft", "Map draft saved");
} catch (error) {
toast.error("Save draft failed", getApiErrorMessage(error, "Failed to save map draft"));
} finally {
endSaving();
}
}, [
activeHouseholdId, applyDraftResponse, beginSaving, endSaving, locationId,
mapDraft, objects, selectedObjectIndex, toast,
]);
const handlePublish = useCallback(async () => {
if (!activeHouseholdId || !locationId) return;
beginSaving("publish");
let savedPendingDraft = false;
try {
if (hasUnsavedChanges) {
const saveResponse = await saveLocationMapDraft(activeHouseholdId, locationId, {
map: mapDraft,
objects: prepareObjectsForSave(objects),
});
savedPendingDraft = true;
applyDraftResponse(saveResponse, "edit", true, { preserveSelectedIndex: selectedObjectIndex });
}
const response = await publishLocationMapDraft(activeHouseholdId, locationId);
applyDraftResponse(response, "view", false);
setEditorTool("pan");
toast.success(
"Published map",
hasUnsavedChanges
? "Latest edits were saved and published"
: "Map is now visible to household members"
);
} catch (error) {
const message = getApiErrorMessage(error, "Failed to publish map");
toast.error("Publish failed", savedPendingDraft ? `${message}. Draft changes were saved.` : message);
} finally {
endSaving();
}
}, [
activeHouseholdId, applyDraftResponse, beginSaving, endSaving, hasUnsavedChanges,
locationId, mapDraft, objects, selectedObjectIndex, setEditorTool, toast,
]);
return { handleCreateBlank, handleCreateFromZones, handlePublish, handleSaveDraft };
}