fix: keep saved map drafts after publish failure
This commit is contained in:
parent
daef7a86de
commit
415a7223cd
@ -270,12 +270,18 @@ export default function LocationMapManager() {
|
||||
const handlePublish = async () => {
|
||||
if (!activeHousehold?.id || !locationId) return;
|
||||
beginSaving("publish");
|
||||
let savedPendingDraft = false;
|
||||
try {
|
||||
if (hasUnsavedChanges) {
|
||||
await saveLocationMapDraft(activeHousehold.id, locationId, {
|
||||
const saveResponse = await saveLocationMapDraft(activeHousehold.id, locationId, {
|
||||
map: mapDraft,
|
||||
objects: prepareObjectsForSave(objects),
|
||||
});
|
||||
savedPendingDraft = true;
|
||||
setMapState(saveResponse.data);
|
||||
setMode("edit");
|
||||
setPreviewDraft(true);
|
||||
syncMapDraftFromState(saveResponse.data, "edit", true);
|
||||
}
|
||||
|
||||
const response = await publishLocationMapDraft(activeHousehold.id, locationId);
|
||||
@ -291,7 +297,11 @@ export default function LocationMapManager() {
|
||||
: "Map is now visible to household members"
|
||||
);
|
||||
} catch (error) {
|
||||
toast.error("Publish failed", getApiErrorMessage(error, "Failed to publish map"));
|
||||
const message = getApiErrorMessage(error, "Failed to publish map");
|
||||
toast.error(
|
||||
"Publish failed",
|
||||
savedPendingDraft ? `${message}. Draft changes were saved.` : message
|
||||
);
|
||||
} finally {
|
||||
endSaving();
|
||||
}
|
||||
|
||||
@ -967,6 +967,89 @@ test("admin publish saves pending map edits before publishing", async ({ page })
|
||||
await expect(page.getByRole("button", { name: "Map area Live Bakery" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("admin publish failure keeps successfully saved pending edits", async ({ page }) => {
|
||||
await mockMapShell(page);
|
||||
|
||||
let mapState = publishedMapState([
|
||||
{
|
||||
id: 1461,
|
||||
location_map_id: 901,
|
||||
zone_id: 501,
|
||||
zone_name: "Bakery",
|
||||
type: "zone",
|
||||
label: "Live Bakery",
|
||||
x: 40,
|
||||
y: 40,
|
||||
width: 260,
|
||||
height: 160,
|
||||
rotation: 0,
|
||||
locked: false,
|
||||
visible: true,
|
||||
sort_order: 1,
|
||||
},
|
||||
], true);
|
||||
let savedPayload: Record<string, unknown> | null = null;
|
||||
let publishCalled = false;
|
||||
|
||||
await page.route("**/households/1/locations/10/map", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify(mapState),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/households/1/locations/10/map/draft", async (route) => {
|
||||
savedPayload = await route.request().postDataJSON();
|
||||
const savedObjects = (savedPayload.objects as Array<Record<string, unknown>>).map((object, index) => ({
|
||||
id: 1465 + index,
|
||||
location_map_id: 900,
|
||||
zone_name: object.zone_id === 501 ? "Bakery" : null,
|
||||
...object,
|
||||
}));
|
||||
mapState = draftAndPublishedMapState(savedObjects, mapState.published_objects, true);
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify(mapState),
|
||||
});
|
||||
});
|
||||
|
||||
await page.route("**/households/1/locations/10/map/publish", async (route) => {
|
||||
publishCalled = true;
|
||||
await route.fulfill({
|
||||
status: 503,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ error: { message: "Publish service unavailable" } }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("/stores/100/locations/10/map");
|
||||
|
||||
await page.getByRole("button", { name: "Edit Map" }).click();
|
||||
await page.getByRole("button", { name: "Edit Objects" }).click();
|
||||
await page.locator(".location-map-object", { hasText: "Live Bakery" }).locator("rect").first().click();
|
||||
await page.getByRole("textbox", { name: "Label" }).fill("Saved Draft Bakery");
|
||||
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
|
||||
|
||||
await page.getByRole("button", { name: "Publish", exact: true }).click();
|
||||
|
||||
await expect.poll(() => publishCalled).toBe(true);
|
||||
expect(savedPayload).not.toBeNull();
|
||||
expect(savedPayload?.objects).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
label: "Saved Draft Bakery",
|
||||
zone_id: 501,
|
||||
}),
|
||||
])
|
||||
);
|
||||
await expect(page.locator(".location-map-status")).toHaveText("Draft");
|
||||
await expect(page.getByRole("button", { name: "Save Draft" })).toBeDisabled();
|
||||
await expect(page.getByRole("button", { name: "Map area Saved Draft Bakery" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Map area Live Bakery" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("viewer wraps long zone labels and keeps item counts visible", async ({ page }) => {
|
||||
await mockMapShell(page);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user