Add store location map manager #20

Open
nalalangan wants to merge 206 commits from feature/location-map-manager into feature/store-selector-modal
3 changed files with 75 additions and 0 deletions
Showing only changes of commit 67ae2763b2 - Show all commits

View File

@ -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"

View File

@ -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%;

View File

@ -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 }) => {