Add store location map manager #20
@ -2,22 +2,17 @@ import { useMemo } from "react";
|
|||||||
import {
|
import {
|
||||||
DEFAULT_MAP_FILTERS,
|
DEFAULT_MAP_FILTERS,
|
||||||
getMapObjectDisplayLabel,
|
getMapObjectDisplayLabel,
|
||||||
|
objectZoneId,
|
||||||
} from "../../lib/locationMapUtils";
|
} 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 = [];
|
const EMPTY_ITEMS = [];
|
||||||
|
|
||||||
export default function LocationMapBottomSheet({
|
export default function LocationMapBottomSheet({
|
||||||
@ -87,7 +82,7 @@ export default function LocationMapBottomSheet({
|
|||||||
const showEditorControls = mode === "edit" && canManage;
|
const showEditorControls = mode === "edit" && canManage;
|
||||||
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
|
const showSelectedObjectForm = Boolean(mode === "edit" && editorTool === "edit" && selectedObject);
|
||||||
const changedLayerCount = useMemo(
|
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]
|
[filters]
|
||||||
);
|
);
|
||||||
const totalAreaCount = mapObjects.length;
|
const totalAreaCount = mapObjects.length;
|
||||||
@ -102,11 +97,6 @@ export default function LocationMapBottomSheet({
|
|||||||
[mapObjects]
|
[mapObjects]
|
||||||
);
|
);
|
||||||
const showDraftOverview = mode === "edit" && editorTool === "edit" && !selectedObject;
|
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 hiddenUnmappedItemCount = Math.max(0, unmappedItemCount - visibleUnmappedItems.length);
|
||||||
const hasHiddenUnmappedItems =
|
const hasHiddenUnmappedItems =
|
||||||
filters.showUnmapped && unmappedItemCount > 0 && visibleUnmappedItems.length === 0;
|
filters.showUnmapped && unmappedItemCount > 0 && visibleUnmappedItems.length === 0;
|
||||||
@ -211,23 +201,7 @@ export default function LocationMapBottomSheet({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{layersOpen ? (
|
{layersOpen ? (
|
||||||
<div className="location-map-display-panel">
|
<LocationMapLayerPanel filters={filters} setFilters={setFilters} />
|
||||||
<div className="location-map-display-controls">
|
|
||||||
{DISPLAY_CONTROLS.map(([key, label]) => (
|
|
||||||
<button
|
|
||||||
key={key}
|
|
||||||
type="button"
|
|
||||||
className={filters[key] ? "active" : ""}
|
|
||||||
aria-pressed={filters[key]}
|
|
||||||
onClick={() =>
|
|
||||||
setFilters((current) => ({ ...current, [key]: !current[key] }))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{showSelectedObjectForm && primaryDraftActions ? (
|
{showSelectedObjectForm && primaryDraftActions ? (
|
||||||
@ -249,128 +223,46 @@ export default function LocationMapBottomSheet({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{showMapOverview ? (
|
{showMapOverview ? (
|
||||||
<div className="location-map-overview" aria-label="Map summary">
|
<LocationMapOverview
|
||||||
<div className="location-map-overview-row">
|
ariaLabel="Map summary"
|
||||||
<span>Areas</span>
|
rows={[
|
||||||
<strong>{filters.showZones ? `${visibleAreaCount} shown` : "Hidden"}</strong>
|
{ label: "Areas", value: filters.showZones ? `${visibleAreaCount} shown` : "Hidden" },
|
||||||
</div>
|
{ label: "Mapped items", value: mappedItemSummary },
|
||||||
<div className="location-map-overview-row">
|
{ label: "Unmapped", value: unmappedItemSummary },
|
||||||
<span>Mapped items</span>
|
]}
|
||||||
<strong>{mappedItemSummary}</strong>
|
/>
|
||||||
</div>
|
|
||||||
<div className="location-map-overview-row">
|
|
||||||
<span>Unmapped</span>
|
|
||||||
<strong>{unmappedItemSummary}</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{showDraftOverview ? (
|
{showDraftOverview ? (
|
||||||
<div className="location-map-overview" aria-label="Draft map summary">
|
<LocationMapOverview
|
||||||
<div className="location-map-overview-row">
|
ariaLabel="Draft map summary"
|
||||||
<span>Areas</span>
|
rows={[
|
||||||
<strong>{totalAreaCount}</strong>
|
{ label: "Areas", value: totalAreaCount },
|
||||||
</div>
|
{ label: "Hidden", value: hiddenAreaCount },
|
||||||
<div className="location-map-overview-row">
|
{ label: "Unlinked", value: unlinkedAreaCount },
|
||||||
<span>Hidden</span>
|
]}
|
||||||
<strong>{hiddenAreaCount}</strong>
|
/>
|
||||||
</div>
|
|
||||||
<div className="location-map-overview-row">
|
|
||||||
<span>Unlinked</span>
|
|
||||||
<strong>{unlinkedAreaCount}</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{mode === "edit" && editorTool === "edit" && selectedObject ? (
|
{mode === "edit" && editorTool === "edit" && selectedObject ? (
|
||||||
<div className="location-map-object-form">
|
<SelectedMapObjectForm
|
||||||
<label className="location-map-field-row">
|
selectedObject={selectedObject}
|
||||||
<span>Label</span>
|
zones={mapState?.zones || EMPTY_ITEMS}
|
||||||
<input
|
saving={saving}
|
||||||
value={selectedObject.label || ""}
|
onObjectField={onObjectField}
|
||||||
disabled={saving}
|
onZoneLinkChange={onZoneLinkChange}
|
||||||
onChange={(event) => onObjectField("label", event.target.value)}
|
onDuplicateObject={onDuplicateObject}
|
||||||
|
onDeleteObject={onDeleteObject}
|
||||||
/>
|
/>
|
||||||
</label>
|
|
||||||
<label className="location-map-field-row">
|
|
||||||
<span>Zone</span>
|
|
||||||
<select
|
|
||||||
aria-label="Linked zone"
|
|
||||||
value={objectZoneId(selectedObject)}
|
|
||||||
disabled={saving}
|
|
||||||
onChange={(event) => onZoneLinkChange(event.target.value)}
|
|
||||||
>
|
|
||||||
<option value="">No linked zone</option>
|
|
||||||
{(mapState?.zones || []).map((zone) => (
|
|
||||||
<option key={zone.id} value={zone.id}>{zone.name}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<div className="location-map-object-flags">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={selectedObject.visible !== false ? "active" : ""}
|
|
||||||
aria-pressed={selectedObject.visible !== false}
|
|
||||||
disabled={saving}
|
|
||||||
onClick={() => onObjectField("visible", selectedObject.visible === false)}
|
|
||||||
>
|
|
||||||
Visible
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={selectedObject.locked ? "active" : ""}
|
|
||||||
aria-pressed={Boolean(selectedObject.locked)}
|
|
||||||
disabled={saving}
|
|
||||||
onClick={() => onObjectField("locked", !selectedObject.locked)}
|
|
||||||
>
|
|
||||||
Locked
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="location-map-editor-actions">
|
|
||||||
<button type="button" onClick={onDuplicateObject} disabled={saving}>Duplicate</button>
|
|
||||||
<button type="button" className="danger" onClick={onDeleteObject} disabled={saving}>Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : mode === "edit" ? (
|
) : mode === "edit" ? (
|
||||||
null
|
null
|
||||||
) : selectedObject ? (
|
) : selectedObject ? (
|
||||||
<div className="location-map-zone-items">
|
<SelectedZoneItemsPanel
|
||||||
{selectedZoneItems.length === 0 ? (
|
selectedZoneItems={selectedZoneItems}
|
||||||
<div className="location-map-zone-empty">
|
hasHiddenSelectedItems={hasHiddenSelectedItems}
|
||||||
<p className="location-map-muted">
|
hiddenSelectedItemCount={hiddenSelectedItemCount}
|
||||||
{hasHiddenSelectedItems
|
onShowSelectedZoneItems={showSelectedZoneItems}
|
||||||
? "Items are assigned here, but hidden by layer filters."
|
/>
|
||||||
: "No items assigned to this zone yet."}
|
|
||||||
</p>
|
|
||||||
{hasHiddenSelectedItems ? (
|
|
||||||
<button type="button" onClick={showSelectedZoneItems}>
|
|
||||||
Show Zone Items
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<ul>
|
|
||||||
{selectedZoneItems.map((item) => (
|
|
||||||
<li key={item.id}>
|
|
||||||
<span>{item.item_name}</span>
|
|
||||||
<small>x{item.quantity}</small>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
{hasHiddenSelectedItems ? (
|
|
||||||
<div className="location-map-zone-hidden-note">
|
|
||||||
<p className="location-map-muted">
|
|
||||||
{hiddenSelectedItemCount} more hidden by layer filters.
|
|
||||||
</p>
|
|
||||||
<button type="button" onClick={showSelectedZoneItems}>
|
|
||||||
Show All Zone Items
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{showSelectedObjectForm && secondaryDraftActions ? (
|
{showSelectedObjectForm && secondaryDraftActions ? (
|
||||||
@ -383,45 +275,13 @@ export default function LocationMapBottomSheet({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{filters.showUnmapped && visibleUnmappedItems.length > 0 ? (
|
{filters.showUnmapped ? (
|
||||||
<div className="location-map-unmapped-list">
|
<UnmappedItemsPanel
|
||||||
<strong>Unmapped Items</strong>
|
visibleUnmappedItems={visibleUnmappedItems}
|
||||||
<ul>
|
hiddenUnmappedItemCount={hiddenUnmappedItemCount}
|
||||||
{unmappedItemPreview.map((item) => (
|
hasHiddenUnmappedItems={hasHiddenUnmappedItems}
|
||||||
<li key={item.id}>{item.item_name}</li>
|
onShowUnmappedItems={showUnmappedItems}
|
||||||
))}
|
/>
|
||||||
{overflowUnmappedItemCount > 0 ? (
|
|
||||||
<li
|
|
||||||
className="location-map-unmapped-more"
|
|
||||||
aria-label={`${overflowUnmappedItemCount} more unmapped items`}
|
|
||||||
>
|
|
||||||
+{overflowUnmappedItemCount} more
|
|
||||||
</li>
|
|
||||||
) : null}
|
|
||||||
</ul>
|
|
||||||
{hiddenUnmappedItemCount > 0 ? (
|
|
||||||
<div className="location-map-zone-hidden-note">
|
|
||||||
<p className="location-map-muted">
|
|
||||||
{hiddenUnmappedItemCount} more hidden by layer filters.
|
|
||||||
</p>
|
|
||||||
<button type="button" onClick={showUnmappedItems}>
|
|
||||||
Show All Unmapped Items
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : hasHiddenUnmappedItems ? (
|
|
||||||
<div className="location-map-unmapped-list">
|
|
||||||
<strong>Unmapped Items</strong>
|
|
||||||
<div className="location-map-zone-empty">
|
|
||||||
<p className="location-map-muted">
|
|
||||||
Unmapped items are hidden by layer filters.
|
|
||||||
</p>
|
|
||||||
<button type="button" onClick={showUnmappedItems}>
|
|
||||||
Show Unmapped Items
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|||||||
218
frontend/src/components/maps/LocationMapBottomSheetSections.jsx
Normal file
218
frontend/src/components/maps/LocationMapBottomSheetSections.jsx
Normal file
@ -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 (
|
||||||
|
<div className="location-map-display-panel">
|
||||||
|
<div className="location-map-display-controls">
|
||||||
|
{MAP_DISPLAY_CONTROLS.map(([key, label]) => (
|
||||||
|
<button
|
||||||
|
key={key}
|
||||||
|
type="button"
|
||||||
|
className={filters[key] ? "active" : ""}
|
||||||
|
aria-pressed={filters[key]}
|
||||||
|
onClick={() =>
|
||||||
|
setFilters((current) => ({ ...current, [key]: !current[key] }))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LocationMapOverview({ ariaLabel, rows }) {
|
||||||
|
return (
|
||||||
|
<div className="location-map-overview" aria-label={ariaLabel}>
|
||||||
|
{rows.map((row) => (
|
||||||
|
<div className="location-map-overview-row" key={row.label}>
|
||||||
|
<span>{row.label}</span>
|
||||||
|
<strong>{row.value}</strong>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectedMapObjectForm({
|
||||||
|
selectedObject,
|
||||||
|
zones = [],
|
||||||
|
saving,
|
||||||
|
onObjectField,
|
||||||
|
onZoneLinkChange,
|
||||||
|
onDuplicateObject,
|
||||||
|
onDeleteObject,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="location-map-object-form">
|
||||||
|
<label className="location-map-field-row">
|
||||||
|
<span>Label</span>
|
||||||
|
<input
|
||||||
|
value={selectedObject.label || ""}
|
||||||
|
disabled={saving}
|
||||||
|
onChange={(event) => onObjectField("label", event.target.value)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<label className="location-map-field-row">
|
||||||
|
<span>Zone</span>
|
||||||
|
<select
|
||||||
|
aria-label="Linked zone"
|
||||||
|
value={objectZoneId(selectedObject)}
|
||||||
|
disabled={saving}
|
||||||
|
onChange={(event) => onZoneLinkChange(event.target.value)}
|
||||||
|
>
|
||||||
|
<option value="">No linked zone</option>
|
||||||
|
{zones.map((zone) => (
|
||||||
|
<option key={zone.id} value={zone.id}>{zone.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<div className="location-map-object-flags">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={selectedObject.visible !== false ? "active" : ""}
|
||||||
|
aria-pressed={selectedObject.visible !== false}
|
||||||
|
disabled={saving}
|
||||||
|
onClick={() => onObjectField("visible", selectedObject.visible === false)}
|
||||||
|
>
|
||||||
|
Visible
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={selectedObject.locked ? "active" : ""}
|
||||||
|
aria-pressed={Boolean(selectedObject.locked)}
|
||||||
|
disabled={saving}
|
||||||
|
onClick={() => onObjectField("locked", !selectedObject.locked)}
|
||||||
|
>
|
||||||
|
Locked
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="location-map-editor-actions">
|
||||||
|
<button type="button" onClick={onDuplicateObject} disabled={saving}>Duplicate</button>
|
||||||
|
<button type="button" className="danger" onClick={onDeleteObject} disabled={saving}>Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectedZoneItemsPanel({
|
||||||
|
selectedZoneItems,
|
||||||
|
hasHiddenSelectedItems,
|
||||||
|
hiddenSelectedItemCount,
|
||||||
|
onShowSelectedZoneItems,
|
||||||
|
}) {
|
||||||
|
if (selectedZoneItems.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="location-map-zone-items">
|
||||||
|
<div className="location-map-zone-empty">
|
||||||
|
<p className="location-map-muted">
|
||||||
|
{hasHiddenSelectedItems
|
||||||
|
? "Items are assigned here, but hidden by layer filters."
|
||||||
|
: "No items assigned to this zone yet."}
|
||||||
|
</p>
|
||||||
|
{hasHiddenSelectedItems ? (
|
||||||
|
<button type="button" onClick={onShowSelectedZoneItems}>
|
||||||
|
Show Zone Items
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="location-map-zone-items">
|
||||||
|
<ul>
|
||||||
|
{selectedZoneItems.map((item) => (
|
||||||
|
<li key={item.id}>
|
||||||
|
<span>{item.item_name}</span>
|
||||||
|
<small>x{item.quantity}</small>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
{hasHiddenSelectedItems ? (
|
||||||
|
<div className="location-map-zone-hidden-note">
|
||||||
|
<p className="location-map-muted">
|
||||||
|
{hiddenSelectedItemCount} more hidden by layer filters.
|
||||||
|
</p>
|
||||||
|
<button type="button" onClick={onShowSelectedZoneItems}>
|
||||||
|
Show All Zone Items
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UnmappedItemsPanel({
|
||||||
|
visibleUnmappedItems,
|
||||||
|
hiddenUnmappedItemCount,
|
||||||
|
hasHiddenUnmappedItems,
|
||||||
|
onShowUnmappedItems,
|
||||||
|
}) {
|
||||||
|
if (visibleUnmappedItems.length === 0 && hasHiddenUnmappedItems) {
|
||||||
|
return (
|
||||||
|
<div className="location-map-unmapped-list">
|
||||||
|
<strong>Unmapped Items</strong>
|
||||||
|
<div className="location-map-zone-empty">
|
||||||
|
<p className="location-map-muted">
|
||||||
|
Unmapped items are hidden by layer filters.
|
||||||
|
</p>
|
||||||
|
<button type="button" onClick={onShowUnmappedItems}>
|
||||||
|
Show Unmapped Items
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visibleUnmappedItems.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unmappedItemPreview = visibleUnmappedItems.slice(0, UNMAPPED_PREVIEW_LIMIT);
|
||||||
|
const overflowUnmappedItemCount = visibleUnmappedItems.length - unmappedItemPreview.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="location-map-unmapped-list">
|
||||||
|
<strong>Unmapped Items</strong>
|
||||||
|
<ul>
|
||||||
|
{unmappedItemPreview.map((item) => (
|
||||||
|
<li key={item.id}>{item.item_name}</li>
|
||||||
|
))}
|
||||||
|
{overflowUnmappedItemCount > 0 ? (
|
||||||
|
<li
|
||||||
|
className="location-map-unmapped-more"
|
||||||
|
aria-label={`${overflowUnmappedItemCount} more unmapped items`}
|
||||||
|
>
|
||||||
|
+{overflowUnmappedItemCount} more
|
||||||
|
</li>
|
||||||
|
) : null}
|
||||||
|
</ul>
|
||||||
|
{hiddenUnmappedItemCount > 0 ? (
|
||||||
|
<div className="location-map-zone-hidden-note">
|
||||||
|
<p className="location-map-muted">
|
||||||
|
{hiddenUnmappedItemCount} more hidden by layer filters.
|
||||||
|
</p>
|
||||||
|
<button type="button" onClick={onShowUnmappedItems}>
|
||||||
|
Show All Unmapped Items
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user