const DEFAULT_LOCATION_NAME = "Default Location"; export const DEFAULT_MAP_SIZE = { width: 1000, height: 700, }; export const MIN_MAP_ZOOM = 0.3; export const MAX_MAP_ZOOM = 1.6; export const DEFAULT_MAP_FILTERS = { showZones: true, showLabels: true, showCounts: true, showPins: false, showMyItems: true, showOtherItems: false, showCompleted: false, showUnmapped: false, }; export const MAP_OBJECT_TYPES = [ "zone", "aisle", "entrance", "checkout", "shelf", "wall", "department", "anchor", "other", ]; export function getStoreName(location) { return location?.name || "Store"; } export function getLocationName(location) { if (!location) return "Location"; if (!location.location_name || location.location_name === DEFAULT_LOCATION_NAME) { return "Default"; } return location.location_name; } export function getMapStatus(state, options = {}) { if (options.hasUnsavedChanges) return "Unsaved Draft"; if (!state?.draft_map && !state?.published_map) return "No Map"; if (options.mode === "edit") return "Draft"; if (options.mode === "view" && options.previewDraft && state?.draft_map) return "Viewing Draft"; if (state?.published_map) return "Published"; if (state?.draft_map) return "Draft"; return "No Map"; } export function objectZoneId(object) { return object?.zone_id ? String(object.zone_id) : ""; } export function mapForMode(mapState, mode, previewDraft) { if (mode === "edit") { return mapState?.draft_map || mapState?.published_map || null; } if (previewDraft && mapState?.draft_map) { return mapState.draft_map; } return mapState?.published_map || mapState?.draft_map || null; } export function objectsForMode(mapState, mode, previewDraft) { if (mode === "edit") { return mapState?.draft_objects?.length ? mapState.draft_objects : mapState?.published_objects || []; } if (previewDraft && mapState?.draft_map) { return mapState.draft_objects || []; } return mapState?.published_objects?.length ? mapState.published_objects : mapState?.draft_objects || []; } export function createClientObject(zone, index = 0) { const offset = index * 24; return { client_id: `new-${Date.now()}-${index}`, zone_id: zone?.id || null, zone_name: zone?.name || null, type: "zone", label: zone?.name || "New Area", x: 80 + offset, y: 80 + offset, width: 220, height: 130, rotation: 0, locked: false, visible: true, sort_order: index + 1, metadata_json: {}, }; } export function normalizeMapObject(object, index = 0) { const hasExplicitLabel = Object.prototype.hasOwnProperty.call(object, "label"); return { ...object, client_id: object.client_id || `object-${object.id || Date.now()}-${index}`, zone_id: object.zone_id ?? null, zone_name: object.zone_name || null, type: MAP_OBJECT_TYPES.includes(object.type) ? object.type : "zone", label: hasExplicitLabel ? String(object.label ?? "").trim() : object.zone_name || "Map Area", x: Number(object.x) || 0, y: Number(object.y) || 0, width: Math.max(40, Number(object.width) || 160), height: Math.max(40, Number(object.height) || 100), rotation: Number(object.rotation) || 0, locked: Boolean(object.locked), visible: object.visible !== false, sort_order: Number(object.sort_order ?? object.sortOrder ?? index + 1), metadata_json: object.metadata_json || {}, }; } export function getObjectKey(object) { return String(object.id || object.client_id); } export function getMapObjectDisplayLabel(object, fallback = "Map Area") { const label = String(object?.label ?? "").trim(); const zoneName = String(object?.zone_name ?? "").trim(); return label || zoneName || fallback; } export function prepareObjectsForSave(objects) { return objects.map((object, index) => ({ zone_id: object.zone_id || null, type: object.type || "zone", label: String(object.label ?? "").trim(), x: Number(object.x) || 0, y: Number(object.y) || 0, width: Math.max(40, Number(object.width) || 160), height: Math.max(40, Number(object.height) || 100), rotation: Number(object.rotation) || 0, locked: Boolean(object.locked), visible: object.visible !== false, sort_order: index + 1, metadata_json: object.metadata_json || {}, })); } export function itemMatchesMapFilters(item, filters, username) { if (!filters.showCompleted && item.bought) return false; const addedBy = Array.isArray(item.added_by_users) ? item.added_by_users : []; const hasOwnershipData = addedBy.length > 0 && username; const isMine = hasOwnershipData ? addedBy.includes(username) : true; if (isMine && !filters.showMyItems) return false; if (!isMine && !filters.showOtherItems) return false; return true; } export function itemsForZone(items, zoneId, filters, username) { return items.filter((item) => ( String(item.zone_id || "") === String(zoneId || "") && itemMatchesMapFilters(item, filters, username) )); } export function unmappedItems(items, filters, username) { return items.filter((item) => !item.zone_id && itemMatchesMapFilters(item, filters, username)); } export function clientPointToMap(event, svgElement, mapSize) { const rect = svgElement.getBoundingClientRect(); const x = ((event.clientX - rect.left) / rect.width) * mapSize.width; const y = ((event.clientY - rect.top) / rect.height) * mapSize.height; return { x, y }; } export function clampMapZoom(value) { return Math.max(MIN_MAP_ZOOM, Math.min(MAX_MAP_ZOOM, value)); } export function clampObjectToMap(object, mapSize) { const width = Math.max(40, Math.min(object.width, mapSize.width)); const height = Math.max(40, Math.min(object.height, mapSize.height)); return { ...object, width, height, x: Math.max(0, Math.min(object.x, mapSize.width - width)), y: Math.max(0, Math.min(object.y, mapSize.height - height)), }; }