Skip to content

Commit e6427af

Browse files
committed
feat(map): merge אזור הרס variants and align pack chip counts with merged tiles
- Treat אזור_הרס-אזור / אזור_הרס-נקודה as one October 7 family with curated label - Pack chip total and active n use virtual tile rows (buildLayerTileRows); family counts as one when all members on
1 parent 10abedf commit e6427af

5 files changed

Lines changed: 59 additions & 10 deletions

File tree

src/map/layers/layerDisplayGlossary.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ export type October7thMergedFamilyKey =
2121
| "מאבק_וגבורה"
2222
| "פגיעה_נקודתית"
2323
| "ביזה"
24+
| "אזור_הרס"
2425
| `אירוע_נקודתי-${string}`;
2526

2627
const OCTOBER_MERGED_FAMILY_LABEL: Partial<Record<string, string>> = {
2728
חדירה_לישוב: "חדירה לישוב",
2829
מאבק_וגבורה: "מאבק וגבורה",
2930
פגיעה_נקודתית: "פגיעה נקודתית",
3031
ביזה: "ביזה",
32+
אזור_הרס: "אזור הרס",
3133
"אירוע_נקודתי-רציחה_חטיפה": "אירוע נקודתי — רציחה וחטיפה",
3234
};
3335

src/map/layers/layerNameUtils.test.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import type { LayerManifestEntry } from "./types";
33
import {
44
buildLayerTileRows,
55
buildOctober7thActiveLegendRows,
6+
countMergedPackFullyActiveTileRows,
7+
countMergedPackTileRows,
68
october7thMergedFamilyKeyFromLayerId,
79
packLayerKey,
810
parsePackLayerKey,
@@ -39,9 +41,9 @@ describe("october7thMergedFamilyKeyFromLayerId", () => {
3941
expect(october7thMergedFamilyKeyFromLayerId("אירוע_נקודתי-רציחה_חטיפה")).toBe("אירוע_נקודתי-רציחה_חטיפה");
4042
});
4143

42-
it("does not merge אזור_הרס geometry variants (excluded from merged families until glossary adds a family key)", () => {
43-
expect(october7thMergedFamilyKeyFromLayerId("אזור_הרס-אזור")).toBeNull();
44-
expect(october7thMergedFamilyKeyFromLayerId("אזור_הרס-נקודה")).toBeNull();
44+
it("merges אזור_הרס geometry variants into one family", () => {
45+
expect(october7thMergedFamilyKeyFromLayerId("אזור_הרס-אזור")).toBe("אזור_הרס");
46+
expect(october7thMergedFamilyKeyFromLayerId("אזור_הרס-נקודה")).toBe("אזור_הרס");
4547
});
4648
});
4749

@@ -184,6 +186,27 @@ describe("buildOctober7thActiveLegendRows", () => {
184186
});
185187
});
186188

