Add store location map manager #20
@ -62,6 +62,8 @@ export default function LocationMapObject({
|
|||||||
const countY = filters.showLabels && labelLines.length > 1 ? object.y + 76 : object.y + 52;
|
const countY = filters.showLabels && labelLines.length > 1 ? object.y + 76 : object.y + 52;
|
||||||
const resizeHandleSize = Math.min(96, Math.max(44, Math.ceil(48 / zoom)));
|
const resizeHandleSize = Math.min(96, Math.max(44, Math.ceil(48 / zoom)));
|
||||||
const resizeHandleInset = 6;
|
const resizeHandleInset = 6;
|
||||||
|
const lockBadgeSize = Math.min(52, Math.max(30, Math.ceil(34 / zoom)));
|
||||||
|
const lockBadgeInset = 8;
|
||||||
const resizeHandleX = Math.min(
|
const resizeHandleX = Math.min(
|
||||||
Math.max(0, mapSize.width - resizeHandleSize),
|
Math.max(0, mapSize.width - resizeHandleSize),
|
||||||
Math.max(
|
Math.max(
|
||||||
@ -76,6 +78,17 @@ export default function LocationMapObject({
|
|||||||
object.y + object.height - resizeHandleSize - resizeHandleInset
|
object.y + object.height - resizeHandleSize - resizeHandleInset
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
const lockBadgeX = Math.min(
|
||||||
|
Math.max(0, mapSize.width - lockBadgeSize),
|
||||||
|
Math.max(
|
||||||
|
object.x + lockBadgeInset,
|
||||||
|
object.x + object.width - lockBadgeSize - lockBadgeInset
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const lockBadgeY = Math.min(
|
||||||
|
Math.max(0, mapSize.height - lockBadgeSize),
|
||||||
|
object.y + lockBadgeInset
|
||||||
|
);
|
||||||
const pinDots = filters.showPins
|
const pinDots = filters.showPins
|
||||||
? zoneItems.slice(0, PIN_PREVIEW_LIMIT).map((item, itemIndex) => {
|
? zoneItems.slice(0, PIN_PREVIEW_LIMIT).map((item, itemIndex) => {
|
||||||
const column = itemIndex % 4;
|
const column = itemIndex % 4;
|
||||||
@ -99,6 +112,7 @@ export default function LocationMapObject({
|
|||||||
"location-map-object",
|
"location-map-object",
|
||||||
isSelected ? "is-selected" : "",
|
isSelected ? "is-selected" : "",
|
||||||
canEditObjects ? "is-editable" : "",
|
canEditObjects ? "is-editable" : "",
|
||||||
|
object.locked ? "is-locked" : "",
|
||||||
].filter(Boolean).join(" ")}
|
].filter(Boolean).join(" ")}
|
||||||
transform={`rotate(${object.rotation || 0} ${object.x + object.width / 2} ${object.y + object.height / 2})`}
|
transform={`rotate(${object.rotation || 0} ${object.x + object.width / 2} ${object.y + object.height / 2})`}
|
||||||
>
|
>
|
||||||
@ -131,6 +145,31 @@ export default function LocationMapObject({
|
|||||||
</text>
|
</text>
|
||||||
) : null}
|
) : null}
|
||||||
{pinDots}
|
{pinDots}
|
||||||
|
{canEditObjects && isSelected && object.locked ? (
|
||||||
|
<g
|
||||||
|
className="location-map-lock-badge"
|
||||||
|
transform={`translate(${lockBadgeX} ${lockBadgeY})`}
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<rect width={lockBadgeSize} height={lockBadgeSize} rx="10" />
|
||||||
|
<path
|
||||||
|
d={[
|
||||||
|
`M ${lockBadgeSize * 0.32} ${lockBadgeSize * 0.48}`,
|
||||||
|
`V ${lockBadgeSize * 0.4}`,
|
||||||
|
`C ${lockBadgeSize * 0.32} ${lockBadgeSize * 0.24}, ${lockBadgeSize * 0.68} ${lockBadgeSize * 0.24}, ${lockBadgeSize * 0.68} ${lockBadgeSize * 0.4}`,
|
||||||
|
`V ${lockBadgeSize * 0.48}`,
|
||||||
|
].join(" ")}
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
className="location-map-lock-body"
|
||||||
|
x={lockBadgeSize * 0.26}
|
||||||
|
y={lockBadgeSize * 0.46}
|
||||||
|
width={lockBadgeSize * 0.48}
|
||||||
|
height={lockBadgeSize * 0.34}
|
||||||
|
rx={lockBadgeSize * 0.08}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
) : null}
|
||||||
{canEditObjects && isSelected && !object.locked ? (
|
{canEditObjects && isSelected && !object.locked ? (
|
||||||
<rect
|
<rect
|
||||||
className="location-map-resize-handle"
|
className="location-map-resize-handle"
|
||||||
|
|||||||
@ -328,10 +328,18 @@
|
|||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-object.is-editable.is-locked rect:first-child {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-object.is-editable rect:first-child:active {
|
.location-map-object.is-editable rect:first-child:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-object.is-editable.is-locked rect:first-child:active {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-object:not(.is-selected):hover rect:first-child {
|
.location-map-object:not(.is-selected):hover rect:first-child {
|
||||||
fill: rgba(37, 99, 141, 0.88);
|
fill: rgba(37, 99, 141, 0.88);
|
||||||
stroke: rgba(147, 197, 253, 0.9);
|
stroke: rgba(147, 197, 253, 0.9);
|
||||||
@ -383,6 +391,29 @@
|
|||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.location-map-lock-badge {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-map-lock-badge rect:first-child {
|
||||||
|
fill: rgba(15, 23, 42, 0.88);
|
||||||
|
stroke: rgba(251, 191, 36, 0.88);
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-map-lock-badge path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #fde68a;
|
||||||
|
stroke-width: 3;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-map-lock-badge .location-map-lock-body {
|
||||||
|
fill: #fde68a;
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
|
||||||
.location-map-empty-canvas {
|
.location-map-empty-canvas {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|||||||
@ -1803,9 +1803,11 @@ test("admin locked map areas hide resize affordances", async ({ page }) => {
|
|||||||
await page.getByRole("button", { name: "Continue Editing" }).click();
|
await page.getByRole("button", { name: "Continue Editing" }).click();
|
||||||
await page.getByRole("button", { name: "Edit Areas" }).click();
|
await page.getByRole("button", { name: "Edit Areas" }).click();
|
||||||
const bakeryArea = page.getByRole("button", { name: "Map area Bakery" });
|
const bakeryArea = page.getByRole("button", { name: "Map area Bakery" });
|
||||||
|
const bakeryObject = page.locator(".location-map-object", { hasText: "Bakery" });
|
||||||
await bakeryArea.click();
|
await bakeryArea.click();
|
||||||
|
|
||||||
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
||||||
|
await expect(page.locator(".location-map-lock-badge")).toHaveCount(0);
|
||||||
await expect(page.getByRole("spinbutton", { name: "X" })).toHaveCount(0);
|
await expect(page.getByRole("spinbutton", { name: "X" })).toHaveCount(0);
|
||||||
const lockedToggle = page.getByRole("button", { name: "Locked" });
|
const lockedToggle = page.getByRole("button", { name: "Locked" });
|
||||||
const visibleToggle = page.getByRole("button", { name: "Visible" });
|
const visibleToggle = page.getByRole("button", { name: "Visible" });
|
||||||
@ -1820,6 +1822,8 @@ test("admin locked map areas hide resize affordances", async ({ page }) => {
|
|||||||
await expect(page.getByRole("spinbutton", { name: "W" })).toHaveCount(0);
|
await expect(page.getByRole("spinbutton", { name: "W" })).toHaveCount(0);
|
||||||
await expect(page.getByRole("spinbutton", { name: "H" })).toHaveCount(0);
|
await expect(page.getByRole("spinbutton", { name: "H" })).toHaveCount(0);
|
||||||
await expect(page.locator(".location-map-resize-handle")).toHaveCount(0);
|
await expect(page.locator(".location-map-resize-handle")).toHaveCount(0);
|
||||||
|
await expect(page.locator(".location-map-lock-badge")).toBeVisible();
|
||||||
|
await expect(bakeryObject).toHaveClass(/is-locked/);
|
||||||
await expect(page.getByText("Unlock this area before moving or resizing it.")).toHaveCount(0);
|
await expect(page.getByText("Unlock this area before moving or resizing it.")).toHaveCount(0);
|
||||||
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
|
await expect(page.locator(".location-map-status")).toHaveText("Unsaved Draft");
|
||||||
|
|
||||||
@ -1830,6 +1834,7 @@ test("admin locked map areas hide resize affordances", async ({ page }) => {
|
|||||||
await lockedToggle.click();
|
await lockedToggle.click();
|
||||||
await expect(lockedToggle).toHaveAttribute("aria-pressed", "false");
|
await expect(lockedToggle).toHaveAttribute("aria-pressed", "false");
|
||||||
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
await expect(page.locator(".location-map-resize-handle")).toBeVisible();
|
||||||
|
await expect(page.locator(".location-map-lock-badge")).toHaveCount(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("admin selected overlapping map area renders above other areas", async ({ page }) => {
|
test("admin selected overlapping map area renders above other areas", async ({ page }) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user