diff --git a/frontend/src/components/maps/LocationMapBottomSheet.jsx b/frontend/src/components/maps/LocationMapBottomSheet.jsx
index 05cfb7a..e31dd5b 100644
--- a/frontend/src/components/maps/LocationMapBottomSheet.jsx
+++ b/frontend/src/components/maps/LocationMapBottomSheet.jsx
@@ -2,22 +2,17 @@ import { useMemo } from "react";
import {
DEFAULT_MAP_FILTERS,
getMapObjectDisplayLabel,
+ objectZoneId,
} from "../../lib/locationMapUtils";
+import {
+ LocationMapLayerPanel,
+ LocationMapOverview,
+ MAP_DISPLAY_CONTROLS,
+ SelectedMapObjectForm,
+ SelectedZoneItemsPanel,
+ UnmappedItemsPanel,
+} from "./LocationMapBottomSheetSections";
-function objectZoneId(object) {
- return object?.zone_id ? String(object.zone_id) : "";
-}
-
-const DISPLAY_CONTROLS = [
- ["showZones", "Zones"],
- ["showLabels", "Labels"],
- ["showCounts", "Counts"],
- ["showPins", "Pins"],
- ["showMyItems", "Mine"],
- ["showOtherItems", "Others"],
- ["showCompleted", "Bought"],
- ["showUnmapped", "Unmapped"],
-];
const EMPTY_ITEMS = [];
export default function LocationMapBottomSheet({
@@ -87,7 +82,7 @@ export default function LocationMapBottomSheet({
const showEditorControls = mode === "edit" && canManage;
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
const changedLayerCount = useMemo(
- () => DISPLAY_CONTROLS.filter(([key]) => filters[key] !== DEFAULT_MAP_FILTERS[key]).length,
+ () => MAP_DISPLAY_CONTROLS.filter(([key]) => filters[key] !== DEFAULT_MAP_FILTERS[key]).length,
[filters]
);
const totalAreaCount = mapObjects.length;
@@ -102,11 +97,6 @@ export default function LocationMapBottomSheet({
[mapObjects]
);
const showDraftOverview = mode === "edit" && editorTool === "edit" && !selectedObject;
- const unmappedItemPreview = useMemo(
- () => visibleUnmappedItems.slice(0, 8),
- [visibleUnmappedItems]
- );
- const overflowUnmappedItemCount = visibleUnmappedItems.length - unmappedItemPreview.length;
const hiddenUnmappedItemCount = Math.max(0, unmappedItemCount - visibleUnmappedItems.length);
const hasHiddenUnmappedItems =
filters.showUnmapped && unmappedItemCount > 0 && visibleUnmappedItems.length === 0;
@@ -211,23 +201,7 @@ export default function LocationMapBottomSheet({
{layersOpen ? (
-
-
- {DISPLAY_CONTROLS.map(([key, label]) => (
-
- ))}
-
-
+
) : null}
{showSelectedObjectForm && primaryDraftActions ? (
@@ -249,128 +223,46 @@ export default function LocationMapBottomSheet({
) : null}
{showMapOverview ? (
-
-
- Areas
- {filters.showZones ? `${visibleAreaCount} shown` : "Hidden"}
-
-
- Mapped items
- {mappedItemSummary}
-
-
- Unmapped
- {unmappedItemSummary}
-
-
+
) : null}
{showDraftOverview ? (
-
-
- Areas
- {totalAreaCount}
-
-
- Hidden
- {hiddenAreaCount}
-
-
- Unlinked
- {unlinkedAreaCount}
-
-
+
) : null}
{mode === "edit" && editorTool === "edit" && selectedObject ? (
-
-
-
-
-
-
-
-
-
-
-
-
+
) : mode === "edit" ? (
null
) : selectedObject ? (
-
- {selectedZoneItems.length === 0 ? (
-
-
- {hasHiddenSelectedItems
- ? "Items are assigned here, but hidden by layer filters."
- : "No items assigned to this zone yet."}
-
- {hasHiddenSelectedItems ? (
-
- ) : null}
-
- ) : (
- <>
-
- {selectedZoneItems.map((item) => (
- -
- {item.item_name}
- x{item.quantity}
-
- ))}
-
- {hasHiddenSelectedItems ? (
-
-
- {hiddenSelectedItemCount} more hidden by layer filters.
-
-
-
- ) : null}
- >
- )}
-
+
) : null}
{showSelectedObjectForm && secondaryDraftActions ? (
@@ -383,45 +275,13 @@ export default function LocationMapBottomSheet({
) : null}
- {filters.showUnmapped && visibleUnmappedItems.length > 0 ? (
-
-
Unmapped Items
-
- {unmappedItemPreview.map((item) => (
- - {item.item_name}
- ))}
- {overflowUnmappedItemCount > 0 ? (
- -
- +{overflowUnmappedItemCount} more
-
- ) : null}
-
- {hiddenUnmappedItemCount > 0 ? (
-
-
- {hiddenUnmappedItemCount} more hidden by layer filters.
-
-
-
- ) : null}
-
- ) : hasHiddenUnmappedItems ? (
-
-
Unmapped Items
-
-
- Unmapped items are hidden by layer filters.
-
-
-
-
+ {filters.showUnmapped ? (
+
) : null}
);
diff --git a/frontend/src/components/maps/LocationMapBottomSheetSections.jsx b/frontend/src/components/maps/LocationMapBottomSheetSections.jsx
new file mode 100644
index 0000000..e300aa7
--- /dev/null
+++ b/frontend/src/components/maps/LocationMapBottomSheetSections.jsx
@@ -0,0 +1,218 @@
+import { objectZoneId } from "../../lib/locationMapUtils";
+
+export const MAP_DISPLAY_CONTROLS = [
+ ["showZones", "Zones"],
+ ["showLabels", "Labels"],
+ ["showCounts", "Counts"],
+ ["showPins", "Pins"],
+ ["showMyItems", "Mine"],
+ ["showOtherItems", "Others"],
+ ["showCompleted", "Bought"],
+ ["showUnmapped", "Unmapped"],
+];
+
+const UNMAPPED_PREVIEW_LIMIT = 8;
+
+export function LocationMapLayerPanel({ filters, setFilters }) {
+ return (
+
+
+ {MAP_DISPLAY_CONTROLS.map(([key, label]) => (
+
+ ))}
+
+
+ );
+}
+
+export function LocationMapOverview({ ariaLabel, rows }) {
+ return (
+
+ {rows.map((row) => (
+
+ {row.label}
+ {row.value}
+
+ ))}
+
+ );
+}
+
+export function SelectedMapObjectForm({
+ selectedObject,
+ zones = [],
+ saving,
+ onObjectField,
+ onZoneLinkChange,
+ onDuplicateObject,
+ onDeleteObject,
+}) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export function SelectedZoneItemsPanel({
+ selectedZoneItems,
+ hasHiddenSelectedItems,
+ hiddenSelectedItemCount,
+ onShowSelectedZoneItems,
+}) {
+ if (selectedZoneItems.length === 0) {
+ return (
+
+
+
+ {hasHiddenSelectedItems
+ ? "Items are assigned here, but hidden by layer filters."
+ : "No items assigned to this zone yet."}
+
+ {hasHiddenSelectedItems ? (
+
+ ) : null}
+
+
+ );
+ }
+
+ return (
+
+
+ {selectedZoneItems.map((item) => (
+ -
+ {item.item_name}
+ x{item.quantity}
+
+ ))}
+
+ {hasHiddenSelectedItems ? (
+
+
+ {hiddenSelectedItemCount} more hidden by layer filters.
+
+
+
+ ) : null}
+
+ );
+}
+
+export function UnmappedItemsPanel({
+ visibleUnmappedItems,
+ hiddenUnmappedItemCount,
+ hasHiddenUnmappedItems,
+ onShowUnmappedItems,
+}) {
+ if (visibleUnmappedItems.length === 0 && hasHiddenUnmappedItems) {
+ return (
+
+
Unmapped Items
+
+
+ Unmapped items are hidden by layer filters.
+
+
+
+
+ );
+ }
+
+ if (visibleUnmappedItems.length === 0) {
+ return null;
+ }
+
+ const unmappedItemPreview = visibleUnmappedItems.slice(0, UNMAPPED_PREVIEW_LIMIT);
+ const overflowUnmappedItemCount = visibleUnmappedItems.length - unmappedItemPreview.length;
+
+ return (
+
+
Unmapped Items
+
+ {unmappedItemPreview.map((item) => (
+ - {item.item_name}
+ ))}
+ {overflowUnmappedItemCount > 0 ? (
+ -
+ +{overflowUnmappedItemCount} more
+
+ ) : null}
+
+ {hiddenUnmappedItemCount > 0 ? (
+
+
+ {hiddenUnmappedItemCount} more hidden by layer filters.
+
+
+
+ ) : null}
+
+ );
+}