mapcomplete/UI/ImportFlow/CreateNotes.ts

136 lines
5.1 KiB
TypeScript

import Combine from "../Base/Combine"
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { UIEventSource } from "../../Logic/UIEventSource"
import Title from "../Base/Title"
import Toggle from "../Input/Toggle"
import Loading from "../Base/Loading"
import { VariableUiElement } from "../Base/VariableUIElement"
import { FixedUiElement } from "../Base/FixedUiElement"
import { SubtleButton } from "../Base/SubtleButton"
import Svg from "../../Svg"
import Translations from "../i18n/Translations"
import { Translation } from "../i18n/Translation"
export class CreateNotes extends Combine {
public static createNoteContentsUi(
feature: { properties: any; geometry: { coordinates: [number, number] } },
options: { wikilink: string; intro: string; source: string; theme: string }
): (Translation | string)[] {
const src = feature.properties["source"] ?? feature.properties["src"] ?? options.source
delete feature.properties["source"]
delete feature.properties["src"]
let extraNote = ""
if (feature.properties["note"]) {
extraNote = feature.properties["note"] + "\n"
delete feature.properties["note"]
}
const tags: string[] = []
for (const key in feature.properties) {
if (feature.properties[key] === null || feature.properties[key] === undefined) {
console.warn("Null or undefined key for ", feature.properties)
continue
}
if (feature.properties[key] === "") {
continue
}
tags.push(
key +
"=" +
(feature.properties[key] + "")
.replace(/=/, "\\=")
.replace(/;/g, "\\;")
.replace(/\n/g, "\\n")
)
}
const lat = feature.geometry.coordinates[1]
const lon = feature.geometry.coordinates[0]
const note = Translations.t.importHelper.noteParts
return [
options.intro,
extraNote,
note.datasource.Subs({ source: src }),
note.wikilink.Subs(options),
"",
note.importEasily,
`https://mapcomplete.osm.be/${options.theme}.html?z=18&lat=${lat}&lon=${lon}#import`,
...tags,
]
}
public static createNoteContents(
feature: { properties: any; geometry: { coordinates: [number, number] } },
options: { wikilink: string; intro: string; source: string; theme: string }
): string[] {
return CreateNotes.createNoteContentsUi(feature, options).map((trOrStr) => {
if (typeof trOrStr === "string") {
return trOrStr
}
return trOrStr.txt
})
}
constructor(
state: { osmConnection: OsmConnection },
v: { features: any[]; wikilink: string; intro: string; source: string; theme: string }
) {
const t = Translations.t.importHelper.createNotes
const createdNotes: UIEventSource<number[]> = new UIEventSource<number[]>([])
const failed = new UIEventSource<string[]>([])
const currentNote = createdNotes.map((n) => n.length)
for (const f of v.features) {
const lat = f.geometry.coordinates[1]
const lon = f.geometry.coordinates[0]
const text = CreateNotes.createNoteContents(f, v).join("\n")
state.osmConnection.openNote(lat, lon, text).then(
({ id }) => {
createdNotes.data.push(id)
createdNotes.ping()
},
(err) => {
failed.data.push(err)
failed.ping()
}
)
}
super([
new Title(t.title),
t.loading,
new Toggle(
new Loading(
new VariableUiElement(
currentNote.map((count) =>
t.creating.Subs({
count,
total: v.features.length,
})
)
)
),
new Combine([
Svg.party_svg().SetClass("w-24"),
t.done.Subs({ count: v.features.length }).SetClass("thanks"),
new SubtleButton(Svg.note_svg(), t.openImportViewer, {
url: "import_viewer.html",
}),
]),
currentNote.map((count) => count < v.features.length)
),
new VariableUiElement(
failed.map((failed) => {
if (failed.length === 0) {
return undefined
}
return new Combine([
new FixedUiElement("Some entries failed").SetClass("alert"),
...failed,
]).SetClass("flex flex-col")
})
),
])
this.SetClass("flex flex-col")
}
}