189+
describe("countMergedPackTileRows / countMergedPackFullyActiveTileRows", () => {
190+
it("counts october merged families as one virtual row each", () => {
191+
const layers = [layer("ביזה-אזור"), layer("ביזה-נקודה"), layer("solo")];
192+
expect(countMergedPackTileRows("october_7th", layers)).toBe(2);
193+
const key = (id: string) => packLayerKey("october_7th", id);
194+
const onBoth = { [key("ביזה-אזור")]: true, [key("ביזה-נקודה")]: true, [key("solo")]: false };
195+
expect(countMergedPackFullyActiveTileRows("october_7th", layers, onBoth)).toBe(1);
196+
const onPartial = { [key("ביזה-אזור")]: true, [key("ביזה-נקודה")]: false, [key("solo")]: true };
197+
expect(countMergedPackFullyActiveTileRows("october_7th", layers, onPartial)).toBe(1);
198+
const onAll = { [key("ביזה-אזור")]: true, [key("ביזה-נקודה")]: true, [key("solo")]: true };
199+
expect(countMergedPackFullyActiveTileRows("october_7th", layers, onAll)).toBe(2);
200+
});
201+
202+
it("matches raw layer count for non-october packs", () => {
203+
const layers = [layer("a"), layer("b")];
204+
expect(countMergedPackTileRows("greens", layers)).toBe(2);
205+
const m = { [packLayerKey("greens", "a")]: true, [packLayerKey("greens", "b")]: false };
206+
expect(countMergedPackFullyActiveTileRows("greens", layers, m)).toBe(1);
207+
});
208+
});
209+
187210
describe("pickOctober7thFamilyLayerForSwatch", () => {
188211
it("prefers point over line over polygon, then manifest order", () => {
189212
const manifest: LayerManifestEntry[] = [

src/map/layers/layerNameUtils.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,13 @@ function stripOctober7GeometrySuffix(layerId: string): string {
111111
/**
112112
* Maps a concrete layer id to its merged display family when it belongs to a
113113
* geometry-variant group (October 7 pack only).
114-
*
115-
* Intentional exclusions: some layers share a `-אזור` / `-נקודה` (or similar) pattern but are
116-
* not merged — for example `אזור_הרס-אזור` and `אזור_הרס-נקודה` stay separate rows until a
117-
* dedicated `אזור_הרס` family key and curated label are added to the product glossary.
118114
*/
119115
export function october7thMergedFamilyKeyFromLayerId(layerId: string): October7thMergedFamilyKey | null {
120116
if (layerId.startsWith("חדירה_לישוב")) return "חדירה_לישוב";
121117
if (layerId.startsWith("מאבק_וגבורה")) return "מאבק_וגבורה";
122118
if (layerId.startsWith("פגיעה_נקודתית")) return "פגיעה_נקודתית";
123119
if (layerId.startsWith("ביזה-")) return "ביזה";
120+
if (layerId.startsWith("אזור_הרס-")) return "אזור_הרס";
124121
if (layerId.startsWith("אירוע_נקודתי-")) {
125122
return stripOctober7GeometrySuffix(layerId) as October7thMergedFamilyKey;
126123
}
@@ -212,3 +209,29 @@ export function buildOctober7thActiveLegendRows(
212209
}
213210
return rows;
214211
}
212+
213+
/** Virtual tile rows for pack UI (October 7 merges geometry-variant families into one row each). */
214+
export function countMergedPackTileRows(packId: string, layers: LayerManifestEntry[]): number {
215+
return buildLayerTileRows(packId, layers).length;
216+
}
217+
218+
/**
219+
* How many of those virtual rows are fully on (single layer on, or merged family with every member on).
220+
* Matches chip `n` when `total` is `countMergedPackTileRows` for the same pack.
221+
*/
222+
export function countMergedPackFullyActiveTileRows(
223+
packId: string,
224+
layers: LayerManifestEntry[],
225+
layerOnByKey: Record<string, boolean>,
226+
): number {
227+
const isOn = (layerId: string) => layerOnByKey[packLayerKey(packId, layerId)] === true;
228+
let n = 0;
229+
for (const row of buildLayerTileRows(packId, layers)) {
230+
if (row.kind === "layer") {
231+
if (isOn(row.layer.id)) n += 1;
232+
} else if (row.members.length > 0 && row.members.every((m) => isOn(m.id))) {
233+
n += 1;
234+
}
235+
}
236+
return n;
237+
}

src/pages/MapPage/LayerPackChipsScroller.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { countMergedPackTileRows } from "../../map/layers/layerNameUtils";
12
import type { LayerRegistry } from "../../map/layers/types";
23

34
type Props = {
@@ -23,7 +24,7 @@ export default function LayerPackChipsScroller({
2324

2425
const renderChip = (p: (typeof packs)[0]) => {
2526
const n = activeCountForPack(p.id);
26-
const total = p.manifest.layers.length;
27+
const total = countMergedPackTileRows(p.id, p.manifest.layers);
2728
const focused = p.id === focusedPackId;
2829
return (
2930
<div key={p.id} className="layer-packs-sheet-pack-chip">

src/pages/MapPage/useLayerPackState.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useCallback, useEffect, useMemo, useState } from "react";
2-
import { packLayerKey } from "../../map/layers/layerNameUtils";
2+
import { countMergedPackFullyActiveTileRows, packLayerKey } from "../../map/layers/layerNameUtils";
33
import type { LayerRegistry } from "../../map/layers/types";
44

55
const FUTURE_DEV_PARKING_LAYER_KEY = packLayerKey("future_development", "חניה");
@@ -156,7 +156,7 @@ export function useLayerPackState(registry: LayerRegistry | null) {
156156
if (!registry) return 0;
157157
const pack = registry.packs.find((p) => p.id === packId);
158158
if (!pack) return 0;
159-
return pack.manifest.layers.filter((l) => layerOnByKey[getLayerKey(packId, l.id)]).length;
159+
return countMergedPackFullyActiveTileRows(packId, pack.manifest.layers, layerOnByKey);
160160
},
161161
[registry, layerOnByKey]
162162
);

0 commit comments

Comments
 (0)