Skip to content

Commit

Permalink
refactor(map): rework map state & map-related features
Browse files Browse the repository at this point in the history
  • Loading branch information
jahow committed Sep 15, 2024
1 parent c58b59c commit cd6bbdb
Show file tree
Hide file tree
Showing 33 changed files with 420 additions and 1,199 deletions.
9 changes: 1 addition & 8 deletions libs/feature/map/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
export * from './lib/+state/map.facade'
export * from './lib/+state/map.models'
export * from './lib/+state/map.selectors'
export * from './lib/+state/map.reducer'
export * from './lib/+state/map.actions'
export * from './lib/feature-map.module'
export * from './lib/manager/map-manager.service'
export * from './lib/manager/map-instance.directive'
export * from './lib/feature-info/feature-info.service'
export * from './lib/map-context/map-context.model'
export * from './lib/map-context/map-context.service'
export * from './lib/map-context/component/map-context.component'
export * from './lib/map-state-container/map-state-container.component'
export * from './lib/constant'
export * from './lib/utils'
export * from './lib/style'
export * from './lib/layers-panel/layers-panel.component'
export * from './lib/add-layer-from-catalog/add-layer-from-catalog.component'
export * from './lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component'
export * from './lib/map-container/map-container.component'
export * from './lib/geocoding/geocoding.component'
35 changes: 10 additions & 25 deletions libs/feature/map/src/lib/+state/map.actions.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,17 @@
import { createAction, props } from '@ngrx/store'
import { MapLayer } from './map.models'
import { MapContext } from '@geospatial-sdk/core'
import type { Feature } from 'geojson'

