import Combine from "../Base/Combine" import { FlowStep } from "./FlowStep" import { BBox } from "../../Logic/BBox" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { Store, UIEventSource } from "../../Logic/UIEventSource" import CreateNoteImportLayer from "../../Models/ThemeConfig/Conversion/CreateNoteImportLayer" import FilteredLayer, { FilterState } from "../../Models/FilteredLayer" import GeoJsonSource from "../../Logic/FeatureSource/Sources/GeoJsonSource" import MetaTagging from "../../Logic/MetaTagging" import RelationsTracker from "../../Logic/Osm/RelationsTracker" import FilteringFeatureSource from "../../Logic/FeatureSource/Sources/FilteringFeatureSource" import Minimap from "../Base/Minimap" import ShowDataLayer from "../ShowDataLayer/ShowDataLayer" import FeatureInfoBox from "../Popup/FeatureInfoBox" import { ImportUtils } from "./ImportUtils" import import_candidate from "../../assets/layers/import_candidate/import_candidate.json" import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" import Title from "../Base/Title" import Loading from "../Base/Loading" import { VariableUiElement } from "../Base/VariableUIElement" import known_layers from "../../assets/generated/known_layers.json" import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import Translations from "../i18n/Translations" import { Feature } from "geojson" import DivContainer from "../Base/DivContainer" /** * Filters out points for which the import-note already exists, to prevent duplicates */ export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{ bbox: BBox; layer: LayerConfig; features: any[]; theme: string }> { public IsValid: Store public Value: Store<{ bbox: BBox; layer: LayerConfig; features: any[]; theme: string }> constructor(state, params: { bbox: BBox; layer: LayerConfig; features: any[]; theme: string }) { const t = Translations.t.importHelper.compareToAlreadyExistingNotes const layerConfig = known_layers.layers.filter((l) => l.id === params.layer.id)[0] if (layerConfig === undefined) { console.error("WEIRD: layer not found in the builtin layer overview") } const importLayerJson = new CreateNoteImportLayer(150).convertStrict( layerConfig, "CompareToAlreadyExistingNotes" ) const importLayer = new LayerConfig(importLayerJson, "import-layer-dynamic") const flayer: FilteredLayer = { appliedFilters: new UIEventSource>( new Map() ), isDisplayed: new UIEventSource(true), layerDef: importLayer, } const allNotesWithinBbox = new GeoJsonSource(flayer, params.bbox.padAbsolute(0.0001)) allNotesWithinBbox.features.map((f) => MetaTagging.addMetatags( f, { memberships: new RelationsTracker(), getFeaturesWithin: () => [], getFeatureById: () => undefined, }, importLayer, state, { includeDates: true, // We assume that the non-dated metatags are already set by the cache generator includeNonDates: true, } ) ) const alreadyOpenImportNotes = new FilteringFeatureSource( state, undefined, allNotesWithinBbox ) const map = Minimap.createMiniMap() map.SetClass("w-full").SetStyle("height: 500px") const comparisonMap = Minimap.createMiniMap({ location: map.location, }) comparisonMap.SetClass("w-full").SetStyle("height: 500px") new ShowDataLayer({ layerToShow: importLayer, state, zoomToFeatures: true, leafletMap: map.leafletMap, features: alreadyOpenImportNotes, popup: (tags, layer) => new FeatureInfoBox(tags, layer, state), }) const maxDistance = new UIEventSource(10) const partitionedImportPoints = ImportUtils.partitionFeaturesIfNearby( params, alreadyOpenImportNotes.features.map((ff) => ({ features: ff.map((ff) => ff.feature) })), maxDistance ) new ShowDataLayer({ layerToShow: new LayerConfig(import_candidate), state, zoomToFeatures: true, leafletMap: comparisonMap.leafletMap, features: StaticFeatureSource.fromGeojsonStore( partitionedImportPoints.map((p) => p.hasNearby) ), popup: (tags, layer) => new FeatureInfoBox(tags, layer, state), }) super([ new Title(t.titleLong), new VariableUiElement( alreadyOpenImportNotes.features.map( (notesWithImport) => { if ( allNotesWithinBbox.state.data !== undefined && allNotesWithinBbox.state.data["error"] !== undefined ) { const error = allNotesWithinBbox.state.data["error"] t.loadingFailed.Subs({ error }) } if ( allNotesWithinBbox.features.data === undefined || allNotesWithinBbox.features.data.length === 0 ) { return new Loading(t.loading) } if (notesWithImport.length === 0) { return t.noPreviousNotesFound.SetClass("thanks") } return new Combine([ t.mapExplanation.Subs(params.features), map, new DivContainer("fullscreen"), new VariableUiElement( partitionedImportPoints.map(({ noNearby, hasNearby }) => { if (noNearby.length === 0) { // Nothing can be imported return t.completelyImported .SetClass("alert w-full block") .SetStyle("padding: 0.5rem") } if (hasNearby.length === 0) { // All points can be imported return t.nothingNearby .SetClass("thanks w-full block") .SetStyle("padding: 0.5rem") } return new Combine([ t.someNearby .Subs({ hasNearby: hasNearby.length, distance: maxDistance.data, }) .SetClass("alert"), t.wontBeImported, comparisonMap.SetClass("w-full"), ]).SetClass("w-full") }) ), ]).SetClass("flex flex-col") }, [allNotesWithinBbox.features, allNotesWithinBbox.state] ) ), ]) this.SetClass("flex flex-col") this.Value = partitionedImportPoints.map(({ noNearby }) => ({ features: noNearby, bbox: params.bbox, layer: params.layer, theme: params.theme, })) this.IsValid = alreadyOpenImportNotes.features.map( (ff) => { if (allNotesWithinBbox.features.data.length === 0) { // Not yet loaded return false } if (ff.length == 0) { // No import notes at all return true } return partitionedImportPoints.data.noNearby.length > 0 // at least _something_ can be imported }, [partitionedImportPoints, allNotesWithinBbox.features] ) } }