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 resizeHandleSize = Math.min(96, Math.max(44, Math.ceil(48 / zoom)));
|
||||
const resizeHandleInset = 6;
|
||||
const lockBadgeSize = Math.min(52, Math.max(30, Math.ceil(34 / zoom)));
|
||||
const lockBadgeInset = 8;
|
||||
const resizeHandleX = Math.min(
|
||||
Math.max(0, mapSize.width - resizeHandleSize),
|
||||
Math.max(
|
||||
@ -76,6 +78,17 @@ export default function LocationMapObject({
|
||||
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
|
||||
? zoneItems.slice(0, PIN_PREVIEW_LIMIT).map((item, itemIndex) => {
|
||||
const column = itemIndex % 4;
|
||||
@ -99,6 +112,7 @@ export default function LocationMapObject({
|
||||
"location-map-object",
|
||||
isSelected ? "is-selected" : "",
|
||||
canEditObjects ? "is-editable" : "",
|
||||
object.locked ? "is-locked" : "",
|
||||
].filter(Boolean).join(" ")}
|
||||
transform={`rotate(${object.rotation || 0} ${object.x + object.width / 2} ${object.y + object.height / 2})`}
|
||||
>
|
||||
@ -131,6 +145,31 @@ export default function LocationMapObject({
|
||||
</text>
|
||||
) : null}
|
||||
{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 ? (
|
||||
<rect
|
||||
className="location-map-resize-handle"
|
||||
|
||||
@ -328,10 +328,18 @@
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.location-map-object.is-editable.is-locked rect:first-child {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.location-map-object.is-editable rect:first-child:active {
|
||||
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 {
|
||||
fill: rgba(37, 99, 141, 0.88);
|
||||
stroke: rgba(147, 197, 253, 0.9);
|
||||
@ -383,6 +391,29 @@
|
||||
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 {
|
||||
position: sticky;
|
||||
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: "Edit Areas" }).click();
|
||||
const bakeryArea = page.getByRole("button", { name: "Map area Bakery" });
|
||||
const bakeryObject = page.locator(".location-map-object", { hasText: "Bakery" });
|
||||
await bakeryArea.click();
|
||||
|
||||
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);
|
||||
const lockedToggle = page.getByRole("button", { name: "Locked" });
|
||||
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: "H" })).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.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 expect(lockedToggle).toHaveAttribute("aria-pressed", "false");
|
||||
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 }) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user