export const addLayer = createAction(
'[Map] Add Layer',
props<{ layer: MapLayer; atIndex?: number }>()
export const setContext = createAction(
'[Map] Set Context',
props<{ context: MapContext }>()
)

export const removeLayer = createAction(
'[Map] Remove Layer',
props<{ index: number }>()
export const setSelectedFeatures = createAction(
'[Map] Set Selected Features',
props<{ selectedFeatures: Feature[] }>()
)

export const updateLayer = createAction(
'[Map] Update Layer',
props<{ updatedLayer: MapLayer; index: number }>()
)

export const changeLayerOrder = createAction(
'[Map] Change Layer Order',
props<{ currentIndex: number; newIndex: number }>()
)

export const setLayerError = createAction(
'[Map] Set Layer Error',
props<{ index: number; error: string }>()
)

export const clearLayerError = createAction(
'[Map] Clear Layer Error',
props<{ index: number }>()
export const clearSelectedFeatures = createAction(
'[Map] Clear Selected Features'
)
27 changes: 0 additions & 27 deletions libs/feature/map/src/lib/+state/map.effects.spec.ts

This file was deleted.

7 changes: 0 additions & 7 deletions libs/feature/map/src/lib/+state/map.effects.ts

This file was deleted.

43 changes: 13 additions & 30 deletions libs/feature/map/src/lib/+state/map.facade.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { NgModule } from '@angular/core'
import { TestBed } from '@angular/core/testing'
import { EffectsModule } from '@ngrx/effects'
import { Store, StoreModule } from '@ngrx/store'
import { readFirst } from '@nx/angular/testing'
import { MapEffects } from './map.effects'
import { MapFacade } from './map.facade'
import * as MapActions from './map.actions'
import { MAP_FEATURE_KEY, mapReducer, MapState } from './map.reducer'
import { mapCtxLayerWmsFixture } from '../map-context/map-context.fixtures'
import { mapCtxLayerWmsFixture } from '@geonetwork-ui/common/fixtures'

interface TestSchema {
map: MapState
Expand All @@ -19,10 +18,7 @@ describe('MapFacade', () => {
describe('used in NgModule', () => {
beforeEach(() => {
@NgModule({
imports: [
StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
EffectsModule.forFeature([MapEffects]),
],
imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)],
providers: [MapFacade],
})
class CustomFeatureModule {}
Expand All @@ -41,31 +37,18 @@ describe('MapFacade', () => {
facade = TestBed.inject(MapFacade)
})

describe('layers$ / addLayer / addLayerAtIndex', () => {
it('emits the list of layers after each change', async () => {
let list = await readFirst(facade.layers$)
expect(list.length).toBe(0)

facade.addLayer({
...mapCtxLayerWmsFixture(),
title: 'world',
})

list = await readFirst(facade.layers$)
expect(list.length).toBe(1)
expect(list.map((l) => l.title)).toEqual(['world'])
describe('setContext', () => {
it('dispatches a setContext action', async () => {
const spy = jest.spyOn(store, 'dispatch')
const context = {
layers: [mapCtxLayerWmsFixture()],
view: null,
}

facade.addLayerAtIndex(
{
...mapCtxLayerWmsFixture(),
title: 'hello',
},
0
)
facade.applyContext(context)

list = await readFirst(facade.layers$)
expect(list.length).toBe(2)
expect(list.map((l) => l.title)).toEqual(['hello', 'world'])
const action = MapActions.setContext({ context })
expect(spy).toHaveBeenCalledWith(action)
})
})
})
Expand Down
26 changes: 11 additions & 15 deletions libs/feature/map/src/lib/+state/map.facade.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
import { Injectable } from '@angular/core'
import { select, Store } from '@ngrx/store'
import * as MapSelectors from './map.selectors'
import { MapLayer } from './map.models'
import * as MapActions from './map.actions'
import { MapContext } from '@geospatial-sdk/core'
import { Feature } from 'geojson'

@Injectable()
export class MapFacade {
layers$ = this.store.pipe(select(MapSelectors.getMapLayers))
context$ = this.store.pipe(select(MapSelectors.getMapContext))
selectedFeatures$ = this.store.pipe(select(MapSelectors.getSelectedFeatures))

constructor(private readonly store: Store) {}

/**
* Use the initialization action to perform one
* or more tasks in your Effects.
*/
init() {
// placeholder
applyContext(context: MapContext) {
this.store.dispatch(MapActions.setContext({ context }))
}

addLayer(layer: MapLayer) {
this.store.dispatch(MapActions.addLayer({ layer }))
selectFeatures(selectedFeatures: Feature[]) {
this.store.dispatch(MapActions.setSelectedFeatures({ selectedFeatures }))
}
addLayerAtIndex(layer: MapLayer, index: number) {
this.store.dispatch(MapActions.addLayer({ layer, atIndex: index }))
}
removeLayer(index: number) {
this.store.dispatch(MapActions.removeLayer({ index }))

clearFeatureSelection() {
this.store.dispatch(MapActions.clearSelectedFeatures())
}
}
9 changes: 0 additions & 9 deletions libs/feature/map/src/lib/+state/map.models.ts

This file was deleted.

124 changes: 15 additions & 109 deletions libs/feature/map/src/lib/+state/map.reducer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Action } from '@ngrx/store'

import * as MapActions from './map.actions'
import { initialMapState, mapReducer, MapState } from './map.reducer'
import { mapCtxLayerWmsFixture } from '../map-context/map-context.fixtures'
import { MapLayerWithInfo } from './map.models'
import { MapContextLayer } from '@geospatial-sdk/core'
import { mapCtxLayerWmsFixture } from '@geonetwork-ui/common/fixtures'

function getSampleLayer(title: string): MapLayerWithInfo {
return { ...mapCtxLayerWmsFixture(), loading: false, error: null, title }
function getSampleLayer(label: string): MapContextLayer {
return { ...mapCtxLayerWmsFixture(), label }
}

describe('Map Reducer', () => {
Expand All @@ -15,119 +13,27 @@ describe('Map Reducer', () => {
beforeEach(() => {
initialState = {
...initialMapState,
layers: [
getSampleLayer('first'),
getSampleLayer('second'),
getSampleLayer('third'),
],
}
})

describe('addLayer', () => {
describe('setContext', () => {
it('should add a layer at the end of the list if no index specified', () => {
const action = MapActions.addLayer({ layer: getSampleLayer('test') })
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual([
'first',
'second',
'third',
'test',
])
})
it('should add a layer at a specific index if specified', () => {
const action = MapActions.addLayer({
layer: getSampleLayer('test'),
atIndex: 0,
})
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual([
'test',
'first',
'second',
'third',
])
})
})

describe('removeLayer', () => {
it('should remove a layer at the specified index', () => {
const action = MapActions.removeLayer({ index: 2 })
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual(['first', 'second'])
})
})

describe('updateLayer', () => {
it('should update a layer at the specified index', () => {
const action = MapActions.updateLayer({
updatedLayer: getSampleLayer('updated'),
index: 1,
const action = MapActions.setContext({
context: {
...initialMapState.context,
layers: [
getSampleLayer('first'),
getSampleLayer('second'),
getSampleLayer('third'),
],
},
})
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual([
expect(result.context.layers.map((l) => l.label)).toEqual([
'first',
'updated',
'third',
])
})
})

describe('changeLayerOrder', () => {
it('should reorder the array of layers (current index > new index)', () => {
const action = MapActions.changeLayerOrder({
currentIndex: 1,
newIndex: 0,
})
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual([
'second',
'first',
'third',
])
})
it('should reorder the array of layers (current index < new index)', () => {
const action = MapActions.changeLayerOrder({
currentIndex: 1,
newIndex: 2,
})
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.title)).toEqual([
'first',
'third',
'second',
])
})
})

describe('setLayerError', () => {
it('should set the error on a layer', () => {
const action = MapActions.setLayerError({
index: 2,
error: 'something went wrong',
})
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.error)).toEqual([
null,
null,
'something went wrong',
])
})
})

describe('clearLayerError', () => {
it('should clear the error on a layer', () => {
initialState.layers[1].error = 'oopsie'
const action = MapActions.clearLayerError({ index: 1 })
const result: MapState = mapReducer(initialState, action)
expect(result.layers.map((l) => l.error)).toEqual([null, null, null])
})
})

describe('unknown action', () => {
it('should return the previous state', () => {
const action = {} as Action
const result = mapReducer(initialState, action)
expect(result).toBe(initialState)
})
})
})
Loading

0 comments on commit cd6bbdb

Please sign in to comment.