// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck // TODO: refactor this mixin experiment as it no longer plays well with Typescript import { isEmpty } from 'lodash' import { makeObservable, observable } from 'mobx' import { DatabaseFeature } from '../../stores/gisStore' import { Element } from '../element' import { GisElement } from '../gisElement' import { Mixin } from './isLocal' // eslint-disable-next-line @typescript-eslint/no-explicit-any type GConstructor = new (...args: any[]) => T export const hasConnectedFeatures = ( Base: TBase, ) => { return class LocalElement extends Base { relatedGis: Record = {} mapNotes: Element[] = [] // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(...args: any[]) { super(...args) makeObservable(this, { relatedGis: observable, mapNotes: observable, }) } async loadConnectedFeatures(): Promise { if (isEmpty(this.relationElements)) { this.hydrateRelationElements() } // children who also contain geo relations are included const relatedElements = [ ...this.children.filter( (c) => c.constructor.GEO_RELATION_ATTRIBUTES.length > 0, ), ] // also this element is important for related features const geoRelationAttributes = Base.GEO_RELATION_ATTRIBUTES if (geoRelationAttributes.length > 0) { relatedElements.unshift(this) } const features: DatabaseFeature[] = [] const relatedGisElements: Record< string, GisElement[] > = relatedElements.reduce((accEl, element) => { const gisElements = Object.values(getGisForElement(element)) accEl[element.hash] = gisElements return accEl }, {}) // console.tron.log('relatedGisElements', relatedGisElements) this.relatedGis = relatedGisElements // this code just flattens the values into a simple array const relationElementHashes = Object.values(relatedGisElements).reduce( (a: GisElement[], rf) => { a.push(...rf) return a }, [], ) if (relationElementHashes.length > 0) { const relationFeatures = await this.store.gisStore.getFeaturesForElements( relationElementHashes, ) if (relationFeatures) { features.push(...relationFeatures) } } features.forEach((feature) => { const featureElementHash = feature.element?.elementHash if (!featureElementHash) { return } const featureElement = this.store.elementStore.elements.get( featureElementHash, ) if (!featureElement || !(featureElement instanceof GisElement)) { return } const relatedGisElementEntry = Object.entries(relatedGisElements).find( ([, candidateFeatures]) => { const containsFeature = !!candidateFeatures.find( (ge) => ge.GEO_IDENTIFIER === feature.properties.identifierHash, ) return containsFeature }, ) let elementContext: Element = null if (relatedGisElementEntry) { elementContext = relatedElements.find( (re) => re.hash === relatedGisElementEntry[0], ) } featureElement.feature = this.store.gisstore.elementStore.instantiateFeatures( [feature], )[0] featureElement.feature.setElementContext(elementContext) }) return features } async loadMapNotes() { const mapNotesAttr = Base.ATTRIBUTES.MAP_NOTES const hasNotes = this.attributeExists(mapNotesAttr) if (!hasNotes) { return } const mapNotes = this.getAttributeElementValue(mapNotesAttr) const promises = mapNotes.map((mn) => mn.loadRaw()) await Promise.all(promises) this.mapNotes = mapNotes } } } const getGisForElement: (element: Element) => Record = ( element: Element, ) => { const relationAttrs = element.constructor.GEO_RELATION_ATTRIBUTES return relationAttrs.reduce((acc, attribute) => { const relation = element.relationElements[attribute] if (!relation) { return acc } return relation .filter((relationElement) => relationElement instanceof GisElement) .reduce((accR, geoElement: GisElement) => { if (!accR[geoElement.hash]) { accR[geoElement.hash] = geoElement } return accR }, acc) }, {}) } export type ConnectedFeaturesElement = Mixin export const instanceOfConnectedFeatures = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any object: any, ): object is ConnectedFeaturesElement => object && (object as ConnectedFeaturesElement).loadConnectedFeatures !== undefined